hanzio 1.2.0 → 2.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 +786 -239
- package/dist/api-wrapper/builders.d.ts +4 -3
- package/dist/api-wrapper/create-client.d.ts +1 -1
- package/dist/api-wrapper/describe.d.ts +16 -0
- package/dist/api-wrapper/endpoint.d.ts +18 -0
- package/dist/api-wrapper/errors.d.ts +39 -2
- package/dist/api-wrapper/index.d.ts +5 -0
- package/dist/api-wrapper/otel.d.ts +44 -0
- package/dist/api-wrapper/paginate.d.ts +12 -0
- package/dist/api-wrapper/redaction.d.ts +2 -0
- package/dist/api-wrapper/shared.d.ts +16 -2
- package/dist/api-wrapper/testing.d.ts +23 -0
- package/dist/api-wrapper/transport.d.ts +4 -5
- package/dist/api-wrapper/types.d.ts +103 -18
- package/dist/array/index.d.ts +50 -4
- package/dist/cache/createCache.d.ts +31 -0
- package/dist/cache/index.d.ts +19 -2
- package/dist/color/contrast.d.ts +40 -0
- package/dist/color/index.d.ts +2 -0
- package/dist/{math → color}/metricsSeriesColors.d.ts +14 -7
- package/dist/cool-console-log/index.d.ts +34 -5
- package/dist/crypto/encoding.d.ts +18 -0
- package/dist/crypto/hash.d.ts +33 -0
- package/dist/crypto/index.d.ts +4 -0
- package/dist/crypto/sealer.d.ts +25 -0
- package/dist/crypto/webhook.d.ts +20 -0
- package/dist/date/index.d.ts +46 -2
- package/dist/emitter/index.d.ts +21 -0
- package/dist/error/index.d.ts +12 -0
- package/dist/format/index.d.ts +102 -0
- package/dist/function/index.d.ts +60 -0
- package/dist/guard/index.d.ts +20 -0
- package/dist/i18n/index.d.ts +37 -0
- package/dist/index-0zvtcbzy.js +224 -0
- package/dist/index-181e6vfw.js +29 -0
- package/dist/index-8r2vdzjg.js +87 -0
- package/dist/index-hy7kbb99.js +157 -0
- package/dist/{src/secrets/infisical.js → index-j1ybktbr.js} +500 -538
- package/dist/index-k9yx6bne.js +89 -0
- package/dist/index-kj1phgrx.js +169 -0
- package/dist/index-mnkcfyx8.js +78 -0
- package/dist/{p-queue/index.js → index-pwt0dz63.js} +7 -11
- package/dist/index-rp5pqghz.js +157 -0
- package/dist/index-srt06xd2.js +15 -0
- package/dist/index-wjyb9bsd.js +263 -0
- package/dist/index.d.ts +7 -7
- package/dist/jwt/index.d.ts +50 -2
- package/dist/math/index.d.ts +2 -2
- package/dist/math/linearRegressionTrend.d.ts +14 -1
- package/dist/math/scale.d.ts +8 -0
- package/dist/object/index.d.ts +19 -0
- package/dist/p-queue/index.d.ts +1 -1
- package/dist/promise/index.d.ts +97 -2
- package/dist/sitemap/index.d.ts +48 -6
- package/dist/src/api-wrapper/index.js +60 -1130
- package/dist/src/api-wrapper/testing.js +20 -0
- package/dist/{cool-console-log → src/cool-console-log}/index.js +80 -33
- package/dist/src/crypto/index.js +195 -0
- package/dist/src/format/index.js +211 -0
- package/dist/src/i18n/index.js +36 -0
- package/dist/src/index.js +739 -3145
- package/dist/src/jwt/index.js +138 -92
- package/dist/src/p-queue/index.js +9 -437
- package/dist/src/secrets/index.js +44 -1428
- package/dist/src/secrets/vite.js +6 -39
- package/dist/src/secrets/worker.js +10 -273
- package/dist/src/sitemap/index.js +183 -511
- package/dist/src/storage/index.js +119 -0
- package/dist/src/zod/index.js +340 -167
- package/dist/state/index.d.ts +21 -0
- package/dist/storage/index.d.ts +58 -0
- package/dist/string/index.d.ts +75 -2
- package/dist/typedswitch/index.d.ts +31 -24
- package/dist/types/index.d.ts +11 -0
- package/dist/url/index.d.ts +50 -1
- package/dist/zod/index.d.ts +32 -3
- package/dist/zod/introspect.d.ts +19 -0
- package/dist/zod/jsonToZodSchemaMapper.d.ts +3 -1
- package/dist/zod/zodMinMaxFilter.d.ts +22 -3
- package/dist/zod/zodToTypeString.d.ts +8 -3
- package/package.json +78 -7
- package/src/api-wrapper/actions-impl.ts +11 -72
- package/src/api-wrapper/builders.ts +32 -25
- package/src/api-wrapper/create-client.ts +171 -41
- package/src/api-wrapper/describe.ts +157 -0
- package/src/api-wrapper/endpoint.ts +26 -0
- package/src/api-wrapper/error-reporting.ts +7 -1
- package/src/api-wrapper/errors.ts +107 -2
- package/src/api-wrapper/headers.ts +11 -6
- package/src/api-wrapper/index.ts +5 -0
- package/src/api-wrapper/otel.ts +139 -0
- package/src/api-wrapper/paginate.ts +28 -0
- package/src/api-wrapper/redaction.ts +42 -0
- package/src/api-wrapper/shared.ts +21 -2
- package/src/api-wrapper/testing.ts +48 -0
- package/src/api-wrapper/transport.ts +41 -43
- package/src/api-wrapper/types.ts +185 -18
- package/src/array/index.ts +195 -42
- package/src/cache/createCache.ts +157 -0
- package/src/cache/index.ts +132 -147
- package/src/color/contrast.ts +163 -0
- package/src/color/index.ts +22 -0
- package/src/{math → color}/metricsSeriesColors.ts +47 -49
- package/src/cool-console-log/index.ts +128 -41
- package/src/crypto/encoding.ts +83 -0
- package/src/crypto/hash.ts +170 -0
- package/src/crypto/index.ts +26 -0
- package/src/crypto/sealer.ts +168 -0
- package/src/crypto/webhook.ts +86 -0
- package/src/date/index.ts +109 -34
- package/src/emitter/index.ts +82 -0
- package/src/error/index.ts +63 -0
- package/src/format/index.ts +389 -0
- package/src/function/index.ts +201 -0
- package/src/guard/index.ts +80 -0
- package/src/i18n/index.ts +125 -0
- package/src/index.ts +11 -7
- package/src/jwt/index.ts +199 -125
- package/src/math/index.ts +5 -10
- package/src/math/linearRegressionTrend.ts +33 -8
- package/src/math/scale.ts +17 -0
- package/src/object/index.ts +99 -0
- package/src/p-queue/index.ts +2 -0
- package/src/promise/index.ts +304 -9
- package/src/sitemap/index.ts +293 -130
- package/src/state/index.ts +133 -81
- package/src/storage/index.ts +187 -0
- package/src/string/index.ts +261 -23
- package/src/typedswitch/index.ts +58 -38
- package/src/types/index.ts +14 -0
- package/src/url/index.ts +146 -1
- package/src/zod/index.ts +105 -9
- package/src/zod/introspect.ts +103 -0
- package/src/zod/jsonToZodSchemaMapper.ts +44 -21
- package/src/zod/zodMinMaxFilter.ts +37 -13
- package/src/zod/zodToTypeString.ts +184 -181
- package/dist/api-wrapper/index.js +0 -250
- package/dist/gzip/index.d.ts +0 -2
- package/dist/gzip/index.js +0 -16
- package/dist/index.js +0 -1823
- package/dist/jwt/index.js +0 -19
- package/dist/sitemap/index.js +0 -552
- package/dist/src/gzip/index.js +0 -16
- package/dist/src/secrets/loaders.js +0 -1529
- package/dist/zod/index.js +0 -210
|
@@ -1,222 +1,225 @@
|
|
|
1
1
|
import type { z } from 'zod'
|
|
2
|
+
import { isRecord } from '../guard'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
export type Schema = z.core.$ZodType
|
|
5
|
+
export type Def = z.core.$ZodTypes['_zod']['def']
|
|
6
|
+
|
|
7
|
+
// Schemas on the current render path, so recursive (lazy/getter) schemas terminate
|
|
8
|
+
const visiting = new Set<Schema>()
|
|
9
|
+
|
|
10
|
+
export function walk<T>(schema: Schema, onCycle: T, fn: (def: Def) => T): T {
|
|
11
|
+
if (visiting.has(schema)) return onCycle
|
|
12
|
+
visiting.add(schema)
|
|
13
|
+
try {
|
|
14
|
+
return fn(defOf(schema))
|
|
15
|
+
} finally {
|
|
16
|
+
visiting.delete(schema)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function defOf(schema: Schema): Def {
|
|
21
|
+
return (schema as z.core.$ZodTypes)._zod.def
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Pipes are described by their output, except transforms, whose output can't be inspected
|
|
25
|
+
function pipeTarget(def: z.core.$ZodPipeDef): Schema {
|
|
26
|
+
return defOf(def.out).type === 'transform' ? def.in : def.out
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function literal(value: unknown): string {
|
|
30
|
+
if (typeof value === 'string') return JSON.stringify(value)
|
|
31
|
+
return typeof value === 'bigint' ? `${value}n` : String(value)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Parenthesize unions/intersections where they'd otherwise bind wrongly (e.g. `(a | b)[]`)
|
|
35
|
+
function wrap(type: string): string {
|
|
36
|
+
return /[|&]/.test(type) ? `(${type})` : type
|
|
6
37
|
}
|
|
7
38
|
|
|
8
39
|
/**
|
|
9
40
|
* Convert a Zod schema to a human-readable TypeScript-like interface string
|
|
10
41
|
*/
|
|
11
|
-
export function zodToTypeString(schema:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// Zod 4: check value.type === 'optional', Zod 3: check _def.typeName
|
|
35
|
-
const valueType = getDefProp<string>(
|
|
36
|
-
(value as unknown as { _zod?: { def: unknown } })._zod?.def ??
|
|
37
|
-
(value as unknown as { _def?: unknown })._def,
|
|
38
|
-
'type'
|
|
39
|
-
)
|
|
40
|
-
const isOptional = valueType === 'optional'
|
|
41
|
-
const innerSchema = isOptional
|
|
42
|
-
? (getDefProp<z.ZodType>(
|
|
43
|
-
(value as unknown as { _zod?: { def: unknown } })._zod?.def ??
|
|
44
|
-
(value as unknown as { _def?: unknown })._def,
|
|
45
|
-
'innerType'
|
|
46
|
-
) ?? value)
|
|
47
|
-
: value
|
|
48
|
-
const typeStr = zodToTypeString(innerSchema, indent + 1)
|
|
49
|
-
return `${innerPad}${key}${isOptional ? '?' : ''}: ${typeStr}`
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
return `{\n${fields.join('\n')}\n${pad}}`
|
|
53
|
-
}
|
|
42
|
+
export function zodToTypeString(schema: Schema, indent = 0): string {
|
|
43
|
+
return walk(schema, 'unknown', (def) => {
|
|
44
|
+
const pad = ' '.repeat(indent)
|
|
45
|
+
const innerPad = ' '.repeat(indent + 1)
|
|
46
|
+
const render = (inner: Schema) => zodToTypeString(inner, indent)
|
|
47
|
+
|
|
48
|
+
switch (def.type) {
|
|
49
|
+
case 'object': {
|
|
50
|
+
const entries = Object.entries(def.shape)
|
|
51
|
+
if (entries.length === 0) return '{}'
|
|
52
|
+
|
|
53
|
+
const fields = entries.map(([key, value]) => {
|
|
54
|
+
const valueDef = defOf(value)
|
|
55
|
+
const isOptional = valueDef.type === 'optional'
|
|
56
|
+
const typeStr = zodToTypeString(
|
|
57
|
+
isOptional ? valueDef.innerType : value,
|
|
58
|
+
indent + 1
|
|
59
|
+
)
|
|
60
|
+
return `${innerPad}${key}${isOptional ? '?' : ''}: ${typeStr}`
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return `{\n${fields.join('\n')}\n${pad}}`
|
|
64
|
+
}
|
|
54
65
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const itemType =
|
|
58
|
-
getDefProp<z.ZodType>(def, 'element') ??
|
|
59
|
-
getDefProp<z.ZodType>(def, 'type')
|
|
60
|
-
return itemType ? `${zodToTypeString(itemType, indent)}[]` : 'unknown[]'
|
|
61
|
-
}
|
|
66
|
+
case 'array':
|
|
67
|
+
return `${wrap(render(def.element))}[]`
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
case 'tuple': {
|
|
70
|
+
const items = def.items.map(render)
|
|
71
|
+
if (def.rest) items.push(`...${wrap(render(def.rest))}[]`)
|
|
72
|
+
return `[${items.join(', ')}]`
|
|
73
|
+
}
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
|
|
75
|
+
case 'string':
|
|
76
|
+
case 'number':
|
|
77
|
+
case 'bigint':
|
|
78
|
+
case 'boolean':
|
|
79
|
+
case 'symbol':
|
|
80
|
+
case 'null':
|
|
81
|
+
case 'undefined':
|
|
82
|
+
case 'void':
|
|
83
|
+
case 'never':
|
|
84
|
+
case 'any':
|
|
85
|
+
case 'unknown':
|
|
86
|
+
return def.type
|
|
68
87
|
|
|
69
|
-
|
|
70
|
-
|
|
88
|
+
case 'date':
|
|
89
|
+
return 'Date'
|
|
71
90
|
|
|
72
|
-
|
|
73
|
-
|
|
91
|
+
case 'record':
|
|
92
|
+
return `Record<${render(def.keyType)}, ${render(def.valueType)}>`
|
|
74
93
|
|
|
75
|
-
|
|
76
|
-
|
|
94
|
+
case 'map':
|
|
95
|
+
return `Map<${render(def.keyType)}, ${render(def.valueType)}>`
|
|
77
96
|
|
|
78
|
-
|
|
79
|
-
|
|
97
|
+
case 'set':
|
|
98
|
+
return `Set<${render(def.valueType)}>`
|
|
80
99
|
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
case 'promise':
|
|
101
|
+
return `Promise<${render(def.innerType)}>`
|
|
83
102
|
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
case 'enum':
|
|
104
|
+
return Object.values(def.entries).map(literal).join(' | ')
|
|
86
105
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return valueType
|
|
90
|
-
? `Record<string, ${zodToTypeString(valueType, indent)}>`
|
|
91
|
-
: 'Record<string, unknown>'
|
|
92
|
-
}
|
|
106
|
+
case 'literal':
|
|
107
|
+
return def.values.map(literal).join(' | ')
|
|
93
108
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return values ? values.map((v) => `"${v}"`).join(' | ') : 'string'
|
|
97
|
-
}
|
|
109
|
+
case 'union':
|
|
110
|
+
return def.options.map(render).join(' | ')
|
|
98
111
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return typeof value === 'string' ? `"${value}"` : String(value)
|
|
102
|
-
}
|
|
112
|
+
case 'intersection':
|
|
113
|
+
return `${wrap(render(def.left))} & ${wrap(render(def.right))}`
|
|
103
114
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return options
|
|
107
|
-
? options.map((o) => zodToTypeString(o, indent)).join(' | ')
|
|
108
|
-
: 'unknown'
|
|
109
|
-
}
|
|
115
|
+
case 'optional':
|
|
116
|
+
return `${render(def.innerType)} | undefined`
|
|
110
117
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return inner ? `${zodToTypeString(inner, indent)} | undefined` : 'unknown'
|
|
114
|
-
}
|
|
118
|
+
case 'nullable':
|
|
119
|
+
return `${render(def.innerType)} | null`
|
|
115
120
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
case 'nonoptional': {
|
|
122
|
+
const innerDef = defOf(def.innerType)
|
|
123
|
+
return render(
|
|
124
|
+
innerDef.type === 'optional' ? innerDef.innerType : def.innerType
|
|
125
|
+
)
|
|
126
|
+
}
|
|
120
127
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
128
|
+
case 'default':
|
|
129
|
+
case 'prefault':
|
|
130
|
+
case 'catch':
|
|
131
|
+
case 'readonly':
|
|
132
|
+
return render(def.innerType)
|
|
125
133
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
case 'ZodUnknown':
|
|
137
|
-
case 'ZodRecord':
|
|
138
|
-
case 'ZodEnum':
|
|
139
|
-
case 'ZodLiteral':
|
|
140
|
-
case 'ZodUnion':
|
|
141
|
-
case 'ZodOptional':
|
|
142
|
-
case 'ZodNullable':
|
|
143
|
-
case 'ZodDefault':
|
|
144
|
-
// For Zod 3, recurse with the lowercase version
|
|
145
|
-
return zodToTypeString(schema, indent)
|
|
146
|
-
|
|
147
|
-
default:
|
|
148
|
-
return 'unknown'
|
|
149
|
-
}
|
|
134
|
+
case 'lazy':
|
|
135
|
+
return render(def.getter())
|
|
136
|
+
|
|
137
|
+
case 'pipe':
|
|
138
|
+
return render(pipeTarget(def))
|
|
139
|
+
|
|
140
|
+
default:
|
|
141
|
+
return 'unknown'
|
|
142
|
+
}
|
|
143
|
+
})
|
|
150
144
|
}
|
|
151
145
|
|
|
152
146
|
/**
|
|
153
|
-
* Generate example JSON from a Zod schema
|
|
147
|
+
* Generate example JSON from a Zod schema. Values are JSON-safe: dates become ISO
|
|
148
|
+
* strings, bigints numbers, sets arrays and maps/records empty objects.
|
|
154
149
|
*/
|
|
155
|
-
export function zodToExample(schema:
|
|
156
|
-
|
|
157
|
-
(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
switch (schemaType) {
|
|
166
|
-
case 'object': {
|
|
167
|
-
const shape = getDefProp<Record<string, z.ZodType>>(def, 'shape')
|
|
168
|
-
if (!shape) return {}
|
|
169
|
-
const result: Record<string, unknown> = {}
|
|
170
|
-
for (const [key, value] of Object.entries(shape)) {
|
|
171
|
-
const valueType = getDefProp<string>(
|
|
172
|
-
(value as unknown as { _zod?: { def: unknown } })._zod?.def ??
|
|
173
|
-
(value as unknown as { _def?: unknown })._def,
|
|
174
|
-
'type'
|
|
175
|
-
)
|
|
176
|
-
const isOptional = valueType === 'optional'
|
|
177
|
-
if (!isOptional) {
|
|
178
|
-
result[key] = zodToExample(value)
|
|
150
|
+
export function zodToExample(schema: Schema): unknown {
|
|
151
|
+
return walk(schema, null, (def): unknown => {
|
|
152
|
+
switch (def.type) {
|
|
153
|
+
case 'object': {
|
|
154
|
+
const result: Record<string, unknown> = {}
|
|
155
|
+
for (const [key, value] of Object.entries(def.shape)) {
|
|
156
|
+
if (defOf(value).type !== 'optional') {
|
|
157
|
+
result[key] = zodToExample(value)
|
|
158
|
+
}
|
|
179
159
|
}
|
|
160
|
+
return result
|
|
180
161
|
}
|
|
181
|
-
return result
|
|
182
|
-
}
|
|
183
162
|
|
|
184
|
-
case 'array': {
|
|
185
|
-
// Zod 4 uses 'element', Zod 3 uses 'type'
|
|
186
|
-
const itemType =
|
|
187
|
-
getDefProp<z.ZodType>(def, 'element') ??
|
|
188
|
-
getDefProp<z.ZodType>(def, 'type')
|
|
189
163
|
// Always return array with one item for better example
|
|
190
|
-
|
|
191
|
-
|
|
164
|
+
case 'array':
|
|
165
|
+
return [zodToExample(def.element)]
|
|
192
166
|
|
|
193
|
-
|
|
194
|
-
|
|
167
|
+
case 'set':
|
|
168
|
+
return [zodToExample(def.valueType)]
|
|
195
169
|
|
|
196
|
-
|
|
197
|
-
|
|
170
|
+
case 'tuple':
|
|
171
|
+
return def.items.map(zodToExample)
|
|
198
172
|
|
|
199
|
-
|
|
200
|
-
|
|
173
|
+
case 'string':
|
|
174
|
+
return ''
|
|
201
175
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
176
|
+
case 'number':
|
|
177
|
+
case 'bigint':
|
|
178
|
+
return 0
|
|
206
179
|
|
|
207
|
-
|
|
208
|
-
|
|
180
|
+
case 'boolean':
|
|
181
|
+
return false
|
|
209
182
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const inner = getDefProp<z.ZodType>(def, 'innerType')
|
|
213
|
-
return inner ? zodToExample(inner) : null
|
|
214
|
-
}
|
|
183
|
+
case 'date':
|
|
184
|
+
return new Date(0).toISOString()
|
|
215
185
|
|
|
216
|
-
|
|
217
|
-
|
|
186
|
+
case 'enum':
|
|
187
|
+
return Object.values(def.entries)[0]
|
|
218
188
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
189
|
+
case 'literal':
|
|
190
|
+
return def.values[0]
|
|
191
|
+
|
|
192
|
+
case 'union':
|
|
193
|
+
return zodToExample(def.options[0] as Schema)
|
|
194
|
+
|
|
195
|
+
case 'intersection': {
|
|
196
|
+
const left = zodToExample(def.left)
|
|
197
|
+
const right = zodToExample(def.right)
|
|
198
|
+
return isRecord(left) && isRecord(right) ? { ...left, ...right } : left
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
case 'optional':
|
|
202
|
+
case 'nullable':
|
|
203
|
+
case 'nonoptional':
|
|
204
|
+
case 'default':
|
|
205
|
+
case 'prefault':
|
|
206
|
+
case 'catch':
|
|
207
|
+
case 'readonly':
|
|
208
|
+
case 'promise':
|
|
209
|
+
return zodToExample(def.innerType)
|
|
210
|
+
|
|
211
|
+
case 'lazy':
|
|
212
|
+
return zodToExample(def.getter())
|
|
213
|
+
|
|
214
|
+
case 'pipe':
|
|
215
|
+
return zodToExample(pipeTarget(def))
|
|
216
|
+
|
|
217
|
+
case 'record':
|
|
218
|
+
case 'map':
|
|
219
|
+
return {}
|
|
220
|
+
|
|
221
|
+
default:
|
|
222
|
+
return null
|
|
223
|
+
}
|
|
224
|
+
})
|
|
222
225
|
}
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
// src/api-wrapper/index.ts
|
|
2
|
-
import { ZodError } from "zod";
|
|
3
|
-
|
|
4
|
-
class ResponseValidationError extends Error {
|
|
5
|
-
zodError;
|
|
6
|
-
rawResponse;
|
|
7
|
-
validationIssues;
|
|
8
|
-
constructor(zodError, rawResponse) {
|
|
9
|
-
const issues = zodError.issues.map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`).join("; ");
|
|
10
|
-
super(`Response validation failed: ${issues}`);
|
|
11
|
-
this.name = "ResponseValidationError";
|
|
12
|
-
this.zodError = zodError;
|
|
13
|
-
this.rawResponse = rawResponse;
|
|
14
|
-
this.validationIssues = issues;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
class HttpResponseError extends Error {
|
|
19
|
-
status;
|
|
20
|
-
body;
|
|
21
|
-
constructor(status, body) {
|
|
22
|
-
super(`HTTP error: ${status} - ${body}`);
|
|
23
|
-
this.name = "HttpResponseError";
|
|
24
|
-
this.status = status;
|
|
25
|
-
this.body = body;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function createApiClient(apiConfig) {
|
|
29
|
-
const request = async (endpointKey, input = {}) => {
|
|
30
|
-
const endpoint = apiConfig.endpoints[endpointKey];
|
|
31
|
-
if (!endpoint) {
|
|
32
|
-
throw new Error(`Unknown API endpoint: ${String(endpointKey)}`);
|
|
33
|
-
}
|
|
34
|
-
const { finalUrl, fullUrl } = buildUrl(endpoint, input.reqParams, input.reqQuery, apiConfig.baseApiUrls, apiConfig.defaultBaseApiUrl, input.url);
|
|
35
|
-
const endpointName = apiConfig.name ? `${apiConfig.name}.${String(endpointKey)}` : String(endpointKey);
|
|
36
|
-
const startedAt = Date.now();
|
|
37
|
-
let retryCount = 0;
|
|
38
|
-
let httpStatus = 0;
|
|
39
|
-
apiConfig.onRequestStart?.({ endpoint: endpointName, url: fullUrl });
|
|
40
|
-
try {
|
|
41
|
-
const config = {
|
|
42
|
-
method: endpoint.method,
|
|
43
|
-
url: finalUrl,
|
|
44
|
-
queryParams: buildQueryParams(endpoint, input.reqQuery),
|
|
45
|
-
body: buildRequestBody(endpoint, input.reqBody),
|
|
46
|
-
headers: buildHeaders(endpoint, input.reqHeaders, apiConfig.defaultHeaders ?? {}),
|
|
47
|
-
doNotEncodeQueryParams: endpoint.doNotEncodeQueryParams,
|
|
48
|
-
timeoutMs: apiConfig.timeoutMs,
|
|
49
|
-
fetchFn: apiConfig.fetch ?? fetch
|
|
50
|
-
};
|
|
51
|
-
const result = await makeRequestWithRetry(config, apiConfig.retries ?? 3, apiConfig.retryDelayMs ?? 300, (response) => validateAndTransformResponse(endpoint, response), apiConfig.shouldRetry ?? defaultShouldRetry, apiConfig.logger);
|
|
52
|
-
retryCount = result.retryCount;
|
|
53
|
-
httpStatus = result.httpStatus;
|
|
54
|
-
const responseTimeMs = Date.now() - startedAt;
|
|
55
|
-
const responseSizeMb = calculateSizeInMb(result.validatedData);
|
|
56
|
-
const requestSizeMb = calculateSizeInMb({
|
|
57
|
-
method: config.method,
|
|
58
|
-
url: fullUrl,
|
|
59
|
-
body: config.body,
|
|
60
|
-
headers: config.headers
|
|
61
|
-
});
|
|
62
|
-
apiConfig.onRequestEnd?.({
|
|
63
|
-
endpoint: endpointName,
|
|
64
|
-
url: fullUrl,
|
|
65
|
-
status: httpStatus,
|
|
66
|
-
retryCount,
|
|
67
|
-
responseTimeMs
|
|
68
|
-
});
|
|
69
|
-
return {
|
|
70
|
-
data: result.validatedData,
|
|
71
|
-
requestSizeMb,
|
|
72
|
-
responseSizeMb,
|
|
73
|
-
requestSizeTotalMb: requestSizeMb + responseSizeMb,
|
|
74
|
-
responseTimeMs,
|
|
75
|
-
httpStatus,
|
|
76
|
-
retryCount
|
|
77
|
-
};
|
|
78
|
-
} catch (error) {
|
|
79
|
-
apiConfig.logger?.error?.(error);
|
|
80
|
-
throw error;
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
return { request };
|
|
84
|
-
}
|
|
85
|
-
var createApiWrapper = createApiClient;
|
|
86
|
-
async function validateResponse(schema, data) {
|
|
87
|
-
try {
|
|
88
|
-
return await schema.parseAsync(data);
|
|
89
|
-
} catch (error) {
|
|
90
|
-
if (error instanceof ZodError) {
|
|
91
|
-
throw new ResponseValidationError(error, data);
|
|
92
|
-
}
|
|
93
|
-
throw error;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
async function httpRequest(config) {
|
|
97
|
-
const queryString = config.doNotEncodeQueryParams ? Object.entries(config.queryParams).map(([key, value]) => `${key}=${value}`).join("&") : new URLSearchParams(config.queryParams).toString();
|
|
98
|
-
const fullUrl = queryString ? `${config.url}?${queryString}` : config.url;
|
|
99
|
-
const abortController = new AbortController;
|
|
100
|
-
const timeout = config.timeoutMs === undefined ? undefined : setTimeout(() => abortController.abort(), config.timeoutMs);
|
|
101
|
-
try {
|
|
102
|
-
return await config.fetchFn(fullUrl, {
|
|
103
|
-
method: config.method,
|
|
104
|
-
headers: config.headers,
|
|
105
|
-
body: buildFetchBody(config.body, config.headers),
|
|
106
|
-
signal: abortController.signal
|
|
107
|
-
});
|
|
108
|
-
} finally {
|
|
109
|
-
if (timeout)
|
|
110
|
-
clearTimeout(timeout);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
async function makeRequestWithRetry(config, maxRetries, retryDelayMs, validateFn, shouldRetry, logger) {
|
|
114
|
-
let retryCount = 0;
|
|
115
|
-
while (true) {
|
|
116
|
-
try {
|
|
117
|
-
logger?.debug?.("API request", config);
|
|
118
|
-
const response = await httpRequest(config);
|
|
119
|
-
if (response.status >= 400) {
|
|
120
|
-
if (retryCount < maxRetries && shouldRetry({ response, retryCount, maxRetries })) {
|
|
121
|
-
retryCount++;
|
|
122
|
-
await delay(retryDelayMs);
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
throw new HttpResponseError(response.status, await response.text());
|
|
126
|
-
}
|
|
127
|
-
return {
|
|
128
|
-
validatedData: await validateFn(response),
|
|
129
|
-
retryCount,
|
|
130
|
-
httpStatus: response.status
|
|
131
|
-
};
|
|
132
|
-
} catch (error) {
|
|
133
|
-
if (error instanceof HttpResponseError)
|
|
134
|
-
throw error;
|
|
135
|
-
if (retryCount >= maxRetries || !shouldRetry({ error, retryCount, maxRetries })) {
|
|
136
|
-
throw error;
|
|
137
|
-
}
|
|
138
|
-
retryCount++;
|
|
139
|
-
await delay(retryDelayMs);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
async function validateAndTransformResponse(endpoint, response) {
|
|
144
|
-
const responseHeaders = getHeadersAsObject(response.headers);
|
|
145
|
-
const contentType = responseHeaders["content-type"] ?? "";
|
|
146
|
-
const responseData = contentType.includes("application/json") ? await response.json() : await response.text();
|
|
147
|
-
const transformedData = endpoint.resFormatter ? endpoint.resFormatter(responseData, responseHeaders) : responseData;
|
|
148
|
-
return validateResponse(endpoint.resSchema, transformedData);
|
|
149
|
-
}
|
|
150
|
-
function buildUrl(endpoint, params, reqQuery, baseApiUrls, defaultBaseApiUrl, url) {
|
|
151
|
-
if (url) {
|
|
152
|
-
const finalUrl2 = replacePathParams(url, params);
|
|
153
|
-
const queryString2 = new URLSearchParams(buildQueryParams(endpoint, reqQuery)).toString();
|
|
154
|
-
return {
|
|
155
|
-
finalUrl: finalUrl2,
|
|
156
|
-
fullUrl: queryString2 ? `${finalUrl2}?${queryString2}` : finalUrl2
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
const defaultBaseUrl = defaultBaseApiUrl ?? Object.keys(baseApiUrls)[0];
|
|
160
|
-
if (!defaultBaseUrl) {
|
|
161
|
-
throw new Error("At least one base API URL is required");
|
|
162
|
-
}
|
|
163
|
-
const baseUrlKey = endpoint.baseApiUrl ?? defaultBaseUrl;
|
|
164
|
-
const configBaseUrl = baseApiUrls[baseUrlKey];
|
|
165
|
-
if (!configBaseUrl) {
|
|
166
|
-
throw new Error(`Unknown base API URL: ${baseUrlKey}`);
|
|
167
|
-
}
|
|
168
|
-
const baseUrl = typeof configBaseUrl === "function" ? configBaseUrl() : configBaseUrl;
|
|
169
|
-
const path = typeof endpoint.path === "function" ? endpoint.path(baseUrl) : endpoint.path;
|
|
170
|
-
const finalUrl = replacePathParams(`${baseUrl}${path}`, params);
|
|
171
|
-
const queryString = new URLSearchParams(buildQueryParams(endpoint, reqQuery)).toString();
|
|
172
|
-
return {
|
|
173
|
-
finalUrl,
|
|
174
|
-
fullUrl: queryString ? `${finalUrl}?${queryString}` : finalUrl
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
function buildQueryParams(endpoint, query) {
|
|
178
|
-
const defaultParams = endpoint.reqDefaultQueryParams ?? {};
|
|
179
|
-
const parsedQuery = endpoint.reqQuerySchema ? endpoint.reqQuerySchema.parse(query) : query ?? {};
|
|
180
|
-
const merged = { ...defaultParams, ...parsedQuery };
|
|
181
|
-
return Object.fromEntries(Object.entries(merged).filter(([, value]) => value !== undefined).map(([key, value]) => [key, String(value)]));
|
|
182
|
-
}
|
|
183
|
-
function buildRequestBody(endpoint, body) {
|
|
184
|
-
if (!endpoint.reqBodySchema)
|
|
185
|
-
return body;
|
|
186
|
-
const parsedBody = endpoint.reqBodySchema.parse(body);
|
|
187
|
-
if (endpoint.reqBodyFormat !== "form-data") {
|
|
188
|
-
return parsedBody;
|
|
189
|
-
}
|
|
190
|
-
const formData = new FormData;
|
|
191
|
-
for (const [key, value] of Object.entries(parsedBody)) {
|
|
192
|
-
if (value == null)
|
|
193
|
-
continue;
|
|
194
|
-
formData.set(key, value instanceof Blob ? value : String(value));
|
|
195
|
-
}
|
|
196
|
-
return formData;
|
|
197
|
-
}
|
|
198
|
-
function buildHeaders(endpoint, headers, defaultHeaders) {
|
|
199
|
-
const contentType = endpoint.reqBodyFormat === "json" ? "application/json" : undefined;
|
|
200
|
-
const parsedHeaders = endpoint.reqHeadersSchema ? endpoint.reqHeadersSchema.parse(headers) : headers ?? {};
|
|
201
|
-
return {
|
|
202
|
-
...defaultHeaders,
|
|
203
|
-
...contentType && { "Content-Type": contentType },
|
|
204
|
-
...endpoint.defaultHeaders,
|
|
205
|
-
...parsedHeaders
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
function buildFetchBody(body, headers) {
|
|
209
|
-
if (body === undefined || body === null)
|
|
210
|
-
return;
|
|
211
|
-
if (body instanceof FormData || body instanceof Blob)
|
|
212
|
-
return body;
|
|
213
|
-
if (headers["Content-Type"] === "application/json")
|
|
214
|
-
return JSON.stringify(body);
|
|
215
|
-
return body;
|
|
216
|
-
}
|
|
217
|
-
function replacePathParams(path, params) {
|
|
218
|
-
return path.replace(/:(\w+)/g, (_, key) => {
|
|
219
|
-
const value = params?.[key];
|
|
220
|
-
if (value === undefined) {
|
|
221
|
-
throw new Error(`Missing required path parameter: ${key}`);
|
|
222
|
-
}
|
|
223
|
-
return encodeURIComponent(String(value));
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
function getHeadersAsObject(headers) {
|
|
227
|
-
const result = {};
|
|
228
|
-
headers.forEach((value, key) => {
|
|
229
|
-
result[key] = value;
|
|
230
|
-
});
|
|
231
|
-
return result;
|
|
232
|
-
}
|
|
233
|
-
function calculateSizeInMb(data) {
|
|
234
|
-
const sizeInBytes = new TextEncoder().encode(JSON.stringify(data)).length;
|
|
235
|
-
return sizeInBytes / (1024 * 1024);
|
|
236
|
-
}
|
|
237
|
-
function defaultShouldRetry({ error, response }) {
|
|
238
|
-
if (error)
|
|
239
|
-
return true;
|
|
240
|
-
return response ? response.status >= 500 : false;
|
|
241
|
-
}
|
|
242
|
-
function delay(ms) {
|
|
243
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
244
|
-
}
|
|
245
|
-
export {
|
|
246
|
-
createApiWrapper,
|
|
247
|
-
createApiClient,
|
|
248
|
-
ResponseValidationError,
|
|
249
|
-
HttpResponseError
|
|
250
|
-
};
|
package/dist/gzip/index.d.ts
DELETED
package/dist/gzip/index.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// src/gzip/index.ts
|
|
2
|
-
import pako from "pako";
|
|
3
|
-
function compressString(input) {
|
|
4
|
-
const uint8Array = new TextEncoder().encode(input);
|
|
5
|
-
const compressed = pako.deflate(uint8Array);
|
|
6
|
-
return btoa(String.fromCharCode.apply(null, compressed));
|
|
7
|
-
}
|
|
8
|
-
function decompressString(compressedString) {
|
|
9
|
-
const compressedData = new Uint8Array(atob(compressedString).split("").map((char) => char.charCodeAt(0)));
|
|
10
|
-
const decompressed = pako.inflate(compressedData);
|
|
11
|
-
return new TextDecoder().decode(decompressed);
|
|
12
|
-
}
|
|
13
|
-
export {
|
|
14
|
-
decompressString,
|
|
15
|
-
compressString
|
|
16
|
-
};
|