hanzio 2.0.0 → 2.2.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/LICENSE +21 -0
- package/README.md +5 -6
- package/dist/api-wrapper/endpoint.d.ts +8 -5
- package/dist/api-wrapper/transport.d.ts +1 -0
- package/dist/api-wrapper/types.d.ts +7 -0
- package/dist/{index-wjyb9bsd.js → index-hyt6c56h.js} +39 -12
- package/dist/index-ktynw3vs.js +37 -0
- package/dist/{index-181e6vfw.js → index-w882zry3.js} +1 -1
- package/dist/{index-j1ybktbr.js → index-zbj9s3s3.js} +6 -4
- package/dist/secrets/core.d.ts +7 -0
- package/dist/secrets/index.d.ts +3 -1
- package/dist/secrets/public-config.d.ts +7 -0
- package/dist/secrets/vite.d.ts +1 -0
- package/dist/secrets/worker.d.ts +1 -0
- package/dist/src/api-wrapper/index.js +1 -1
- package/dist/src/secrets/index.js +14 -8
- package/dist/src/secrets/vite.js +5 -1
- package/dist/src/secrets/worker.js +8 -4
- package/package.json +10 -3
- package/src/api-wrapper/README.md +738 -0
- package/src/api-wrapper/create-client.ts +9 -3
- package/src/api-wrapper/endpoint.ts +19 -5
- package/src/api-wrapper/transport.ts +6 -2
- package/src/api-wrapper/types.ts +13 -0
- package/src/crypto/README.md +144 -0
- package/src/format/README.md +120 -0
- package/src/i18n/README.md +65 -0
- package/src/jwt/README.md +70 -0
- package/src/p-queue/README.md +237 -0
- package/src/secrets/README.md +413 -0
- package/src/secrets/core.ts +72 -16
- package/src/secrets/index.ts +16 -4
- package/src/secrets/public-config.ts +47 -0
- package/src/secrets/vite.ts +2 -0
- package/src/secrets/worker.ts +2 -0
- package/src/sitemap/README.md +61 -0
- package/src/storage/README.md +71 -0
- package/src/typedswitch/README.md +319 -0
- package/dist/index-srt06xd2.js +0 -15
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# typedswitch
|
|
2
|
+
|
|
3
|
+
A type-safe, exhaustive switch expression for TypeScript. Handle discriminated unions and string literals with full type inference, compile-time exhaustiveness checking, and async support.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install typedswitch
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add typedswitch
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun add typedswitch
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **Full type inference** — Return types are automatically inferred from your handlers
|
|
22
|
+
- **Exhaustiveness checking** — TypeScript ensures all cases are handled at compile time
|
|
23
|
+
- **Discriminated union support** — Works with any discriminant key, not just `type`
|
|
24
|
+
- **Async-aware** — Async handlers preserve their `Promise` return type
|
|
25
|
+
- **Default handlers** — Handle remaining cases with a fallback
|
|
26
|
+
- **Return type constraints** — Enforce that all handlers return a specific type
|
|
27
|
+
- **`assertNever`** — Exhaustiveness checking for regular `switch` statements
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### String/Enum Input
|
|
32
|
+
|
|
33
|
+
Switch on a string literal or enum value directly:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { typedSwitch } from 'typedswitch'
|
|
37
|
+
|
|
38
|
+
type Status = 'success' | 'error' | 'pending'
|
|
39
|
+
|
|
40
|
+
const status: Status = 'success'
|
|
41
|
+
|
|
42
|
+
// All cases required — TypeScript enforces exhaustiveness
|
|
43
|
+
const message = typedSwitch(status, {
|
|
44
|
+
success: () => 'Operation completed!',
|
|
45
|
+
error: () => 'Something went wrong',
|
|
46
|
+
pending: () => 'Please wait...',
|
|
47
|
+
})
|
|
48
|
+
// message: string
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Each handler receives the narrowed value:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
const result = typedSwitch(status, {
|
|
55
|
+
success: (val) => val.toUpperCase(), // val: 'success'
|
|
56
|
+
error: (val) => val.toUpperCase(), // val: 'error'
|
|
57
|
+
pending: (val) => val.toUpperCase(), // val: 'pending'
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Discriminated Union Input
|
|
62
|
+
|
|
63
|
+
Switch on objects with a string, number, or boolean discriminant property (like `type`, `kind`, `status`, etc.):
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
type Event =
|
|
67
|
+
| { type: 'click'; x: number; y: number }
|
|
68
|
+
| { type: 'scroll'; offset: number }
|
|
69
|
+
| { type: 'keypress'; key: string }
|
|
70
|
+
|
|
71
|
+
const event: Event = { type: 'click', x: 100, y: 200 }
|
|
72
|
+
|
|
73
|
+
// Specify the discriminant key as the second argument
|
|
74
|
+
const description = typedSwitch(event, 'type', {
|
|
75
|
+
click: (e) => `Clicked at (${e.x}, ${e.y})`, // e: { type: 'click'; x: number; y: number }
|
|
76
|
+
scroll: (e) => `Scrolled ${e.offset}px`, // e: { type: 'scroll'; offset: number }
|
|
77
|
+
keypress: (e) => `Pressed ${e.key}`, // e: { type: 'keypress'; key: string }
|
|
78
|
+
})
|
|
79
|
+
// description: string
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Works with any discriminant key:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
type Order =
|
|
86
|
+
| { status: 'pending'; createdAt: Date }
|
|
87
|
+
| { status: 'completed'; completedAt: Date }
|
|
88
|
+
| { status: 'cancelled'; reason: string }
|
|
89
|
+
|
|
90
|
+
const order: Order = { status: 'completed', completedAt: new Date() }
|
|
91
|
+
|
|
92
|
+
const info = typedSwitch(order, 'status', {
|
|
93
|
+
pending: (o) => `Created: ${o.createdAt}`,
|
|
94
|
+
completed: (o) => `Done: ${o.completedAt}`,
|
|
95
|
+
cancelled: (o) => `Cancelled: ${o.reason}`,
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Number and boolean discriminants work too. Cases are keyed by `String(value)`:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
type Response =
|
|
103
|
+
| { code: 200; body: string }
|
|
104
|
+
| { code: 404; path: string }
|
|
105
|
+
|
|
106
|
+
typedSwitch(response, 'code', {
|
|
107
|
+
200: (r) => r.body, // r: { code: 200; body: string }
|
|
108
|
+
404: (r) => `Missing ${r.path}`, // r: { code: 404; path: string }
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
type Result = { ok: true; value: number } | { ok: false; error: string }
|
|
112
|
+
|
|
113
|
+
typedSwitch(result, 'ok', {
|
|
114
|
+
true: (r) => r.value,
|
|
115
|
+
false: (r) => r.error,
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Default Handler
|
|
120
|
+
|
|
121
|
+
Handle a subset of cases and catch the rest with a default handler:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
type Status = 'success' | 'error' | 'pending' | 'cancelled'
|
|
125
|
+
|
|
126
|
+
const status: Status = 'cancelled'
|
|
127
|
+
|
|
128
|
+
// Only handle specific cases, default handles the rest
|
|
129
|
+
const message = typedSwitch(
|
|
130
|
+
status,
|
|
131
|
+
{
|
|
132
|
+
success: () => 'Done!',
|
|
133
|
+
error: () => 'Failed!',
|
|
134
|
+
},
|
|
135
|
+
(val) => `Unhandled status: ${val}` // val: 'pending' | 'cancelled' (unhandled cases only)
|
|
136
|
+
)
|
|
137
|
+
// message: string
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Only required, defined handlers narrow the default handler's input. Optional
|
|
141
|
+
handlers (including reusable `PartialStringSwitchCases` and
|
|
142
|
+
`PartialObjectSwitchCases` maps) can be absent, so their cases remain in the
|
|
143
|
+
default handler's input type.
|
|
144
|
+
|
|
145
|
+
Works with discriminated unions too:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const description = typedSwitch(
|
|
149
|
+
event,
|
|
150
|
+
'type',
|
|
151
|
+
{
|
|
152
|
+
click: (e) => `Clicked at (${e.x}, ${e.y})`,
|
|
153
|
+
},
|
|
154
|
+
(e) => `Unhandled event: ${e.type}` // e: scroll or keypress event (unhandled members only)
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Async Handlers
|
|
159
|
+
|
|
160
|
+
Mix sync and async handlers freely. `typedSwitch` returns the selected handler's value directly, so async branches preserve their `Promise` return type while sync branches remain sync:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// All sync — returns string
|
|
164
|
+
const syncResult = typedSwitch(status, {
|
|
165
|
+
success: () => 'ok',
|
|
166
|
+
error: () => 'err',
|
|
167
|
+
pending: () => 'wait',
|
|
168
|
+
})
|
|
169
|
+
// syncResult: string
|
|
170
|
+
|
|
171
|
+
// All async — returns Promise<string>
|
|
172
|
+
const asyncResult = typedSwitch(status, {
|
|
173
|
+
success: async () => {
|
|
174
|
+
const data = await fetchData()
|
|
175
|
+
return data.message
|
|
176
|
+
},
|
|
177
|
+
error: async () => 'err',
|
|
178
|
+
pending: async () => 'wait',
|
|
179
|
+
})
|
|
180
|
+
// asyncResult: Promise<string>
|
|
181
|
+
|
|
182
|
+
const message = await asyncResult
|
|
183
|
+
|
|
184
|
+
// Mixed sync/async — returns string | Promise<string>
|
|
185
|
+
const mixedResult = typedSwitch(status, {
|
|
186
|
+
success: () => 'ok',
|
|
187
|
+
error: async () => 'err',
|
|
188
|
+
pending: () => 'wait',
|
|
189
|
+
})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Return Type Inference
|
|
193
|
+
|
|
194
|
+
Return types are inferred from all handlers as a union:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
const result = typedSwitch(status, {
|
|
198
|
+
success: () => ({ ok: true, data: 'hello' }),
|
|
199
|
+
error: () => ({ ok: false, code: 500 }),
|
|
200
|
+
pending: () => null,
|
|
201
|
+
})
|
|
202
|
+
// result: { ok: true; data: string } | { ok: false; code: number } | null
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Return Type Constraints
|
|
206
|
+
|
|
207
|
+
Enforce that all handlers return a type extending a constraint with `typedSwitch<Constraint>(...)`. The `<Constraint>` is optional; omit it when you want TypeScript to infer the return types freely.
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
interface HasId {
|
|
211
|
+
id: string
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// All handlers must return something with { id: string }
|
|
215
|
+
const result = typedSwitch<HasId>(status, {
|
|
216
|
+
success: () => ({ id: '123', name: 'John' }), // ✓ OK
|
|
217
|
+
error: () => ({ id: '456', code: 500 }), // ✓ OK
|
|
218
|
+
pending: () => ({ id: '789' }), // ✓ OK
|
|
219
|
+
})
|
|
220
|
+
// result: HasId
|
|
221
|
+
|
|
222
|
+
// This would be a compile error:
|
|
223
|
+
typedSwitch<HasId>(status, {
|
|
224
|
+
success: () => ({ name: 'John' }), // ✗ Error: missing 'id'
|
|
225
|
+
error: () => ({ id: '456' }),
|
|
226
|
+
pending: () => ({ id: '789' }),
|
|
227
|
+
})
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Constraints also work with discriminated unions and default handlers:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
const result = typedSwitch<HasId>(
|
|
234
|
+
event,
|
|
235
|
+
'type',
|
|
236
|
+
{
|
|
237
|
+
click: () => ({ id: 'click-1', x: 10, y: 20 }),
|
|
238
|
+
scroll: () => ({ id: 'scroll-1', offset: 100 }),
|
|
239
|
+
keypress: () => ({ id: 'key-1', key: 'Enter' }),
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Error Handling
|
|
245
|
+
|
|
246
|
+
When a case is unhandled at runtime (e.g., due to unsafe casts), `typedSwitch` throws a descriptive error:
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
const status = 'unknown' as Status
|
|
250
|
+
|
|
251
|
+
typedSwitch(status, {
|
|
252
|
+
success: () => 'ok',
|
|
253
|
+
error: () => 'err',
|
|
254
|
+
})
|
|
255
|
+
// Throws: "Unhandled case: unknown. Available cases: success, error"
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
For discriminated unions:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
// Throws: "Unhandled case: unknown (discriminant key: "type"). Available cases: click, scroll, keypress"
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Object discriminants must be strings, numbers, or booleans. Missing or other discriminant values throw a runtime error if they reach `typedSwitch`.
|
|
265
|
+
|
|
266
|
+
## `assertNever`
|
|
267
|
+
|
|
268
|
+
For regular `switch` statements, put `assertNever` in the `default` branch. It fails to compile if a case is missing, and throws at runtime if an unexpected value gets through:
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { assertNever } from 'typedswitch'
|
|
272
|
+
|
|
273
|
+
function label(status: Status) {
|
|
274
|
+
switch (status) {
|
|
275
|
+
case 'success': return 'Done'
|
|
276
|
+
case 'error': return 'Failed'
|
|
277
|
+
case 'pending': return 'Waiting'
|
|
278
|
+
default: return assertNever(status) // compile error if a case is missing
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## API Reference
|
|
284
|
+
|
|
285
|
+
### `typedSwitch(value, cases)`
|
|
286
|
+
|
|
287
|
+
Switch on a string literal with exhaustive case handling.
|
|
288
|
+
|
|
289
|
+
### `typedSwitch(value, cases, defaultHandler)`
|
|
290
|
+
|
|
291
|
+
Switch on a string literal with partial cases and a default fallback.
|
|
292
|
+
|
|
293
|
+
### `typedSwitch(object, key, cases)`
|
|
294
|
+
|
|
295
|
+
Switch on a discriminated union using the specified discriminant key (string, number, or boolean values).
|
|
296
|
+
|
|
297
|
+
### `typedSwitch(object, key, cases, defaultHandler)`
|
|
298
|
+
|
|
299
|
+
Switch on a discriminated union with partial cases and a default fallback.
|
|
300
|
+
|
|
301
|
+
### `typedSwitch<Constraint>(value, cases)`
|
|
302
|
+
|
|
303
|
+
Switch on a string literal while enforcing that each handler returns `Constraint` or `Promise<Constraint>`.
|
|
304
|
+
|
|
305
|
+
### `typedSwitch<Constraint>(object, key, cases)`
|
|
306
|
+
|
|
307
|
+
Switch on a discriminated union while enforcing that each handler returns `Constraint` or `Promise<Constraint>`.
|
|
308
|
+
|
|
309
|
+
### `assertNever(value, message?)`
|
|
310
|
+
|
|
311
|
+
Takes a `never` value and always throws (`Unexpected value: ${value}` or `message`). Use it for exhaustive `switch` statements.
|
|
312
|
+
|
|
313
|
+
### Exported Helper Types
|
|
314
|
+
|
|
315
|
+
`StringSwitchCases`, `PartialStringSwitchCases`, `ObjectSwitchCases`, and `PartialObjectSwitchCases` are exported for users who want to annotate reusable case maps.
|
|
316
|
+
|
|
317
|
+
## License
|
|
318
|
+
|
|
319
|
+
MIT
|
package/dist/index-srt06xd2.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// src/secrets/errors.ts
|
|
2
|
-
class SecretLoadError2 extends Error {
|
|
3
|
-
code;
|
|
4
|
-
operation;
|
|
5
|
-
status;
|
|
6
|
-
constructor(code, message, details = {}) {
|
|
7
|
-
super(message);
|
|
8
|
-
this.name = "SecretLoadError";
|
|
9
|
-
this.code = code;
|
|
10
|
-
this.operation = details.operation;
|
|
11
|
-
this.status = details.status;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export { SecretLoadError2 };
|