@sip-protocol/sdk 0.1.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/dist/index.d.mts +3640 -0
- package/dist/index.d.ts +3640 -0
- package/dist/index.js +5725 -0
- package/dist/index.mjs +5606 -0
- package/package.json +61 -0
- package/src/adapters/index.ts +19 -0
- package/src/adapters/near-intents.ts +475 -0
- package/src/adapters/oneclick-client.ts +367 -0
- package/src/commitment.ts +470 -0
- package/src/crypto.ts +93 -0
- package/src/errors.ts +471 -0
- package/src/index.ts +369 -0
- package/src/intent.ts +488 -0
- package/src/privacy.ts +382 -0
- package/src/proofs/index.ts +52 -0
- package/src/proofs/interface.ts +228 -0
- package/src/proofs/mock.ts +258 -0
- package/src/proofs/noir.ts +233 -0
- package/src/sip.ts +299 -0
- package/src/solver/index.ts +25 -0
- package/src/solver/mock-solver.ts +278 -0
- package/src/stealth.ts +414 -0
- package/src/validation.ts +401 -0
- package/src/wallet/base-adapter.ts +407 -0
- package/src/wallet/errors.ts +106 -0
- package/src/wallet/ethereum/adapter.ts +655 -0
- package/src/wallet/ethereum/index.ts +48 -0
- package/src/wallet/ethereum/mock.ts +505 -0
- package/src/wallet/ethereum/types.ts +364 -0
- package/src/wallet/index.ts +116 -0
- package/src/wallet/registry.ts +207 -0
- package/src/wallet/solana/adapter.ts +533 -0
- package/src/wallet/solana/index.ts +40 -0
- package/src/wallet/solana/mock.ts +522 -0
- package/src/wallet/solana/types.ts +253 -0
- package/src/zcash/index.ts +53 -0
- package/src/zcash/rpc-client.ts +623 -0
- package/src/zcash/shielded-service.ts +641 -0
package/src/errors.ts
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom errors for SIP Protocol SDK
|
|
3
|
+
*
|
|
4
|
+
* Provides a comprehensive error hierarchy with:
|
|
5
|
+
* - Machine-readable error codes
|
|
6
|
+
* - Human-readable messages
|
|
7
|
+
* - Original cause preservation
|
|
8
|
+
* - Additional debugging context
|
|
9
|
+
* - Serialization for logging
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// ─── Error Codes ─────────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Machine-readable error codes for programmatic error handling
|
|
16
|
+
*/
|
|
17
|
+
export enum ErrorCode {
|
|
18
|
+
// General errors (1xxx)
|
|
19
|
+
UNKNOWN = 'SIP_1000',
|
|
20
|
+
INTERNAL = 'SIP_1001',
|
|
21
|
+
NOT_IMPLEMENTED = 'SIP_1002',
|
|
22
|
+
|
|
23
|
+
// Validation errors (2xxx)
|
|
24
|
+
VALIDATION_FAILED = 'SIP_2000',
|
|
25
|
+
INVALID_INPUT = 'SIP_2001',
|
|
26
|
+
INVALID_CHAIN = 'SIP_2002',
|
|
27
|
+
INVALID_PRIVACY_LEVEL = 'SIP_2003',
|
|
28
|
+
INVALID_AMOUNT = 'SIP_2004',
|
|
29
|
+
INVALID_HEX = 'SIP_2005',
|
|
30
|
+
INVALID_KEY = 'SIP_2006',
|
|
31
|
+
INVALID_ADDRESS = 'SIP_2007',
|
|
32
|
+
MISSING_REQUIRED = 'SIP_2008',
|
|
33
|
+
OUT_OF_RANGE = 'SIP_2009',
|
|
34
|
+
|
|
35
|
+
// Cryptographic errors (3xxx)
|
|
36
|
+
CRYPTO_FAILED = 'SIP_3000',
|
|
37
|
+
ENCRYPTION_FAILED = 'SIP_3001',
|
|
38
|
+
DECRYPTION_FAILED = 'SIP_3002',
|
|
39
|
+
KEY_DERIVATION_FAILED = 'SIP_3003',
|
|
40
|
+
COMMITMENT_FAILED = 'SIP_3004',
|
|
41
|
+
SIGNATURE_FAILED = 'SIP_3005',
|
|
42
|
+
INVALID_CURVE_POINT = 'SIP_3006',
|
|
43
|
+
INVALID_SCALAR = 'SIP_3007',
|
|
44
|
+
|
|
45
|
+
// Proof errors (4xxx)
|
|
46
|
+
PROOF_FAILED = 'SIP_4000',
|
|
47
|
+
PROOF_GENERATION_FAILED = 'SIP_4001',
|
|
48
|
+
PROOF_VERIFICATION_FAILED = 'SIP_4002',
|
|
49
|
+
PROOF_NOT_IMPLEMENTED = 'SIP_4003',
|
|
50
|
+
PROOF_PROVIDER_NOT_READY = 'SIP_4004',
|
|
51
|
+
INVALID_PROOF_PARAMS = 'SIP_4005',
|
|
52
|
+
|
|
53
|
+
// Intent errors (5xxx)
|
|
54
|
+
INTENT_FAILED = 'SIP_5000',
|
|
55
|
+
INTENT_EXPIRED = 'SIP_5001',
|
|
56
|
+
INTENT_CANCELLED = 'SIP_5002',
|
|
57
|
+
INTENT_NOT_FOUND = 'SIP_5003',
|
|
58
|
+
INTENT_INVALID_STATE = 'SIP_5004',
|
|
59
|
+
PROOFS_REQUIRED = 'SIP_5005',
|
|
60
|
+
QUOTE_EXPIRED = 'SIP_5006',
|
|
61
|
+
|
|
62
|
+
// Network errors (6xxx)
|
|
63
|
+
NETWORK_FAILED = 'SIP_6000',
|
|
64
|
+
NETWORK_TIMEOUT = 'SIP_6001',
|
|
65
|
+
NETWORK_UNAVAILABLE = 'SIP_6002',
|
|
66
|
+
RPC_ERROR = 'SIP_6003',
|
|
67
|
+
API_ERROR = 'SIP_6004',
|
|
68
|
+
RATE_LIMITED = 'SIP_6005',
|
|
69
|
+
|
|
70
|
+
// Wallet errors (7xxx)
|
|
71
|
+
WALLET_ERROR = 'SIP_7000',
|
|
72
|
+
WALLET_NOT_CONNECTED = 'SIP_7001',
|
|
73
|
+
WALLET_CONNECTION_FAILED = 'SIP_7002',
|
|
74
|
+
WALLET_SIGNING_FAILED = 'SIP_7003',
|
|
75
|
+
WALLET_TRANSACTION_FAILED = 'SIP_7004',
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ─── Serialized Error Type ───────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Serialized error format for logging and transmission
|
|
82
|
+
*/
|
|
83
|
+
export interface SerializedError {
|
|
84
|
+
name: string
|
|
85
|
+
code: ErrorCode
|
|
86
|
+
message: string
|
|
87
|
+
field?: string
|
|
88
|
+
context?: Record<string, unknown>
|
|
89
|
+
cause?: string
|
|
90
|
+
stack?: string
|
|
91
|
+
timestamp: string
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ─── Base Error Class ────────────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Base error class for SIP Protocol
|
|
98
|
+
*
|
|
99
|
+
* All SDK errors extend this class and include:
|
|
100
|
+
* - `code`: Machine-readable error code for programmatic handling
|
|
101
|
+
* - `cause`: Original error if this error wraps another
|
|
102
|
+
* - `context`: Additional debugging information
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* try {
|
|
107
|
+
* await sip.execute(intent, quote)
|
|
108
|
+
* } catch (e) {
|
|
109
|
+
* if (e instanceof SIPError) {
|
|
110
|
+
* console.log(`Error ${e.code}: ${e.message}`)
|
|
111
|
+
* if (e.cause) console.log('Caused by:', e.cause)
|
|
112
|
+
* }
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export class SIPError extends Error {
|
|
117
|
+
/** Machine-readable error code */
|
|
118
|
+
readonly code: ErrorCode
|
|
119
|
+
|
|
120
|
+
/** Additional debugging context */
|
|
121
|
+
readonly context?: Record<string, unknown>
|
|
122
|
+
|
|
123
|
+
/** Timestamp when error was created */
|
|
124
|
+
readonly timestamp: Date
|
|
125
|
+
|
|
126
|
+
constructor(
|
|
127
|
+
message: string,
|
|
128
|
+
code: ErrorCode = ErrorCode.UNKNOWN,
|
|
129
|
+
options?: {
|
|
130
|
+
cause?: Error
|
|
131
|
+
context?: Record<string, unknown>
|
|
132
|
+
}
|
|
133
|
+
) {
|
|
134
|
+
super(message, { cause: options?.cause })
|
|
135
|
+
this.name = 'SIPError'
|
|
136
|
+
this.code = code
|
|
137
|
+
this.context = options?.context
|
|
138
|
+
this.timestamp = new Date()
|
|
139
|
+
|
|
140
|
+
// Preserve stack trace
|
|
141
|
+
if (Error.captureStackTrace) {
|
|
142
|
+
Error.captureStackTrace(this, this.constructor)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Serialize error for logging or transmission
|
|
148
|
+
*/
|
|
149
|
+
toJSON(): SerializedError {
|
|
150
|
+
return {
|
|
151
|
+
name: this.name,
|
|
152
|
+
code: this.code,
|
|
153
|
+
message: this.message,
|
|
154
|
+
context: this.context,
|
|
155
|
+
cause: this.cause instanceof Error ? this.cause.message : undefined,
|
|
156
|
+
stack: this.stack,
|
|
157
|
+
timestamp: this.timestamp.toISOString(),
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Create a string representation for logging
|
|
163
|
+
*/
|
|
164
|
+
toString(): string {
|
|
165
|
+
let result = `[${this.code}] ${this.name}: ${this.message}`
|
|
166
|
+
if (this.cause instanceof Error) {
|
|
167
|
+
result += `\n Caused by: ${this.cause.message}`
|
|
168
|
+
}
|
|
169
|
+
return result
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ─── Validation Error ────────────────────────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Error thrown when input validation fails
|
|
177
|
+
*
|
|
178
|
+
* Provides detailed information about what validation failed
|
|
179
|
+
* and optionally which field caused the error.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* throw new ValidationError('Amount must be positive', 'input.amount')
|
|
184
|
+
*
|
|
185
|
+
* // With error code
|
|
186
|
+
* throw new ValidationError('Invalid chain ID', 'chain', {
|
|
187
|
+
* code: ErrorCode.INVALID_CHAIN,
|
|
188
|
+
* context: { received: 'invalid-chain' }
|
|
189
|
+
* })
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
export class ValidationError extends SIPError {
|
|
193
|
+
/** The field that failed validation (if applicable) */
|
|
194
|
+
readonly field?: string
|
|
195
|
+
|
|
196
|
+
constructor(
|
|
197
|
+
message: string,
|
|
198
|
+
field?: string,
|
|
199
|
+
context?: Record<string, unknown>,
|
|
200
|
+
code: ErrorCode = ErrorCode.VALIDATION_FAILED,
|
|
201
|
+
) {
|
|
202
|
+
const fullMessage = field
|
|
203
|
+
? `Validation failed for '${field}': ${message}`
|
|
204
|
+
: `Validation failed: ${message}`
|
|
205
|
+
super(fullMessage, code, { context })
|
|
206
|
+
this.name = 'ValidationError'
|
|
207
|
+
this.field = field
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
toJSON(): SerializedError {
|
|
211
|
+
return {
|
|
212
|
+
...super.toJSON(),
|
|
213
|
+
field: this.field,
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ─── Cryptographic Error ─────────────────────────────────────────────────────
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Error thrown when cryptographic operations fail
|
|
222
|
+
*
|
|
223
|
+
* Covers encryption, decryption, key derivation, commitments, and signatures.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```typescript
|
|
227
|
+
* throw new CryptoError('Decryption failed', ErrorCode.DECRYPTION_FAILED, {
|
|
228
|
+
* cause: originalError,
|
|
229
|
+
* context: { operation: 'decryptWithViewing' }
|
|
230
|
+
* })
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
export class CryptoError extends SIPError {
|
|
234
|
+
/** The cryptographic operation that failed */
|
|
235
|
+
readonly operation?: string
|
|
236
|
+
|
|
237
|
+
constructor(
|
|
238
|
+
message: string,
|
|
239
|
+
code: ErrorCode = ErrorCode.CRYPTO_FAILED,
|
|
240
|
+
options?: {
|
|
241
|
+
cause?: Error
|
|
242
|
+
context?: Record<string, unknown>
|
|
243
|
+
operation?: string
|
|
244
|
+
}
|
|
245
|
+
) {
|
|
246
|
+
super(message, code, options)
|
|
247
|
+
this.name = 'CryptoError'
|
|
248
|
+
this.operation = options?.operation
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Error thrown when encryption functions are called but not yet implemented
|
|
254
|
+
*
|
|
255
|
+
* @deprecated Use CryptoError with ErrorCode.NOT_IMPLEMENTED instead
|
|
256
|
+
*/
|
|
257
|
+
export class EncryptionNotImplementedError extends CryptoError {
|
|
258
|
+
/** The type of encryption operation */
|
|
259
|
+
readonly operationType: 'encrypt' | 'decrypt'
|
|
260
|
+
|
|
261
|
+
/** Reference to the specification document */
|
|
262
|
+
readonly specReference: string
|
|
263
|
+
|
|
264
|
+
constructor(
|
|
265
|
+
operation: 'encrypt' | 'decrypt',
|
|
266
|
+
specReference: string,
|
|
267
|
+
) {
|
|
268
|
+
const message = `${operation.charAt(0).toUpperCase() + operation.slice(1)}ion is not implemented. ` +
|
|
269
|
+
`Real authenticated encryption (ChaCha20-Poly1305) is required. ` +
|
|
270
|
+
`See specification: ${specReference}`
|
|
271
|
+
super(message, ErrorCode.NOT_IMPLEMENTED, {
|
|
272
|
+
context: { operation, specReference }
|
|
273
|
+
})
|
|
274
|
+
this.name = 'EncryptionNotImplementedError'
|
|
275
|
+
this.operationType = operation
|
|
276
|
+
this.specReference = specReference
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ─── Proof Error ─────────────────────────────────────────────────────────────
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Error thrown when proof operations fail
|
|
284
|
+
*
|
|
285
|
+
* Covers proof generation, verification, and related operations.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```typescript
|
|
289
|
+
* throw new ProofError('Proof verification failed', ErrorCode.PROOF_VERIFICATION_FAILED, {
|
|
290
|
+
* context: { proofType: 'funding', publicInputs: [...] }
|
|
291
|
+
* })
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
export class ProofError extends SIPError {
|
|
295
|
+
/** The type of proof involved */
|
|
296
|
+
readonly proofType?: 'funding' | 'validity' | 'fulfillment' | 'viewing'
|
|
297
|
+
|
|
298
|
+
constructor(
|
|
299
|
+
message: string,
|
|
300
|
+
code: ErrorCode = ErrorCode.PROOF_FAILED,
|
|
301
|
+
options?: {
|
|
302
|
+
cause?: Error
|
|
303
|
+
context?: Record<string, unknown>
|
|
304
|
+
proofType?: 'funding' | 'validity' | 'fulfillment' | 'viewing'
|
|
305
|
+
}
|
|
306
|
+
) {
|
|
307
|
+
super(message, code, options)
|
|
308
|
+
this.name = 'ProofError'
|
|
309
|
+
this.proofType = options?.proofType
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Error thrown when a proof function is called but not yet implemented
|
|
315
|
+
*
|
|
316
|
+
* This error indicates that real ZK proof generation is required but not available.
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* ```typescript
|
|
320
|
+
* // Use ProofProvider for proof generation
|
|
321
|
+
* const provider = new NoirProofProvider(config)
|
|
322
|
+
* await provider.initialize()
|
|
323
|
+
* const result = await provider.generateFundingProof(params)
|
|
324
|
+
* ```
|
|
325
|
+
*/
|
|
326
|
+
export class ProofNotImplementedError extends ProofError {
|
|
327
|
+
/** Reference to the specification document */
|
|
328
|
+
readonly specReference: string
|
|
329
|
+
|
|
330
|
+
constructor(
|
|
331
|
+
proofType: 'funding' | 'validity' | 'fulfillment' | 'viewing',
|
|
332
|
+
specReference: string,
|
|
333
|
+
) {
|
|
334
|
+
const message = `${proofType.charAt(0).toUpperCase() + proofType.slice(1)} proof generation is not implemented. ` +
|
|
335
|
+
`Real ZK proofs are required for production use. ` +
|
|
336
|
+
`See specification: ${specReference}`
|
|
337
|
+
super(message, ErrorCode.PROOF_NOT_IMPLEMENTED, {
|
|
338
|
+
context: { specReference },
|
|
339
|
+
proofType,
|
|
340
|
+
})
|
|
341
|
+
this.name = 'ProofNotImplementedError'
|
|
342
|
+
this.specReference = specReference
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ─── Intent Error ────────────────────────────────────────────────────────────
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Error thrown when intent operations fail
|
|
350
|
+
*
|
|
351
|
+
* Covers intent creation, execution, and lifecycle errors.
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```typescript
|
|
355
|
+
* throw new IntentError('Intent has expired', ErrorCode.INTENT_EXPIRED, {
|
|
356
|
+
* context: { intentId, expiry, now: Date.now() }
|
|
357
|
+
* })
|
|
358
|
+
* ```
|
|
359
|
+
*/
|
|
360
|
+
export class IntentError extends SIPError {
|
|
361
|
+
/** The intent ID involved (if available) */
|
|
362
|
+
readonly intentId?: string
|
|
363
|
+
|
|
364
|
+
constructor(
|
|
365
|
+
message: string,
|
|
366
|
+
code: ErrorCode = ErrorCode.INTENT_FAILED,
|
|
367
|
+
options?: {
|
|
368
|
+
cause?: Error
|
|
369
|
+
context?: Record<string, unknown>
|
|
370
|
+
intentId?: string
|
|
371
|
+
}
|
|
372
|
+
) {
|
|
373
|
+
super(message, code, options)
|
|
374
|
+
this.name = 'IntentError'
|
|
375
|
+
this.intentId = options?.intentId
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// ─── Network Error ───────────────────────────────────────────────────────────
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Error thrown when external service communication fails
|
|
383
|
+
*
|
|
384
|
+
* Covers RPC calls, API requests, and network connectivity issues.
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* ```typescript
|
|
388
|
+
* throw new NetworkError('RPC request failed', ErrorCode.RPC_ERROR, {
|
|
389
|
+
* cause: originalError,
|
|
390
|
+
* context: { endpoint: 'https://...', method: 'eth_call' }
|
|
391
|
+
* })
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
export class NetworkError extends SIPError {
|
|
395
|
+
/** The endpoint that failed (if applicable) */
|
|
396
|
+
readonly endpoint?: string
|
|
397
|
+
|
|
398
|
+
/** HTTP status code (if applicable) */
|
|
399
|
+
readonly statusCode?: number
|
|
400
|
+
|
|
401
|
+
constructor(
|
|
402
|
+
message: string,
|
|
403
|
+
code: ErrorCode = ErrorCode.NETWORK_FAILED,
|
|
404
|
+
options?: {
|
|
405
|
+
cause?: Error
|
|
406
|
+
context?: Record<string, unknown>
|
|
407
|
+
endpoint?: string
|
|
408
|
+
statusCode?: number
|
|
409
|
+
}
|
|
410
|
+
) {
|
|
411
|
+
super(message, code, options)
|
|
412
|
+
this.name = 'NetworkError'
|
|
413
|
+
this.endpoint = options?.endpoint
|
|
414
|
+
this.statusCode = options?.statusCode
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// ─── Error Utilities ─────────────────────────────────────────────────────────
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Check if an error is a SIP Protocol error
|
|
422
|
+
*/
|
|
423
|
+
export function isSIPError(error: unknown): error is SIPError {
|
|
424
|
+
return error instanceof SIPError
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Check if an error has a specific error code
|
|
429
|
+
*/
|
|
430
|
+
export function hasErrorCode(error: unknown, code: ErrorCode): boolean {
|
|
431
|
+
return isSIPError(error) && error.code === code
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Wrap an unknown error as a SIPError
|
|
436
|
+
*
|
|
437
|
+
* Useful for catching and re-throwing with additional context.
|
|
438
|
+
*
|
|
439
|
+
* @example
|
|
440
|
+
* ```typescript
|
|
441
|
+
* try {
|
|
442
|
+
* await riskyOperation()
|
|
443
|
+
* } catch (e) {
|
|
444
|
+
* throw wrapError(e, 'Operation failed', ErrorCode.INTERNAL)
|
|
445
|
+
* }
|
|
446
|
+
* ```
|
|
447
|
+
*/
|
|
448
|
+
export function wrapError(
|
|
449
|
+
error: unknown,
|
|
450
|
+
message: string,
|
|
451
|
+
code: ErrorCode = ErrorCode.INTERNAL,
|
|
452
|
+
context?: Record<string, unknown>
|
|
453
|
+
): SIPError {
|
|
454
|
+
if (error instanceof SIPError) {
|
|
455
|
+
return error
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const cause = error instanceof Error ? error : new Error(String(error))
|
|
459
|
+
|
|
460
|
+
return new SIPError(message, code, { cause, context })
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Extract error message from unknown error
|
|
465
|
+
*/
|
|
466
|
+
export function getErrorMessage(error: unknown): string {
|
|
467
|
+
if (error instanceof Error) {
|
|
468
|
+
return error.message
|
|
469
|
+
}
|
|
470
|
+
return String(error)
|
|
471
|
+
}
|