ts-procedures 1.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 +459 -0
- package/package.json +50 -0
- package/src/errors.ts +39 -0
- package/src/exports.ts +6 -0
- package/src/index.test.ts +364 -0
- package/src/index.ts +180 -0
- package/src/schema/compute-schema.test.ts +128 -0
- package/src/schema/compute-schema.ts +55 -0
- package/src/schema/extract-json-schema.test.ts +25 -0
- package/src/schema/extract-json-schema.ts +15 -0
- package/src/schema/parser.test.ts +156 -0
- package/src/schema/parser.ts +92 -0
- package/src/schema/resolve-schema-lib.test.ts +19 -0
- package/src/schema/resolve-schema-lib.ts +29 -0
- package/src/schema/types.ts +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
# ts-procedures
|
|
2
|
+
|
|
3
|
+
A TypeScript RPC framework that creates type-safe, schema-validated procedure calls with a single function definition. Define your procedures once and get full type inference, runtime validation and procedure documentation/configuration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install ts-procedures
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Procedures } from 'ts-procedures'
|
|
15
|
+
import { Type } from 'typebox'
|
|
16
|
+
|
|
17
|
+
// Create a procedures factory
|
|
18
|
+
const { Create } = Procedures()
|
|
19
|
+
|
|
20
|
+
// Define a procedure with schema validation
|
|
21
|
+
const { GetUser, procedure, info } = Create(
|
|
22
|
+
'GetUser',
|
|
23
|
+
{
|
|
24
|
+
description: 'Fetches a user by ID',
|
|
25
|
+
schema: {
|
|
26
|
+
params: Type.Object({ userId: Type.String() }),
|
|
27
|
+
returnType: Type.Object({ id: Type.String(), name: Type.String() }),
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
async (ctx, params /* typed as { userId: string } */) => {
|
|
31
|
+
|
|
32
|
+
// returnType is inferred as { id: string; name: string }
|
|
33
|
+
return { id: params.userId, name: 'John Doe' }
|
|
34
|
+
},
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
// Call the procedure directly
|
|
38
|
+
const user = await GetUser({}, { userId: '123' })
|
|
39
|
+
// Or use the generic reference
|
|
40
|
+
const user2 = await procedure({}, { userId: '456' })
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Core Concepts
|
|
44
|
+
|
|
45
|
+
### Procedures Factory
|
|
46
|
+
|
|
47
|
+
The `Procedures()` function creates a factory for defining procedures. It accepts two generic type parameters:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
Procedures<TContext, TExtendedConfig>(builder?: {
|
|
51
|
+
onCreate?: (procedure: TProcedureRegistration<TContext, TExtendedConfig>) => void
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
| Parameter | Description |
|
|
56
|
+
|-----------|----------------------------------------------------------------------------|
|
|
57
|
+
| `TContext` | The base context type passed to all handlers as the first parameter |
|
|
58
|
+
| `TExtendedConfig` | Additional configuration properties for all procedures `config` properties |
|
|
59
|
+
| `builder.onCreate` | Optional callback invoked when each procedure is registered (runtime) |
|
|
60
|
+
|
|
61
|
+
### Create Function
|
|
62
|
+
|
|
63
|
+
The `Create` function defines individual procedures:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
Create(name, config, handler)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Returns:**
|
|
70
|
+
- `{ [name]: handler }` - Named export for the handler
|
|
71
|
+
- `procedure` - Generic reference to the handler
|
|
72
|
+
- `info` - Procedure meta (name, description, schema, `TExtendedConfig` properties, etc.)
|
|
73
|
+
|
|
74
|
+
## Using Generics
|
|
75
|
+
|
|
76
|
+
### Base Context
|
|
77
|
+
|
|
78
|
+
Define a shared context type for all procedures in your application:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
interface AppContext {
|
|
82
|
+
authToken: string
|
|
83
|
+
requestId: string
|
|
84
|
+
logger: Logger
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const { Create } = Procedures<AppContext>()
|
|
88
|
+
|
|
89
|
+
const { SecureEndpoint } = Create(
|
|
90
|
+
'SecureEndpoint',
|
|
91
|
+
{},
|
|
92
|
+
async (ctx, params) => {
|
|
93
|
+
// ctx.authToken is typed as string
|
|
94
|
+
// ctx.requestId is typed as string
|
|
95
|
+
// ctx.logger is typed as Logger
|
|
96
|
+
return { token: ctx.authToken }
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
// When calling, you must provide the context
|
|
101
|
+
await SecureEndpoint({ authToken: 'abc', requestId: '123', logger: myLogger }, {})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Extended Configuration
|
|
105
|
+
|
|
106
|
+
Add custom properties to all procedure configs:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
interface ExtendedConfig {
|
|
110
|
+
permissions: string[]
|
|
111
|
+
rateLimit?: number
|
|
112
|
+
cacheTTL?: number
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const { Create } = Procedures<AppContext, ExtendedConfig>()
|
|
116
|
+
|
|
117
|
+
const { AdminOnly } = Create(
|
|
118
|
+
'AdminOnly',
|
|
119
|
+
{
|
|
120
|
+
permissions: ['admin'], // Required by ExtendedConfig
|
|
121
|
+
rateLimit: 100, // Optional
|
|
122
|
+
description: 'Admin-only endpoint',
|
|
123
|
+
},
|
|
124
|
+
async (ctx, params) => {
|
|
125
|
+
return { admin: true }
|
|
126
|
+
},
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
// Access extended config via info
|
|
130
|
+
console.log(AdminOnly.info.permissions) // ['admin']
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Combined Example
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
interface CustomContext {
|
|
137
|
+
authToken: string
|
|
138
|
+
tenantId: string
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface ExtendedConfig {
|
|
142
|
+
requiresAuth: boolean
|
|
143
|
+
auditLog?: boolean
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const { Create, getProcedures } = Procedures<CustomContext, ExtendedConfig>({
|
|
147
|
+
onCreate: (procedure) => {
|
|
148
|
+
// Register with your framework
|
|
149
|
+
console.log(`Registered: ${procedure.name}`)
|
|
150
|
+
console.log(`Requires Auth: ${procedure.config.requiresAuth}`)
|
|
151
|
+
},
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const { CreateUser } = Create(
|
|
155
|
+
'CreateUser',
|
|
156
|
+
{
|
|
157
|
+
requiresAuth: true,
|
|
158
|
+
auditLog: true,
|
|
159
|
+
description: 'Creates a new user',
|
|
160
|
+
schema: {
|
|
161
|
+
params: Type.Object({
|
|
162
|
+
email: Type.String(),
|
|
163
|
+
name: Type.String(),
|
|
164
|
+
}),
|
|
165
|
+
returnType: Type.Object({ id: Type.String() }),
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
async (ctx, params) => {
|
|
169
|
+
// Both context and params are fully typed
|
|
170
|
+
return { id: 'user-123' }
|
|
171
|
+
},
|
|
172
|
+
)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Schema Validation
|
|
176
|
+
|
|
177
|
+
### Suretype
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { v } from 'suretype'
|
|
181
|
+
|
|
182
|
+
Create(
|
|
183
|
+
'CreatePost',
|
|
184
|
+
{
|
|
185
|
+
schema: {
|
|
186
|
+
params: Type.Object({
|
|
187
|
+
title: Type.String(),
|
|
188
|
+
content: Type.String(),
|
|
189
|
+
tags: Type.array(Type.String()),
|
|
190
|
+
}),
|
|
191
|
+
returnType: Type.Object({
|
|
192
|
+
id: Type.String(),
|
|
193
|
+
createdAt: Type.String(),
|
|
194
|
+
}),
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
async (ctx, params) => {
|
|
198
|
+
// params typed as { title: string, content: string, tags?: string[] }
|
|
199
|
+
return { id: '1', createdAt: new Date().toISOString() }
|
|
200
|
+
},
|
|
201
|
+
)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### TypeBox
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
import { Type } from 'typebox'
|
|
208
|
+
|
|
209
|
+
Create(
|
|
210
|
+
'CreatePost',
|
|
211
|
+
{
|
|
212
|
+
schema: {
|
|
213
|
+
params: Type.Object({
|
|
214
|
+
title: Type.String(),
|
|
215
|
+
content: Type.String(),
|
|
216
|
+
tags: Type.Optional(Type.Array(Type.String())),
|
|
217
|
+
}),
|
|
218
|
+
returnType: Type.Object({
|
|
219
|
+
id: Type.String(),
|
|
220
|
+
createdAt: Type.String(),
|
|
221
|
+
}),
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
async (ctx, params) => {
|
|
225
|
+
// params typed as { title: string, content: string, tags?: string[] }
|
|
226
|
+
return { id: '1', createdAt: new Date().toISOString() }
|
|
227
|
+
},
|
|
228
|
+
)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Validation Behavior
|
|
232
|
+
|
|
233
|
+
AJV is configured with:
|
|
234
|
+
- `allErrors: true` - Report all validation errors
|
|
235
|
+
- `coerceTypes: true` - Automatically coerce types when possible
|
|
236
|
+
- `removeAdditional: true` - Strip properties not in schema
|
|
237
|
+
|
|
238
|
+
**Note:** `schema.params` is validated at runtime. `schema.returnType` is for documentation/introspection only.
|
|
239
|
+
|
|
240
|
+
## Error Handling
|
|
241
|
+
|
|
242
|
+
### Using ctx.error()
|
|
243
|
+
|
|
244
|
+
The `error()` function is injected into both hooks and handlers:
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
Create(
|
|
248
|
+
'GetResource',
|
|
249
|
+
{},
|
|
250
|
+
async (ctx, params) => {
|
|
251
|
+
const resource = await db.find(params.id)
|
|
252
|
+
if (!resource) {
|
|
253
|
+
throw ctx.error(404, 'Resource not found', { id: params.id })
|
|
254
|
+
}
|
|
255
|
+
return resource
|
|
256
|
+
},
|
|
257
|
+
)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Error Handling
|
|
261
|
+
|
|
262
|
+
| Error Class | Trigger |
|
|
263
|
+
|-------------|---------|
|
|
264
|
+
| ProcedureError | `ctx.error()` in handlers |
|
|
265
|
+
| ProcedureValidationError | Schema validation failure |
|
|
266
|
+
| ProcedureRegistrationError | Invalid schema at registration |
|
|
267
|
+
|
|
268
|
+
### Error Properties
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
try {
|
|
272
|
+
await MyProcedure(ctx, params)
|
|
273
|
+
} catch (e) {
|
|
274
|
+
if (e instanceof ProcedureError) {
|
|
275
|
+
console.log(e.procedureName) // 'MyProcedure'
|
|
276
|
+
console.log(e.message) // 'Resource not found'
|
|
277
|
+
console.log(e.meta) // { id: '123' }
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Framework Integration
|
|
283
|
+
|
|
284
|
+
### onCreate Callback
|
|
285
|
+
|
|
286
|
+
Register procedures with your framework (Express, Fastify, etc.):
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import express from 'express'
|
|
290
|
+
|
|
291
|
+
const app = express()
|
|
292
|
+
const routes: Map<string, Function> = new Map()
|
|
293
|
+
|
|
294
|
+
const { Create } = Procedures<{ req: Request; res: Response }>({
|
|
295
|
+
onCreate: ({ name, handler, config }) => {
|
|
296
|
+
// Register as Express route
|
|
297
|
+
app.post(`/rpc/${name}`, async (req, res) => {
|
|
298
|
+
try {
|
|
299
|
+
const result = await handler({ req, res }, req.body)
|
|
300
|
+
res.json(result)
|
|
301
|
+
} catch (e) {
|
|
302
|
+
if (e instanceof ProcedureError) {
|
|
303
|
+
res.status(500).json({ error: e.message })
|
|
304
|
+
} else {
|
|
305
|
+
res.status(500).json({ error: 'Internal error' })
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
})
|
|
309
|
+
},
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
// Procedures are automatically registered as /rpc/GetUser, /rpc/CreateUser, etc.
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Introspection with getProcedures()
|
|
316
|
+
|
|
317
|
+
Access all registered procedures for documentation or routing:
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
const { Create, getProcedures } = Procedures()
|
|
321
|
+
|
|
322
|
+
Create('GetUser', { schema: { params: Type.Object({ id: Type.String() }) } }, async () => {})
|
|
323
|
+
Create('ListUsers', { schema: { params: Type.Object({}) } }, async () => {})
|
|
324
|
+
|
|
325
|
+
// Get all registered procedures
|
|
326
|
+
const procedures = getProcedures()
|
|
327
|
+
|
|
328
|
+
// Generate OpenAPI spec
|
|
329
|
+
for (const [name, { config }] of procedures) {
|
|
330
|
+
console.log(`${name}:`, config.schema)
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Testing
|
|
335
|
+
|
|
336
|
+
Procedures return handlers that can be called directly in tests:
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
import { describe, test, expect } from 'vitest'
|
|
340
|
+
import { Procedures } from 'ts-procedures'
|
|
341
|
+
import { Type } from 'typebox'
|
|
342
|
+
|
|
343
|
+
interface MyCustomContext {
|
|
344
|
+
userId?: string
|
|
345
|
+
userName?: string
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const { Create } = Procedures<MyCustomContext>()
|
|
349
|
+
|
|
350
|
+
const { GetUser, info } = Create(
|
|
351
|
+
'GetUser',
|
|
352
|
+
{
|
|
353
|
+
schema: {
|
|
354
|
+
params: Type.Object({ hideName: Type.Optional(Type.Boolean()) }),
|
|
355
|
+
returnType: Type.Object({ id: Type.String(), name: Type.String() }),
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
async (ctx, params) => {
|
|
359
|
+
if (!params.userName || !ctx.userId) {
|
|
360
|
+
throw ctx.error('User is not authenticated')
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
id: params.userId,
|
|
365
|
+
name: params?.hideName ? '*******' : params.userName
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
describe('GetUser', () => {
|
|
371
|
+
test('returns user', async () => {
|
|
372
|
+
const result = await GetUser({userId:'123',userName:'Ray'}, { hideName: false })
|
|
373
|
+
expect(result).toEqual({ id: '123', name: 'Ray' })
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
test('hides user name', async () => {
|
|
377
|
+
const result = await GetUser({userId:'123',userName:'Ray'}, { hideName: true })
|
|
378
|
+
expect(result).toEqual({ id: '123', name: '*******' })
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
test('validates params', async () => {
|
|
382
|
+
await expect(GetUser({}, {})).rejects.toThrow(ProcedureValidationError)
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
test('has correct schema', () => {
|
|
386
|
+
expect(info.schema.params).toEqual({
|
|
387
|
+
type: 'object',
|
|
388
|
+
properties: { id: { type: 'string' } },
|
|
389
|
+
required: ['id'],
|
|
390
|
+
})
|
|
391
|
+
})
|
|
392
|
+
})
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## API Reference
|
|
396
|
+
|
|
397
|
+
### Procedures(builder?)
|
|
398
|
+
|
|
399
|
+
Creates a procedure factory.
|
|
400
|
+
|
|
401
|
+
**Parameters:**
|
|
402
|
+
- `builder.onCreate` - Callback invoked when each procedure is registered
|
|
403
|
+
|
|
404
|
+
**Returns:**
|
|
405
|
+
- `Create` - Function to define procedures
|
|
406
|
+
- `getProcedures()` - Returns `Map` of all registered procedures
|
|
407
|
+
|
|
408
|
+
### Create(name, config, handler)
|
|
409
|
+
|
|
410
|
+
Defines a procedure.
|
|
411
|
+
|
|
412
|
+
**Parameters:**
|
|
413
|
+
- `name` - Unique procedure name (becomes named export)
|
|
414
|
+
- `config.description` - Optional description
|
|
415
|
+
- `config.schema.params` - Suretype or TypeBox schema for params (validated at runtime)
|
|
416
|
+
- `config.schema.returnType` - Suretype or TypeBox schema for return returnType (documentation only)
|
|
417
|
+
- Additional properties from `TExtendedConfig`
|
|
418
|
+
- `handler` - Async function `(ctx, params) => Promise<returnType>`
|
|
419
|
+
|
|
420
|
+
**Returns:**
|
|
421
|
+
- `{ [name]: handler }` - Named handler export
|
|
422
|
+
- `procedure` - Generic handler reference
|
|
423
|
+
- `info` - Procedure metareturnType
|
|
424
|
+
|
|
425
|
+
### Type Exports
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
import {
|
|
429
|
+
// Core
|
|
430
|
+
Procedures,
|
|
431
|
+
|
|
432
|
+
// Errors
|
|
433
|
+
ProcedureError,
|
|
434
|
+
ProcedureValidationError,
|
|
435
|
+
ProcedureRegistrationError,
|
|
436
|
+
|
|
437
|
+
// Types
|
|
438
|
+
TLocalContext,
|
|
439
|
+
TProcedureRegistration,
|
|
440
|
+
TNoContextProvided,
|
|
441
|
+
|
|
442
|
+
// Schema utilities
|
|
443
|
+
extractJsonSchema,
|
|
444
|
+
schemaParser,
|
|
445
|
+
isTypeboxSchema,
|
|
446
|
+
isSuretypeSchema,
|
|
447
|
+
|
|
448
|
+
// Schema types
|
|
449
|
+
TJSONSchema,
|
|
450
|
+
TSchemaLib,
|
|
451
|
+
TSchemaParsed,
|
|
452
|
+
TSchemaValidationError,
|
|
453
|
+
Prettify,
|
|
454
|
+
} from 'ts-procedures'
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## License
|
|
458
|
+
|
|
459
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ts-procedures",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A TypeScript RPC framework that creates type-safe, schema-validated procedure calls with a single function definition. Define your procedures once and get full type inference, runtime validation, and framework integration hooks.",
|
|
5
|
+
"main": "dist/exports.js",
|
|
6
|
+
"types": "dist/exports.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/exports.d.ts",
|
|
11
|
+
"import": "./dist/exports.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"lint": "npx eslint src/ --quiet",
|
|
18
|
+
"test": "vitest run"
|
|
19
|
+
},
|
|
20
|
+
"author": "coryrobinson42@gmail.com",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"files": [
|
|
23
|
+
"assets",
|
|
24
|
+
"dist",
|
|
25
|
+
"src"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"typescript",
|
|
29
|
+
"rpc",
|
|
30
|
+
"type-safe",
|
|
31
|
+
"validation",
|
|
32
|
+
"procedures",
|
|
33
|
+
"api",
|
|
34
|
+
"framework"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"ajv": "^8.17.1",
|
|
38
|
+
"ajv-formats": "^3.0.1",
|
|
39
|
+
"typebox": "^1.0.30",
|
|
40
|
+
"suretype": "^3.3.1"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@eslint/js": "^9.17.0",
|
|
44
|
+
"eslint": "^9.17.0",
|
|
45
|
+
"suretype": "^3.3.1",
|
|
46
|
+
"typebox": "^1.0.77",
|
|
47
|
+
"typescript-eslint": "^8.53.0",
|
|
48
|
+
"vitest": "^4.0.18"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { TSchemaValidationError } from './schema/parser.js'
|
|
2
|
+
|
|
3
|
+
export class ProcedureError extends Error {
|
|
4
|
+
constructor(
|
|
5
|
+
readonly procedureName: string,
|
|
6
|
+
readonly message: string,
|
|
7
|
+
readonly meta?: object,
|
|
8
|
+
) {
|
|
9
|
+
super(message)
|
|
10
|
+
this.name = 'ProcedureError'
|
|
11
|
+
|
|
12
|
+
// https://www.dannyguo.com/blog/how-to-fix-instanceof-not-working-for-custom-errors-in-typescript/
|
|
13
|
+
Object.setPrototypeOf(this, ProcedureError.prototype)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class ProcedureValidationError extends ProcedureError {
|
|
18
|
+
constructor(
|
|
19
|
+
readonly procedureName: string,
|
|
20
|
+
message: string,
|
|
21
|
+
readonly errors?: TSchemaValidationError[],
|
|
22
|
+
) {
|
|
23
|
+
super(procedureName, message)
|
|
24
|
+
this.name = 'ProcedureValidationError'
|
|
25
|
+
|
|
26
|
+
// https://www.dannyguo.com/blog/how-to-fix-instanceof-not-working-for-custom-errors-in-typescript/
|
|
27
|
+
Object.setPrototypeOf(this, ProcedureValidationError.prototype)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class ProcedureRegistrationError extends Error {
|
|
32
|
+
constructor(readonly procedureName: string, message: string) {
|
|
33
|
+
super(message)
|
|
34
|
+
this.name = 'ProcedureRegistrationError'
|
|
35
|
+
|
|
36
|
+
// https://www.dannyguo.com/blog/how-to-fix-instanceof-not-working-for-custom-errors-in-typescript/
|
|
37
|
+
Object.setPrototypeOf(this, ProcedureRegistrationError.prototype)
|
|
38
|
+
}
|
|
39
|
+
}
|