@wishknish/knishio-client-ts 0.9.4 → 0.9.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wishknish/knishio-client-ts",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
4
4
  "productName": "Knish.IO TypeScript SDK Client",
5
5
  "description": "TypeScript implementation of the Knish.IO SDK to consume Knish.IO GraphQL APIs with enhanced type safety.",
6
6
  "license": "GPL-3.0-or-later",
@@ -67,7 +67,7 @@
67
67
  "jssha": "^3.3.1",
68
68
  "tslib": "^2.8.1",
69
69
  "wonka": "^6.3.5",
70
- "zod": "^3.23.8"
70
+ "zod": "^4.5.4"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@types/isomorphic-fetch": "^0.0.39",
@@ -113,7 +113,7 @@
113
113
  "README.md",
114
114
  "LICENSE"
115
115
  ],
116
- "packageManager": "yarn@4.6.0",
116
+ "packageManager": "yarn@4.15.0",
117
117
  "engines": {
118
118
  "node": ">=18.0.0"
119
119
  }
package/src/index.ts CHANGED
@@ -359,7 +359,10 @@ export {
359
359
  // VERSION AND SDK INFORMATION
360
360
  // =============================================================================
361
361
 
362
- export const SDK_VERSION = '1.0.0'
362
+ // MUST equal package.json's "version". The CI `version consistency` job enforces this via
363
+ // .github/scripts/check-version.sh, which parses this exact line — keep the literal form
364
+ // `export const SDK_VERSION = '<semver>'` intact so the gate can read it.
365
+ export const SDK_VERSION = '0.9.5'
363
366
  export const SDK_NAME = 'KnishIO-Client-TS'
364
367
  export const COMPATIBLE_SERVER_VERSIONS = [4, 5]
365
368
 
@@ -69,7 +69,7 @@ const CallbackParamsSchema = z.object({
69
69
  action: z.string().min(1, 'Action cannot be empty'),
70
70
  metaType: z.union([z.string(), z.null()]).optional(),
71
71
  metaId: z.union([z.string(), z.null()]).optional(),
72
- meta: z.union([z.instanceof(Meta), z.record(z.unknown()), z.null()]).optional(),
72
+ meta: z.union([z.instanceof(Meta), z.record(z.string(), z.unknown()), z.null()]).optional(),
73
73
  address: z.union([z.string(), z.null()]).optional(),
74
74
  token: z.union([z.string(), z.null()]).optional(),
75
75
  amount: z.union([z.string(), z.null()]).optional(),
@@ -62,6 +62,21 @@ import { z } from 'zod'
62
62
  const hexStringRegex = /^[0-9a-fA-F]+$/
63
63
  const base17HashRegex = /^[0-9a-g]+$/
64
64
 
65
+ // Zod 3's `.url()` was `try { new URL(v) } catch` and returned the input UNCHANGED.
66
+ // Zod 4's `z.url()` returns the normalized `URL.href` instead — it strips default ports and
67
+ // lowercases the host — and there is no opt-out. The parsed `uri` is the endpoint the client
68
+ // actually talks to (KnishIOClient destructures it out of the validated config), so a
69
+ // refinement is used here: it validates exactly as v3 did without rewriting the value.
70
+ const urlString = (message = 'Invalid URL') =>
71
+ z.string().refine((value) => {
72
+ try {
73
+ new URL(value)
74
+ return true
75
+ } catch {
76
+ return false
77
+ }
78
+ }, message)
79
+
65
80
  export const HexStringSchema = z.string()
66
81
  .regex(hexStringRegex, 'Must be a valid hexadecimal string')
67
82
  .brand<'HexString'>()
@@ -115,7 +130,7 @@ export const CellSlugSchema = z.string()
115
130
  // =============================================================================
116
131
 
117
132
  export const AtomIsotopeSchema = z.enum(['C', 'V', 'U', 'T', 'M', 'I', 'R', 'B', 'F'], {
118
- errorMap: () => ({ message: 'Invalid atom isotope. Must be one of: C, V, U, T, M, I, R, B, F' })
133
+ error: 'Invalid atom isotope. Must be one of: C, V, U, T, M, I, R, B, F'
119
134
  })
120
135
 
121
136
  // =============================================================================
@@ -135,7 +150,7 @@ export const AtomMetaDataSchema = z.object({
135
150
  }).strict()
136
151
 
137
152
  export const MetaDataSchema: z.ZodType<Record<string, any>> = z.lazy(() =>
138
- z.record(z.union([
153
+ z.record(z.string(), z.union([
139
154
  MetaDataValueSchema,
140
155
  MetaDataSchema,
141
156
  z.array(MetaDataSchema)
@@ -186,7 +201,7 @@ export const MoleculeParamsSchema = z.object({
186
201
  // =============================================================================
187
202
 
188
203
  export const KnishIOClientConfigSchema = z.object({
189
- uri: z.union([z.string().url(), z.array(z.string().url())]).optional(),
204
+ uri: z.union([urlString(), z.array(urlString())]).optional(),
190
205
  cellSlug: z.union([CellSlugSchema, z.string(), z.null()]).optional(),
191
206
  client: z.unknown().optional(),
192
207
  socket: z.unknown().optional(),
@@ -209,7 +224,7 @@ export const AuthTokenParamsSchema = z.object({
209
224
  export const AuthParamsSchema = z.object({
210
225
  cellSlug: z.union([CellSlugSchema, z.string(), z.null()]).optional(),
211
226
  encrypt: z.boolean().optional(),
212
- callback: z.function().args(z.unknown()).returns(z.void()).optional()
227
+ callback: z.custom<(arg: unknown) => void>((value) => typeof value === 'function').optional()
213
228
  }).strict()
214
229
 
215
230
  export const GuestAuthParamsSchema = z.object({
@@ -224,7 +239,7 @@ export const TransferParamsSchema = z.object({
224
239
  recipient: z.union([WalletAddressSchema, z.string()]),
225
240
  amount: z.union([z.number().positive(), z.string().min(1)]),
226
241
  token: z.union([TokenSlugSchema, z.string()]).optional(),
227
- callbackUrl: z.union([z.string().url(), z.null()]).optional(),
242
+ callbackUrl: z.union([urlString(), z.null()]).optional(),
228
243
  metaType: z.union([MetaTypeSchema, z.string(), z.null()]).optional(),
229
244
  metaId: z.union([MetaIdSchema, z.string(), z.null()]).optional(),
230
245
  meta: z.union([MetaDataSchema, z.null()]).optional()
@@ -278,7 +293,7 @@ export const MetaQueryParamsSchema = z.object({
278
293
  value: z.union([z.string(), z.null()]).optional(),
279
294
  latest: z.union([z.boolean(), z.null()]).optional(),
280
295
  filter: z.union([z.array(MetaFilterSchema), z.null()]).optional(),
281
- queryArgs: z.union([z.record(z.unknown()), z.null()]).optional(),
296
+ queryArgs: z.union([z.record(z.string(), z.unknown()), z.null()]).optional(),
282
297
  count: z.union([z.number().int().min(1), z.null()]).optional(),
283
298
  countBy: z.union([z.string(), z.null()]).optional(),
284
299
  cellSlug: z.union([CellSlugSchema, z.string(), z.null()]).optional()
@@ -316,7 +331,7 @@ export const SignatureResultSchema = z.object({
316
331
 
317
332
  export const GraphQLRequestSchema = z.object({
318
333
  query: z.string().min(1, 'GraphQL query cannot be empty'),
319
- variables: z.record(z.unknown()).optional(),
334
+ variables: z.record(z.string(), z.unknown()).optional(),
320
335
  operationName: z.union([z.string(), z.null()]).optional()
321
336
  }).strict()
322
337
 
@@ -327,13 +342,13 @@ export const GraphQLErrorSchema = z.object({
327
342
  column: z.number().int().min(1)
328
343
  })).optional(),
329
344
  path: z.array(z.union([z.string(), z.number()])).optional(),
330
- extensions: z.record(z.unknown()).optional()
345
+ extensions: z.record(z.string(), z.unknown()).optional()
331
346
  }).strict()
332
347
 
333
348
  export const GraphQLResponseSchema = z.object({
334
349
  data: z.unknown().optional(),
335
350
  errors: z.array(GraphQLErrorSchema).nullable().optional(),
336
- extensions: z.record(z.unknown()).optional()
351
+ extensions: z.record(z.string(), z.unknown()).optional()
337
352
  }).strict()
338
353
 
339
354
  // =============================================================================
@@ -343,8 +358,8 @@ export const GraphQLResponseSchema = z.object({
343
358
  export const SubscriptionOptionsSchema = z.object({
344
359
  operationName: z.string().optional(),
345
360
  query: z.string().optional(),
346
- variables: z.record(z.unknown()).optional(),
347
- callback: z.function().args(z.unknown()).returns(z.void()).optional()
361
+ variables: z.record(z.string(), z.unknown()).optional(),
362
+ callback: z.custom<(arg: unknown) => void>((value) => typeof value === 'function').optional()
348
363
  }).strict()
349
364
 
350
365
  // =============================================================================
@@ -364,7 +379,7 @@ export const ValidationResultSchema = z.object({
364
379
 
365
380
  export const ErrorContextSchema = z.object({
366
381
  operation: z.string().optional(),
367
- parameters: z.record(z.unknown()).optional(),
382
+ parameters: z.record(z.string(), z.unknown()).optional(),
368
383
  timestamp: z.number().int().min(0).optional(),
369
384
  stack: z.string().optional()
370
385
  }).strict()
@@ -407,7 +422,7 @@ export const KnishIOErrorTypeSchema = z.enum([
407
422
  * Validates and parses data using a Zod schema with enhanced error messages
408
423
  */
409
424
  export function parseWithSchema<T>(
410
- schema: z.ZodSchema<T>,
425
+ schema: z.ZodType<T>,
411
426
  data: unknown,
412
427
  context?: string
413
428
  ): T {
@@ -428,7 +443,7 @@ export function parseWithSchema<T>(
428
443
  * Type-safe validation that returns a result object instead of throwing
429
444
  */
430
445
  export function validateWithSchema<T>(
431
- schema: z.ZodSchema<T>,
446
+ schema: z.ZodType<T>,
432
447
  data: unknown
433
448
  ): { success: true; data: T } | { success: false; error: string } {
434
449
  const result = schema.safeParse(data)
@@ -444,7 +459,7 @@ export function validateWithSchema<T>(
444
459
  * Validates multiple values with their respective schemas
445
460
  */
446
461
  export function validateMultiple<T extends Record<string, any>>(
447
- validations: { [K in keyof T]: { schema: z.ZodSchema<T[K]>; data: unknown } }
462
+ validations: { [K in keyof T]: { schema: z.ZodType<T[K]>; data: unknown } }
448
463
  ): T {
449
464
  const result = {} as T
450
465
 
@@ -182,9 +182,7 @@ export class ValidationService {
182
182
  KNISHIO_SERVER_SDK_VERSION: process.env.KNISHIO_SERVER_SDK_VERSION
183
183
  }
184
184
 
185
- // cast: EnvironmentConfig uses .default()/.optional() so its inferred input≠output type and
186
- // doesn't structurally match safeParse's ZodType<T> param; ZodTypeAny sidesteps the mismatch.
187
- const parseResult = safeParse(Schemas.EnvironmentConfig as z.ZodTypeAny, env)
185
+ const parseResult = safeParse(Schemas.EnvironmentConfig, env)
188
186
 
189
187
  if (!parseResult.success) {
190
188
  return {
@@ -55,6 +55,20 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
55
55
 
56
56
  import { z } from 'zod'
57
57
 
58
+ // Zod 3's `.url()` returned the input UNCHANGED; Zod 4's `z.url()` returns the normalized
59
+ // `URL.href` (strips default ports, lowercases the host) with no opt-out. `KnishIOClientConfig
60
+ // .uri` and `KNISHIO_NODE_URI` both flow into the endpoint the client actually calls, so a
61
+ // refinement is used: it validates exactly as v3 did without rewriting the value.
62
+ const urlString = (message = 'Invalid URL') =>
63
+ z.string().refine((value) => {
64
+ try {
65
+ new URL(value)
66
+ return true
67
+ } catch {
68
+ return false
69
+ }
70
+ }, message)
71
+
58
72
  // =============================================================================
59
73
  // CORE TYPE SCHEMAS (2025 TYPESCRIPT PATTERN)
60
74
  // =============================================================================
@@ -92,7 +106,12 @@ export const TokenSlugSchema = createBrandedSchema('TokenSlug',
92
106
  )
93
107
 
94
108
  export const BatchIdSchema = createBrandedSchema('BatchId',
95
- z.string().uuid('Invalid batch ID format')
109
+ // v3's `.uuid()` regex, inlined verbatim. Zod 4's `z.uuid()` additionally enforces the
110
+ // RFC 9562 version/variant nibbles and would reject batch IDs v3 accepted.
111
+ z.string().regex(
112
+ /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/,
113
+ 'Invalid batch ID format'
114
+ )
96
115
  )
97
116
 
98
117
  export const CellSlugSchema = createBrandedSchema('CellSlug',
@@ -152,7 +171,7 @@ export const AtomMetaDataSchema = z.object({
152
171
  export const NormalizedMetaSchema = z.object({
153
172
  key: z.string(),
154
173
  value: z.union([z.string(), z.number(), z.boolean(), z.null()])
155
- }).passthrough() // Allow additional properties
174
+ }).loose() // Allow additional properties
156
175
 
157
176
  // =============================================================================
158
177
  // CORE ENTITY SCHEMAS
@@ -199,8 +218,8 @@ export const MoleculeParamsSchema = z.object({
199
218
 
200
219
  export const KnishIOClientConfigSchema = z.object({
201
220
  uri: z.union([
202
- z.string().url('Invalid URI format'),
203
- z.array(z.string().url('Invalid URI format')).min(1)
221
+ urlString('Invalid URI format'),
222
+ z.array(urlString('Invalid URI format')).min(1)
204
223
  ]).optional(),
205
224
  cellSlug: z.union([CellSlugSchema, z.string()]).optional(),
206
225
  client: z.unknown().optional(),
@@ -213,13 +232,18 @@ export const KnishIOClientConfigSchema = z.object({
213
232
  defaultRequestPolicy: z.enum(['cache-first', 'cache-only', 'network-only', 'cache-and-network']).nullable().optional()
214
233
  }).strict()
215
234
 
216
- // Environment configuration with validation
235
+ // Environment configuration with validation.
236
+ // NOTE: no `.default()` here. The outer `.partial()` wraps every field in `optional()`, so
237
+ // under Zod 3 these defaults never fired (an all-unset env parsed to `{}`). Under Zod 4 they
238
+ // DO fire, and because v4's `.default()` no longer parses the default value they would emit
239
+ // the raw strings 'false' and '4' where the consumer (ValidationService -> KnishIOClientConfig)
240
+ // requires a boolean and a number. Dropping them keeps v3's exact observable output.
217
241
  export const EnvironmentConfigSchema = z.object({
218
- NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
219
- KNISHIO_NODE_URI: z.string().url().optional(),
242
+ NODE_ENV: z.enum(['development', 'production', 'test']).optional(),
243
+ KNISHIO_NODE_URI: urlString().optional(),
220
244
  KNISHIO_CELL_SLUG: z.string().optional(),
221
- KNISHIO_LOGGING: z.string().transform(val => val === 'true').default('false'),
222
- KNISHIO_SERVER_SDK_VERSION: z.string().transform(val => parseInt(val, 10)).default('4')
245
+ KNISHIO_LOGGING: z.string().transform(val => val === 'true').optional(),
246
+ KNISHIO_SERVER_SDK_VERSION: z.string().transform(val => parseInt(val, 10)).optional()
223
247
  }).partial()
224
248
 
225
249
  // =============================================================================
@@ -233,7 +257,7 @@ export const TransferParamsSchema = z.object({
233
257
  'Amount must be positive'
234
258
  ),
235
259
  token: z.union([TokenSlugSchema, z.string()]).optional(),
236
- callbackUrl: z.string().url().optional(),
260
+ callbackUrl: urlString().optional(),
237
261
  metaType: z.string().optional(),
238
262
  metaId: z.string().optional(),
239
263
  meta: MetaDataSchema.optional()
@@ -282,7 +306,7 @@ export const MetaQueryParamsSchema = z.object({
282
306
  value: z.string().optional(),
283
307
  latest: z.boolean().optional(),
284
308
  filter: z.string().optional(),
285
- queryArgs: z.record(z.unknown()).optional(),
309
+ queryArgs: z.record(z.string(), z.unknown()).optional(),
286
310
  count: z.number().int().min(0).optional(),
287
311
  countBy: z.string().optional(),
288
312
  cellSlug: z.union([CellSlugSchema, z.string()]).optional()
@@ -308,7 +332,7 @@ export const AuthTokenParamsSchema = z.object({
308
332
  export const AuthParamsSchema = z.object({
309
333
  cellSlug: z.union([CellSlugSchema, z.string()]).optional(),
310
334
  encrypt: z.boolean().optional(),
311
- callback: z.function().optional()
335
+ callback: z.custom<(...args: unknown[]) => unknown>((value) => typeof value === 'function').optional()
312
336
  }).strict()
313
337
 
314
338
  export const GuestAuthParamsSchema = z.object({
@@ -321,7 +345,7 @@ export const GuestAuthParamsSchema = z.object({
321
345
 
322
346
  export const GraphQLRequestSchema = z.object({
323
347
  query: z.string().min(1),
324
- variables: z.record(z.unknown()).optional(),
348
+ variables: z.record(z.string(), z.unknown()).optional(),
325
349
  operationName: z.string().optional()
326
350
  }).strict()
327
351
 
@@ -332,13 +356,13 @@ export const GraphQLErrorSchema = z.object({
332
356
  column: z.number().int()
333
357
  })).optional(),
334
358
  path: z.array(z.union([z.string(), z.number()])).optional(),
335
- extensions: z.record(z.unknown()).optional()
359
+ extensions: z.record(z.string(), z.unknown()).optional()
336
360
  }).strict()
337
361
 
338
362
  export const GraphQLResponseSchema = z.object({
339
363
  data: z.unknown().optional(),
340
364
  errors: z.array(GraphQLErrorSchema).optional(),
341
- extensions: z.record(z.unknown()).optional()
365
+ extensions: z.record(z.string(), z.unknown()).optional()
342
366
  }).strict()
343
367
 
344
368
  // =============================================================================
@@ -357,7 +381,7 @@ export function safeParse<T>(schema: z.ZodType<T>, data: unknown) {
357
381
  error: {
358
382
  issues: result.error.issues,
359
383
  message: result.error.message,
360
- formatted: result.error.format()
384
+ formatted: z.treeifyError(result.error)
361
385
  }
362
386
  }
363
387
  }