zeed 1.3.1 → 1.4.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.
Files changed (54) hide show
  1. package/AGENTS.md +50 -211
  2. package/README.md +16 -0
  3. package/dist/_experiments/bitcask.cjs +2 -2
  4. package/dist/common/exec/index.d.cts +1 -1
  5. package/dist/common/exec/index.d.mts +1 -1
  6. package/dist/common/exec/pool.d.cts +1 -1
  7. package/dist/common/exec/pool.d.mts +1 -1
  8. package/dist/common/exec/progress.d.cts +1 -1
  9. package/dist/common/exec/progress.d.mts +1 -1
  10. package/dist/common/exec/queue.d.cts +1 -1
  11. package/dist/common/exec/queue.d.mts +1 -1
  12. package/dist/common/index.d.cts +1 -1
  13. package/dist/common/index.d.mts +1 -1
  14. package/dist/common/msg/channel-debug.d.cts +1 -1
  15. package/dist/common/msg/channel-debug.d.mts +1 -1
  16. package/dist/common/msg/channel-local.d.cts +1 -1
  17. package/dist/common/msg/channel-local.d.mts +1 -1
  18. package/dist/common/msg/channel-resilient.d.cts +1 -1
  19. package/dist/common/msg/channel-resilient.d.mts +1 -1
  20. package/dist/common/msg/channel-wkwebview.d.cts +2 -1
  21. package/dist/common/msg/channel-wkwebview.d.mts +2 -1
  22. package/dist/common/msg/channel.d.cts +1 -1
  23. package/dist/common/msg/channel.d.mts +1 -1
  24. package/dist/common/msg/emitter.d.cts +1 -1
  25. package/dist/common/msg/emitter.d.mts +1 -1
  26. package/dist/common/msg/index.d.cts +1 -1
  27. package/dist/common/msg/index.d.mts +1 -1
  28. package/dist/common/msg/messages.d.cts +1 -1
  29. package/dist/common/msg/messages.d.mts +1 -1
  30. package/dist/common/msg/pubsub.d.cts +1 -1
  31. package/dist/common/msg/pubsub.d.mts +1 -1
  32. package/dist/{index-DHXVOH8h.d.cts → index-CFkMqHvX.d.cts} +1 -2
  33. package/dist/{index-DMaPyx9O.d.mts → index-C_3Y_s6f.d.mts} +1 -2
  34. package/dist/index.all.d.cts +1 -1
  35. package/dist/index.all.d.mts +1 -1
  36. package/dist/index.browser.d.cts +1 -1
  37. package/dist/index.browser.d.mts +1 -1
  38. package/dist/index.node.d.cts +1 -1
  39. package/dist/index.node.d.mts +1 -1
  40. package/dist/node/args.cjs +1 -1
  41. package/dist/node/crypto.cjs +1 -1
  42. package/dist/node/env.cjs +2 -2
  43. package/dist/node/files-async.cjs +1 -1
  44. package/dist/node/files.cjs +1 -1
  45. package/dist/node/filestorage.cjs +1 -1
  46. package/dist/node/fs.cjs +1 -1
  47. package/dist/node/log/log-context-node.cjs +1 -1
  48. package/dist/node/log/log-file.cjs +1 -1
  49. package/dist/node/log/log-node.cjs +2 -2
  50. package/dist/node/log/log-rotation.cjs +1 -1
  51. package/dist/node/log/log-util.cjs +1 -1
  52. package/package.json +14 -14
  53. package/src/common/schema/README.md +247 -66
  54. package/src/common/schema/README-SCHEMA.md +0 -0
@@ -3,10 +3,14 @@
3
3
  This module provides a flexible, TypeScript-friendly schema/type system for runtime validation, parsing, and type inference. It is inspired by libraries like [valita](https://github.com/badrap/valita) and implements the [Standard Schema](https://github.com/standard-schema/standard-schema) specification.
4
4
 
5
5
  ## Features
6
- - Define schemas for primitives, objects, arrays, tuples, unions, literals, and functions
6
+
7
+ - Define schemas for primitives, objects, arrays, tuples, unions, literals, records, and functions
7
8
  - Parse and validate data at runtime
8
9
  - Type inference for static TypeScript types
9
- - Extensible and composable
10
+ - Schema transformation: `.pick()`, `.omit()`, `.partial()`, `.required()`, `.extend()`
11
+ - Serialize/deserialize schemas to/from JSON
12
+ - Export schemas to TypeScript interfaces, Swift structs, or JSON Schema
13
+ - Parse environment variables and CLI arguments against a schema
10
14
  - **Standard Schema V1 compatible** - works with tRPC, TanStack Form/Router, Hono, and other compatible libraries
11
15
 
12
16
  ## Standard Schema Compatibility
@@ -18,7 +22,7 @@ All zeed schemas implement the [StandardSchemaV1](https://github.com/standard-sc
18
22
  Every schema has a `~standard` property that provides the standard interface:
19
23
 
20
24
  ```ts
21
- import { z } from './schema'
25
+ import { z } from 'zeed'
22
26
 
23
27
  const schema = z.object({
24
28
  name: z.string(),
@@ -29,11 +33,9 @@ const schema = z.object({
29
33
  const result = schema['~standard'].validate({ name: 'Alice', age: 30 })
30
34
 
31
35
  if (result.issues) {
32
- // Validation failed
33
36
  console.error('Validation errors:', result.issues)
34
37
  }
35
38
  else {
36
- // Validation succeeded
37
39
  console.log('Valid data:', result.value)
38
40
  }
39
41
  ```
@@ -49,18 +51,16 @@ The `~standard` property provides:
49
51
 
50
52
  ### Type Inference
51
53
 
52
- Use the standard schema type helpers for cross-library type inference:
53
-
54
54
  ```ts
55
- import type { StandardSchemaV1 } from './schema-standard'
56
- import { z } from './schema'
55
+ import type { StandardSchemaV1 } from 'zeed'
56
+ import { z } from 'zeed'
57
57
 
58
58
  const schema = z.object({
59
59
  email: z.string(),
60
60
  age: z.number().optional(),
61
61
  })
62
62
 
63
- // Extract input/output types using standard schema helpers
63
+ // Extract input/output types via standard schema helpers
64
64
  type Input = StandardSchemaV1.InferInput<typeof schema>
65
65
  type Output = StandardSchemaV1.InferOutput<typeof schema>
66
66
 
@@ -70,61 +70,53 @@ type User = z.infer<typeof schema>
70
70
 
71
71
  ### Compatible Libraries
72
72
 
73
- Zeed schemas work seamlessly with any library that supports Standard Schema, including:
74
-
75
- - **tRPC** - Type-safe APIs
76
- - **TanStack Form** - Form state management
77
- - **TanStack Router** - Type-safe routing
78
- - **Hono** - Fast web framework
79
- - **And many more** - See the [full list](https://github.com/standard-schema/standard-schema#what-tools--frameworks-accept-spec-compliant-schemas)
73
+ Zeed schemas work with any library that supports Standard Schema, including tRPC, TanStack Form, TanStack Router, Hono and more. See the [full list](https://github.com/standard-schema/standard-schema#what-tools--frameworks-accept-spec-compliant-schemas).
80
74
 
81
75
  ### Generic Validation Function Example
82
76
 
83
- Here's how a third-party library might use zeed schemas:
84
-
85
77
  ```ts
86
- import type { StandardSchemaV1 } from './schema-standard'
78
+ import type { StandardSchemaV1 } from 'zeed'
79
+ import { z } from 'zeed'
87
80
 
88
81
  function standardValidate<T extends StandardSchemaV1>(
89
82
  schema: T,
90
- data: unknown
83
+ data: unknown,
91
84
  ): StandardSchemaV1.InferOutput<T> {
92
85
  const result = schema['~standard'].validate(data)
93
-
94
- if (result.issues) {
86
+ if (result.issues)
95
87
  throw new Error(`Validation failed: ${JSON.stringify(result.issues)}`)
96
- }
97
-
98
88
  return result.value
99
89
  }
100
90
 
101
- // Use with zeed schemas
102
91
  const userSchema = z.object({ name: z.string() })
103
92
  const user = standardValidate(userSchema, { name: 'Alice' })
104
93
  ```
105
94
 
106
- ## Installation
107
-
108
- This module is part of the `github-zeed` project. To use it, import from the appropriate path:
109
-
110
- ```ts
111
- import { array, Infer, literal, number, object, string, union, z } from './schema'
112
- // z.string and string are functionally alike, but z.string is preferred for consistency.
113
- ```
114
-
115
95
  ## Basic Usage
116
96
 
117
97
  ### Primitives
118
98
 
119
99
  ```ts
100
+ import { z } from 'zeed'
101
+
120
102
  const name = z.string()
121
103
  const age = z.number()
122
- // Type: string, number
104
+ const count = z.int()
105
+ const flag = z.boolean()
106
+ const nothing = z.none() // undefined | null
107
+ const whatever = z.any()
108
+
109
+ // Numeric aliases for number()
110
+ const x = z.float()
111
+ const y = z.double()
112
+ const r = z.real()
123
113
  ```
124
114
 
125
115
  ### Objects
126
116
 
127
117
  ```ts
118
+ import { z } from 'zeed'
119
+
128
120
  const user = z.object({
129
121
  name: z.string(),
130
122
  age: z.number().optional(),
@@ -132,97 +124,286 @@ const user = z.object({
132
124
  // Type: { name: string; age?: number }
133
125
  ```
134
126
 
135
- ### Arrays
127
+ ### Arrays and Tuples
136
128
 
137
129
  ```ts
130
+ import { z } from 'zeed'
131
+
138
132
  const tags = z.array(z.string())
139
133
  // Type: string[]
134
+
135
+ const pair = z.tuple([z.string(), z.number()])
136
+ // Type: [string, number]
140
137
  ```
141
138
 
142
- ### Unions
139
+ ### Records
143
140
 
144
141
  ```ts
142
+ import { z } from 'zeed'
143
+
144
+ const scores = z.record(z.number())
145
+ // Type: Record<string, number>
146
+ ```
147
+
148
+ ### Unions and Literals
149
+
150
+ ```ts
151
+ import { z } from 'zeed'
152
+
145
153
  const status = z.union([
146
154
  z.literal('active'),
147
155
  z.literal('inactive'),
148
156
  ])
149
157
  // Type: 'active' | 'inactive'
158
+
159
+ const role = z.enum(['admin', 'user', 'guest'])
160
+ // Type: 'admin' | 'user' | 'guest'
161
+ // Note: z.enum is an alias for stringLiterals
150
162
  ```
151
163
 
152
164
  ### Type Inference
153
165
 
154
166
  ```ts
155
- type User = Infer<typeof user>
156
- // Equivalent to: { name: string; age?: number }
167
+ import { z } from 'zeed'
168
+
169
+ const user = z.object({ name: z.string(), age: z.number().optional() })
170
+ type User = z.infer<typeof user>
171
+ // { name: string; age?: number }
157
172
  ```
158
173
 
159
174
  ### Parsing
160
175
 
161
176
  ```ts
177
+ import { z } from 'zeed'
178
+
179
+ const user = z.object({ name: z.string(), age: z.number().optional() })
162
180
  const parsed = user.parse({ name: 'Alice', age: 30 })
163
- // parsed: { name: 'Alice', age: 30 }
164
181
  ```
165
182
 
166
183
  ### Optional and Default Values
167
184
 
168
185
  ```ts
186
+ import { z } from 'zeed'
187
+
169
188
  const score = z.number().optional().default(0)
170
189
  // Type: number | undefined (default: 0)
190
+
191
+ // Default can also be a function
192
+ const id = z.string().default(() => crypto.randomUUID())
193
+ ```
194
+
195
+ ### Metadata and Descriptions
196
+
197
+ ```ts
198
+ import { z } from 'zeed'
199
+
200
+ const name = z.string().meta({ desc: 'The user name' })
201
+ const age = z.number().describe('Age in years')
171
202
  ```
172
203
 
173
204
  ### Function and RPC Types
174
205
 
175
206
  ```ts
207
+ import { z } from 'zeed'
208
+
176
209
  const add = z.func([z.number(), z.number()], z.number())
177
210
  // Type: (a: number, b: number) => number
211
+
178
212
  const rpcCall = z.rpc(z.object({ id: z.string() }), z.number())
179
213
  // Type: (info: { id: string }) => number | Promise<number>
180
214
  ```
181
215
 
182
- ### Serialization and Deserialization
216
+ ## Object Schema Transformations
183
217
 
184
- You can serialize schema definitions to plain JSON objects and deserialize them back. This is useful for sending schema definitions over the network or storing them in databases.
218
+ Object schemas support composition methods similar to Zod:
185
219
 
186
220
  ```ts
187
- import { deserializeSchema, serializeSchema } from './schema'
221
+ import { z } from 'zeed'
222
+
223
+ const user = z.object({
224
+ id: z.string(),
225
+ name: z.string(),
226
+ email: z.string(),
227
+ age: z.number(),
228
+ })
229
+
230
+ // Extend with additional fields
231
+ const userWithRole = user.extend({ role: z.string() })
232
+
233
+ // Pick a subset of fields
234
+ const userName = user.pick({ id: true, name: true })
235
+
236
+ // Omit fields
237
+ const userWithoutEmail = user.omit({ email: true })
238
+
239
+ // Make all (or selected) fields optional
240
+ const partialUser = user.partial()
241
+ const partialByKey = user.partial({ age: true })
242
+
243
+ // Make all (or selected) fields required
244
+ const requiredUser = partialUser.required()
245
+ ```
246
+
247
+ ## Serialization and Deserialization
248
+
249
+ Serialize schemas to plain JSON and reconstruct them later. Useful for sending schemas over the network or persisting them.
250
+
251
+ ```ts
252
+ import { deserializeSchema, serializeSchema, z } from 'zeed'
188
253
 
189
- // Define a schema
190
254
  const userSchema = z.object({
191
255
  name: z.string(),
192
256
  age: z.number().optional(),
193
- role: z.stringLiterals(['admin', 'user']).default('user'),
257
+ role: z.enum(['admin', 'user']).default('user'),
194
258
  })
195
259
 
196
- // Serialize to plain JSON
197
260
  const serialized = serializeSchema(userSchema)
198
- // Result: { type: 'object', object: { name: { type: 'string' }, ... } }
199
-
200
- // Send over network, store in DB, etc.
201
261
  const jsonString = JSON.stringify(serialized)
202
262
 
203
- // Deserialize back to a schema
204
263
  const deserialized = deserializeSchema(JSON.parse(jsonString))
205
- // deserialized is now a Type instance identical to userSchema
206
-
207
- // Use the deserialized schema for validation
208
264
  const user = deserialized.parse({ name: 'Alice', role: 'admin' })
209
265
  ```
210
266
 
211
- **Note**: Function defaults (e.g., `.default(() => 'value')`) cannot be serialized and will be omitted. Only static default values are preserved during serialization.
267
+ **Note**: Function defaults (e.g., `.default(() => 'value')`) cannot be serialized and are omitted. Only static default values are preserved.
268
+
269
+ ## Parsing Environment Variables
270
+
271
+ Map a flat object schema onto `process.env`. Field names are converted from camelCase to `UPPER_SNAKE_CASE`.
272
+
273
+ ```ts
274
+ import { parseSchemaEnv, stringFromSchemaEnv, z } from 'zeed'
275
+
276
+ const envSchema = z.object({
277
+ port: z.int().default(3000).meta({ envDesc: 'Server port' }),
278
+ dbUrl: z.string().meta({ envDesc: 'Database connection URL' }),
279
+ debug: z.boolean().default(false),
280
+ secret: z.string().meta({ envPrivate: true }),
281
+ })
282
+
283
+ const env = parseSchemaEnv(envSchema)
284
+ // Reads PORT, DB_URL, DEBUG, SECRET from process.env
285
+
286
+ // Generate a .env template (private fields are hidden unless showPrivate=true)
287
+ const template = stringFromSchemaEnv(envSchema)
288
+ ```
289
+
290
+ Supported `meta` fields: `envDesc`, `envPrivate`, `envSkip`.
291
+
292
+ ## Parsing CLI Arguments
293
+
294
+ ```ts
295
+ import { helpSchemaArgs, parseSchemaArgs, z } from 'zeed'
296
+
297
+ const argsSchema = z.object({
298
+ input: z.string().meta({ argShort: 'i', argDesc: 'Input file' }),
299
+ verbose: z.boolean().default(false).meta({ argShort: 'v' }),
300
+ count: z.int().default(1),
301
+ })
302
+
303
+ const [args, rest] = parseSchemaArgs(argsSchema) // reads process.argv
304
+ const help = helpSchemaArgs(argsSchema)
305
+ ```
306
+
307
+ Supported `meta` fields: `argShort`, `argDesc`.
308
+
309
+ ## Exporting Schemas
310
+
311
+ ### TypeScript Interface
312
+
313
+ ```ts
314
+ import { schemaExportTypescriptInterface, z } from 'zeed'
315
+
316
+ const user = z.object({
317
+ name: z.string(),
318
+ age: z.int().optional(),
319
+ })
320
+
321
+ const ts = schemaExportTypescriptInterface(user, 'User')
322
+ // export interface User { name: string; age?: number }
323
+ ```
324
+
325
+ ### Swift Struct
326
+
327
+ ```ts
328
+ import { schemaExportSwiftStruct, z } from 'zeed'
329
+
330
+ const user = z.object({
331
+ name: z.string(),
332
+ age: z.int().optional(),
333
+ })
334
+
335
+ const swift = schemaExportSwiftStruct(user, 'User')
336
+ ```
337
+
338
+ Supported `meta` fields: `swiftName`, `swiftProtocol`, `swiftDesc`, `swiftDefault`.
339
+
340
+ ### JSON Schema
341
+
342
+ ```ts
343
+ import { schemaExportJsonSchema, schemaExportJsonSchemaString, z } from 'zeed'
344
+
345
+ const user = z.object({
346
+ name: z.string(),
347
+ age: z.number().optional(),
348
+ })
349
+
350
+ const jsonSchema = schemaExportJsonSchema(user)
351
+ const jsonSchemaStr = schemaExportJsonSchemaString(user)
352
+ ```
212
353
 
213
354
  ## API Reference
214
355
 
215
- - `string()`, `number()`, `int()`, `boolean()`, `none()`, `any()`
216
- - `object({...})`, `array(type)`, `tuple([type1, type2, ...])`, `record(type)`
217
- - `union([type1, type2, ...])`
218
- - `literal(value)`, `stringLiterals(['a', 'b', ...])`
219
- - `func(args, ret)`, `rpc(info, ret)`
220
- - `.optional()`, `.default(value)`, `.meta({ desc })`, `.extend({...})`
221
- - `parse(obj)`, `map(obj, fn)`
222
- - `serializeSchema(schema)` - Converts a schema to a plain JSON object
223
- - `deserializeSchema(json)` - Reconstructs a schema from a JSON object
356
+ ### Primitives
357
+
358
+ - `z.string()`, `z.number()`, `z.int()`, `z.boolean()`, `z.none()`, `z.any()`
359
+ - `z.float()`, `z.double()`, `z.real()` - aliases for `z.number()`
360
+
361
+ ### Composites
362
+
363
+ - `z.object({...})`, `z.array(type)`, `z.tuple([...])`, `z.record(type)`
364
+ - `z.union([...])`
365
+ - `z.literal(value)`, `z.stringLiterals([...])`, `z.enum([...])`
366
+ - `z.func(args, ret)`, `z.rpc(info, ret)`
367
+
368
+ ### Type methods
369
+
370
+ - `.optional()`, `.default(value | fn)`
371
+ - `.meta({ desc, ... })`, `.describe(msg)`
372
+ - `.parse(obj)`
373
+ - Object only: `.extend({...})`, `.pick({...})`, `.omit({...})`, `.partial()`, `.partial({...})`, `.required()`, `.required({...})`
374
+
375
+ ### Type inference helpers
376
+
377
+ - `z.infer<typeof schema>`
378
+
379
+ ### Serialization
380
+
381
+ - `serializeSchema(schema)` - Convert a schema to a plain JSON object
382
+ - `deserializeSchema(json)` - Reconstruct a schema from a JSON object
383
+
384
+ ### Parsing helpers
385
+
386
+ - `schemaCreateObject(schema)` - Build an object from defaults
387
+ - `schemaParseObject(schema, obj, opt?)` - Parse and coerce an object against a schema
388
+ - `schemaValidateObject(schema, obj, opt?)` - Validate without coercion, returns issues
389
+
390
+ ### Environment and CLI
391
+
392
+ - `parseSchemaEnv(schema, opt?)`, `stringFromSchemaEnv(schema, prefix?, commentOut?, showPrivate?)`
393
+ - `parseSchemaArgs(schema, argv?)`, `helpSchemaArgs(schema)`
394
+
395
+ ### Exporters
396
+
397
+ - `schemaExportTypescriptInterface(schema, name?)`
398
+ - `schemaExportSwiftStruct(schema, name?)`
399
+ - `schemaExportJsonSchema(schema)`, `schemaExportJsonSchemaString(schema)`
400
+
401
+ ### Utilities
402
+
403
+ - `isSchemaObject(schema)`, `isSchemaObjectFlat(schema)`
404
+ - `isSchemaOptional(schema)`, `isSchemaDefault(schema)`, `isSchemaPrimitive(schema)`
224
405
 
225
406
  ## Notes
226
407
 
227
- - `z.string` and `string` are functionally equivalent, but `z.string` is preferred for consistency and clarity.
228
- - Each schema definition results in a corresponding TypeScript type, which can be extracted using `Infer<typeof schema>`.
408
+ - `z.string()` and the bare `string()` export are functionally equivalent, but `z.string()` is preferred for consistency and clarity.
409
+ - Each schema definition results in a corresponding TypeScript type, extractable via `z.infer<typeof schema>`.
File without changes