@originals/sdk 1.4.2 → 1.4.3
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/package.json +4 -1
- package/.eslintrc.json +0 -33
- package/src/adapters/FeeOracleMock.ts +0 -9
- package/src/adapters/index.ts +0 -5
- package/src/adapters/providers/OrdHttpProvider.ts +0 -126
- package/src/adapters/providers/OrdMockProvider.ts +0 -101
- package/src/adapters/types.ts +0 -66
- package/src/bitcoin/BitcoinManager.ts +0 -330
- package/src/bitcoin/BroadcastClient.ts +0 -54
- package/src/bitcoin/OrdinalsClient.ts +0 -119
- package/src/bitcoin/PSBTBuilder.ts +0 -106
- package/src/bitcoin/fee-calculation.ts +0 -38
- package/src/bitcoin/providers/OrdNodeProvider.ts +0 -92
- package/src/bitcoin/providers/OrdinalsProvider.ts +0 -56
- package/src/bitcoin/providers/types.ts +0 -59
- package/src/bitcoin/transactions/commit.ts +0 -465
- package/src/bitcoin/transactions/index.ts +0 -13
- package/src/bitcoin/transfer.ts +0 -43
- package/src/bitcoin/utxo-selection.ts +0 -322
- package/src/bitcoin/utxo.ts +0 -113
- package/src/contexts/credentials-v1.json +0 -237
- package/src/contexts/credentials-v2-examples.json +0 -5
- package/src/contexts/credentials-v2.json +0 -340
- package/src/contexts/credentials.json +0 -237
- package/src/contexts/data-integrity-v2.json +0 -81
- package/src/contexts/dids.json +0 -58
- package/src/contexts/ed255192020.json +0 -93
- package/src/contexts/ordinals-plus.json +0 -23
- package/src/contexts/originals.json +0 -22
- package/src/core/OriginalsSDK.ts +0 -416
- package/src/crypto/Multikey.ts +0 -194
- package/src/crypto/Signer.ts +0 -254
- package/src/crypto/noble-init.ts +0 -121
- package/src/did/BtcoDidResolver.ts +0 -227
- package/src/did/DIDManager.ts +0 -694
- package/src/did/Ed25519Verifier.ts +0 -68
- package/src/did/KeyManager.ts +0 -236
- package/src/did/WebVHManager.ts +0 -498
- package/src/did/createBtcoDidDocument.ts +0 -59
- package/src/did/providers/OrdinalsClientProviderAdapter.ts +0 -68
- package/src/events/EventEmitter.ts +0 -222
- package/src/events/index.ts +0 -19
- package/src/events/types.ts +0 -331
- package/src/examples/basic-usage.ts +0 -78
- package/src/examples/create-module-original.ts +0 -435
- package/src/examples/full-lifecycle-flow.ts +0 -514
- package/src/examples/run.ts +0 -60
- package/src/index.ts +0 -150
- package/src/kinds/KindRegistry.ts +0 -290
- package/src/kinds/index.ts +0 -74
- package/src/kinds/types.ts +0 -470
- package/src/kinds/validators/AgentValidator.ts +0 -257
- package/src/kinds/validators/AppValidator.ts +0 -211
- package/src/kinds/validators/DatasetValidator.ts +0 -242
- package/src/kinds/validators/DocumentValidator.ts +0 -311
- package/src/kinds/validators/MediaValidator.ts +0 -269
- package/src/kinds/validators/ModuleValidator.ts +0 -225
- package/src/kinds/validators/base.ts +0 -276
- package/src/kinds/validators/index.ts +0 -12
- package/src/lifecycle/BatchOperations.ts +0 -373
- package/src/lifecycle/LifecycleManager.ts +0 -2126
- package/src/lifecycle/OriginalsAsset.ts +0 -524
- package/src/lifecycle/ProvenanceQuery.ts +0 -280
- package/src/lifecycle/ResourceVersioning.ts +0 -163
- package/src/migration/MigrationManager.ts +0 -527
- package/src/migration/audit/AuditLogger.ts +0 -176
- package/src/migration/checkpoint/CheckpointManager.ts +0 -112
- package/src/migration/checkpoint/CheckpointStorage.ts +0 -101
- package/src/migration/index.ts +0 -33
- package/src/migration/operations/BaseMigration.ts +0 -126
- package/src/migration/operations/PeerToBtcoMigration.ts +0 -105
- package/src/migration/operations/PeerToWebvhMigration.ts +0 -62
- package/src/migration/operations/WebvhToBtcoMigration.ts +0 -105
- package/src/migration/rollback/RollbackManager.ts +0 -170
- package/src/migration/state/StateMachine.ts +0 -92
- package/src/migration/state/StateTracker.ts +0 -156
- package/src/migration/types.ts +0 -344
- package/src/migration/validation/BitcoinValidator.ts +0 -107
- package/src/migration/validation/CredentialValidator.ts +0 -62
- package/src/migration/validation/DIDCompatibilityValidator.ts +0 -151
- package/src/migration/validation/LifecycleValidator.ts +0 -64
- package/src/migration/validation/StorageValidator.ts +0 -79
- package/src/migration/validation/ValidationPipeline.ts +0 -213
- package/src/resources/ResourceManager.ts +0 -655
- package/src/resources/index.ts +0 -21
- package/src/resources/types.ts +0 -202
- package/src/storage/LocalStorageAdapter.ts +0 -61
- package/src/storage/MemoryStorageAdapter.ts +0 -29
- package/src/storage/StorageAdapter.ts +0 -25
- package/src/storage/index.ts +0 -3
- package/src/types/bitcoin.ts +0 -98
- package/src/types/common.ts +0 -92
- package/src/types/credentials.ts +0 -88
- package/src/types/did.ts +0 -31
- package/src/types/external-shims.d.ts +0 -53
- package/src/types/index.ts +0 -7
- package/src/types/network.ts +0 -175
- package/src/utils/EventLogger.ts +0 -298
- package/src/utils/Logger.ts +0 -322
- package/src/utils/MetricsCollector.ts +0 -358
- package/src/utils/bitcoin-address.ts +0 -130
- package/src/utils/cbor.ts +0 -12
- package/src/utils/encoding.ts +0 -127
- package/src/utils/hash.ts +0 -6
- package/src/utils/retry.ts +0 -46
- package/src/utils/satoshi-validation.ts +0 -196
- package/src/utils/serialization.ts +0 -96
- package/src/utils/telemetry.ts +0 -40
- package/src/utils/validation.ts +0 -119
- package/src/vc/CredentialManager.ts +0 -918
- package/src/vc/Issuer.ts +0 -100
- package/src/vc/Verifier.ts +0 -47
- package/src/vc/cryptosuites/bbs.ts +0 -253
- package/src/vc/cryptosuites/bbsSimple.ts +0 -21
- package/src/vc/cryptosuites/eddsa.ts +0 -99
- package/src/vc/documentLoader.ts +0 -67
- package/src/vc/proofs/data-integrity.ts +0 -33
- package/src/vc/utils/jsonld.ts +0 -18
- package/tests/__mocks__/bbs-signatures.js +0 -17
- package/tests/__mocks__/mf-base58.js +0 -24
- package/tests/fixtures/did-documents.ts +0 -247
- package/tests/index.test.ts +0 -21
- package/tests/integration/BatchOperations.test.ts +0 -531
- package/tests/integration/CompleteLifecycle.e2e.test.ts +0 -735
- package/tests/integration/CredentialManager.test.ts +0 -42
- package/tests/integration/DIDManager.test.ts +0 -41
- package/tests/integration/DidPeerToWebVhFlow.test.ts +0 -351
- package/tests/integration/Events.test.ts +0 -435
- package/tests/integration/Lifecycle.transfer.btco.integration.test.ts +0 -25
- package/tests/integration/LifecycleManager.test.ts +0 -21
- package/tests/integration/MultikeyFlow.test.ts +0 -52
- package/tests/integration/TelemetryIntegration.test.ts +0 -395
- package/tests/integration/WebVhPublish.test.ts +0 -48
- package/tests/integration/createTypedOriginal.test.ts +0 -379
- package/tests/integration/migration/peer-to-webvh.test.ts +0 -172
- package/tests/manual/test-commit-creation.ts +0 -323
- package/tests/mocks/MockKeyStore.ts +0 -38
- package/tests/mocks/adapters/MemoryStorageAdapter.ts +0 -24
- package/tests/mocks/adapters/MockFeeOracle.ts +0 -11
- package/tests/mocks/adapters/MockOrdinalsProvider.ts +0 -76
- package/tests/mocks/adapters/OrdMockProvider.test.ts +0 -176
- package/tests/mocks/adapters/index.ts +0 -6
- package/tests/performance/BatchOperations.perf.test.ts +0 -403
- package/tests/performance/logging.perf.test.ts +0 -336
- package/tests/sdk.test.ts +0 -43
- package/tests/security/bitcoin-penetration-tests.test.ts +0 -622
- package/tests/setup.bun.ts +0 -69
- package/tests/setup.jest.ts +0 -23
- package/tests/stress/batch-operations-stress.test.ts +0 -571
- package/tests/unit/adapters/FeeOracleMock.test.ts +0 -40
- package/tests/unit/bitcoin/BitcoinManager.test.ts +0 -293
- package/tests/unit/bitcoin/BroadcastClient.test.ts +0 -52
- package/tests/unit/bitcoin/OrdNodeProvider.test.ts +0 -53
- package/tests/unit/bitcoin/OrdinalsClient.test.ts +0 -381
- package/tests/unit/bitcoin/OrdinalsClientProvider.test.ts +0 -102
- package/tests/unit/bitcoin/PSBTBuilder.test.ts +0 -84
- package/tests/unit/bitcoin/fee-calculation.test.ts +0 -261
- package/tests/unit/bitcoin/transactions/commit.test.ts +0 -649
- package/tests/unit/bitcoin/transfer.test.ts +0 -31
- package/tests/unit/bitcoin/utxo-selection-new.test.ts +0 -502
- package/tests/unit/bitcoin/utxo.more.test.ts +0 -39
- package/tests/unit/bitcoin/utxo.selection.test.ts +0 -38
- package/tests/unit/core/OriginalsSDK.test.ts +0 -152
- package/tests/unit/crypto/Multikey.test.ts +0 -206
- package/tests/unit/crypto/Signer.test.ts +0 -408
- package/tests/unit/did/BtcoDidResolver.test.ts +0 -611
- package/tests/unit/did/DIDManager.more.test.ts +0 -43
- package/tests/unit/did/DIDManager.test.ts +0 -185
- package/tests/unit/did/Ed25519Verifier.test.ts +0 -160
- package/tests/unit/did/KeyManager.test.ts +0 -452
- package/tests/unit/did/OrdinalsClientProviderAdapter.test.ts +0 -45
- package/tests/unit/did/WebVHManager.test.ts +0 -435
- package/tests/unit/did/createBtcoDidDocument.test.ts +0 -67
- package/tests/unit/did/providers/OrdinalsClientProviderAdapter.test.ts +0 -159
- package/tests/unit/events/EventEmitter.test.ts +0 -407
- package/tests/unit/kinds/KindRegistry.test.ts +0 -329
- package/tests/unit/kinds/types.test.ts +0 -409
- package/tests/unit/kinds/validators.test.ts +0 -651
- package/tests/unit/lifecycle/BatchOperations.test.ts +0 -527
- package/tests/unit/lifecycle/LifecycleManager.cleanapi.test.ts +0 -441
- package/tests/unit/lifecycle/LifecycleManager.keymanagement.test.ts +0 -312
- package/tests/unit/lifecycle/LifecycleManager.prov.test.ts +0 -18
- package/tests/unit/lifecycle/LifecycleManager.test.ts +0 -213
- package/tests/unit/lifecycle/LifecycleManager.transfer.unit.test.ts +0 -30
- package/tests/unit/lifecycle/OriginalsAsset.test.ts +0 -176
- package/tests/unit/lifecycle/ProvenanceQuery.test.ts +0 -577
- package/tests/unit/lifecycle/ResourceVersioning.test.ts +0 -651
- package/tests/unit/resources/ResourceManager.test.ts +0 -740
- package/tests/unit/storage/MemoryStorageAdapter.test.ts +0 -93
- package/tests/unit/types/network.test.ts +0 -255
- package/tests/unit/utils/EventIntegration.test.ts +0 -384
- package/tests/unit/utils/Logger.test.ts +0 -473
- package/tests/unit/utils/MetricsCollector.test.ts +0 -358
- package/tests/unit/utils/bitcoin-address.test.ts +0 -250
- package/tests/unit/utils/cbor.test.ts +0 -35
- package/tests/unit/utils/encoding.test.ts +0 -318
- package/tests/unit/utils/hash.test.ts +0 -12
- package/tests/unit/utils/retry.test.ts +0 -100
- package/tests/unit/utils/satoshi-validation.test.ts +0 -354
- package/tests/unit/utils/serialization.test.ts +0 -124
- package/tests/unit/utils/telemetry.test.ts +0 -52
- package/tests/unit/utils/validation.test.ts +0 -141
- package/tests/unit/vc/CredentialManager.helpers.test.ts +0 -527
- package/tests/unit/vc/CredentialManager.test.ts +0 -487
- package/tests/unit/vc/Issuer.test.ts +0 -107
- package/tests/unit/vc/Verifier.test.ts +0 -525
- package/tests/unit/vc/bbs.test.ts +0 -282
- package/tests/unit/vc/cryptosuites/eddsa.test.ts +0 -398
- package/tests/unit/vc/documentLoader.test.ts +0 -121
- package/tests/unit/vc/proofs/data-integrity.test.ts +0 -24
- package/tsconfig.json +0 -31
- package/tsconfig.test.json +0 -15
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import * as bitcoin from 'bitcoinjs-lib';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Bitcoin network types supported by the validation
|
|
5
|
-
*/
|
|
6
|
-
export type BitcoinNetwork = 'mainnet' | 'regtest' | 'signet';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Maps our network names to bitcoinjs-lib network configurations
|
|
10
|
-
*/
|
|
11
|
-
const getNetwork = (network: BitcoinNetwork): bitcoin.Network => {
|
|
12
|
-
switch (network) {
|
|
13
|
-
case 'mainnet':
|
|
14
|
-
return bitcoin.networks.bitcoin;
|
|
15
|
-
case 'regtest':
|
|
16
|
-
// Regtest uses testnet parameters but with bcrt prefix
|
|
17
|
-
// However, since many regtest addresses in tests use testnet format,
|
|
18
|
-
// we accept both testnet and regtest addresses for regtest network
|
|
19
|
-
return bitcoin.networks.regtest;
|
|
20
|
-
case 'signet':
|
|
21
|
-
// Signet uses the same bech32 prefix as testnet (tb1)
|
|
22
|
-
return bitcoin.networks.testnet;
|
|
23
|
-
default:
|
|
24
|
-
throw new Error(`Unsupported network: ${network}`);
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Validates a Bitcoin address format and checksum for the given network.
|
|
30
|
-
*
|
|
31
|
-
* This function uses bitcoinjs-lib's address.toOutputScript() which performs:
|
|
32
|
-
* - Format validation (bech32, base58check)
|
|
33
|
-
* - Checksum verification
|
|
34
|
-
* - Network prefix validation
|
|
35
|
-
*
|
|
36
|
-
* @param address - The Bitcoin address to validate
|
|
37
|
-
* @param network - The network to validate against ('mainnet', 'regtest', 'signet')
|
|
38
|
-
* @returns true if the address is valid for the network
|
|
39
|
-
* @throws Error with descriptive message if validation fails
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* ```typescript
|
|
43
|
-
* // Valid mainnet address
|
|
44
|
-
* validateBitcoinAddress('bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', 'mainnet'); // true
|
|
45
|
-
*
|
|
46
|
-
* // Invalid checksum
|
|
47
|
-
* validateBitcoinAddress('bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdd', 'mainnet'); // throws
|
|
48
|
-
*
|
|
49
|
-
* // Wrong network
|
|
50
|
-
* validateBitcoinAddress('bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq', 'testnet'); // throws
|
|
51
|
-
* ```
|
|
52
|
-
*/
|
|
53
|
-
export function validateBitcoinAddress(address: string, network: BitcoinNetwork): boolean {
|
|
54
|
-
// Input validation
|
|
55
|
-
if (!address || typeof address !== 'string') {
|
|
56
|
-
throw new Error('Address must be a non-empty string');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const trimmedAddress = address.trim();
|
|
60
|
-
|
|
61
|
-
if (trimmedAddress.length === 0) {
|
|
62
|
-
throw new Error('Address cannot be empty');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Check for mock/test addresses that should not be allowed in production
|
|
66
|
-
if (/^(mock-|test-)/i.test(trimmedAddress)) {
|
|
67
|
-
throw new Error('Mock or test addresses are not valid Bitcoin addresses');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Validate address length (Bitcoin addresses are typically 26-90 characters)
|
|
71
|
-
if (trimmedAddress.length < 26 || trimmedAddress.length > 90) {
|
|
72
|
-
throw new Error(`Invalid address length: ${trimmedAddress.length} characters (expected 26-90)`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
// Get the appropriate network configuration
|
|
77
|
-
const networkConfig = getNetwork(network);
|
|
78
|
-
|
|
79
|
-
// Use bitcoinjs-lib to validate the address format and checksum
|
|
80
|
-
// This will throw if the address is invalid
|
|
81
|
-
bitcoin.address.toOutputScript(trimmedAddress, networkConfig);
|
|
82
|
-
|
|
83
|
-
return true;
|
|
84
|
-
} catch (error) {
|
|
85
|
-
// For regtest, also try testnet network as many tools use testnet addresses for regtest
|
|
86
|
-
if (network === 'regtest') {
|
|
87
|
-
try {
|
|
88
|
-
bitcoin.address.toOutputScript(trimmedAddress, bitcoin.networks.testnet);
|
|
89
|
-
return true;
|
|
90
|
-
} catch {
|
|
91
|
-
// Fall through to error handling below
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Parse the error to provide more specific feedback
|
|
96
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
97
|
-
|
|
98
|
-
// Check for common error patterns and provide helpful messages
|
|
99
|
-
if (errorMessage.includes('Invalid checksum') || errorMessage.includes('checksum')) {
|
|
100
|
-
throw new Error(`Invalid Bitcoin address checksum for address: ${trimmedAddress}`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (errorMessage.includes('Invalid prefix') || errorMessage.includes('prefix')) {
|
|
104
|
-
throw new Error(`Invalid address prefix for ${network} network: ${trimmedAddress}`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (errorMessage.includes('too short') || errorMessage.includes('too long')) {
|
|
108
|
-
throw new Error(`Invalid address length for ${network}: ${trimmedAddress}`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Generic invalid address error
|
|
112
|
-
throw new Error(`Invalid Bitcoin address for ${network} network: ${trimmedAddress} (${errorMessage})`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Validates a Bitcoin address and returns a boolean instead of throwing
|
|
118
|
-
*
|
|
119
|
-
* @param address - The Bitcoin address to validate
|
|
120
|
-
* @param network - The network to validate against
|
|
121
|
-
* @returns true if valid, false otherwise
|
|
122
|
-
*/
|
|
123
|
-
export function isValidBitcoinAddress(address: string, network: BitcoinNetwork): boolean {
|
|
124
|
-
try {
|
|
125
|
-
validateBitcoinAddress(address, network);
|
|
126
|
-
return true;
|
|
127
|
-
} catch {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
}
|
package/src/utils/cbor.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import * as cbor from 'cbor-js';
|
|
2
|
-
|
|
3
|
-
export function encode(input: unknown): Uint8Array {
|
|
4
|
-
const encoded: any = (cbor as any).encode(input);
|
|
5
|
-
return new Uint8Array(encoded);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function decode<T = unknown>(bytes: Uint8Array | ArrayBuffer | Buffer): T {
|
|
9
|
-
const view = new Uint8Array(bytes as any);
|
|
10
|
-
return (cbor as any).decode(view.buffer) as T;
|
|
11
|
-
}
|
|
12
|
-
|
package/src/utils/encoding.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import b58 from 'b58';
|
|
2
|
-
|
|
3
|
-
export function encodeBase64UrlMultibase(bytes: Uint8Array): string {
|
|
4
|
-
return 'z' + Buffer.from(bytes).toString('base64url');
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function decodeBase64UrlMultibase(s: string): Uint8Array {
|
|
8
|
-
if (!s || s[0] !== 'z') {
|
|
9
|
-
throw new Error('Invalid Multibase encoding');
|
|
10
|
-
}
|
|
11
|
-
return Buffer.from(s.slice(1), 'base64url');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function hexToBytes(hex: string): Uint8Array {
|
|
15
|
-
const clean = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
16
|
-
if (clean.length % 2 !== 0) {
|
|
17
|
-
throw new Error('Invalid hex string length');
|
|
18
|
-
}
|
|
19
|
-
const out = new Uint8Array(clean.length / 2);
|
|
20
|
-
for (let i = 0; i < clean.length; i += 2) {
|
|
21
|
-
const byteStr = clean.substring(i, i + 2);
|
|
22
|
-
const value = parseInt(byteStr, 16);
|
|
23
|
-
if (Number.isNaN(value)) {
|
|
24
|
-
throw new Error('Invalid hex string');
|
|
25
|
-
}
|
|
26
|
-
out[i / 2] = value;
|
|
27
|
-
}
|
|
28
|
-
return out;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// multibase base58-btc header
|
|
32
|
-
export const MULTIBASE_BASE58BTC_HEADER = 'z';
|
|
33
|
-
// multibase base64url header
|
|
34
|
-
export const MULTIBASE_BASE64URL_HEADER = 'u';
|
|
35
|
-
// multicodec ed25519-pub header as varint
|
|
36
|
-
export const MULTICODEC_ED25519_PUB_HEADER = new Uint8Array([0xed, 0x01]);
|
|
37
|
-
// multicodec ed25519-priv header as varint
|
|
38
|
-
export const MULTICODEC_ED25519_PRIV_HEADER = new Uint8Array([0x80, 0x26]);
|
|
39
|
-
// multicodec x25519-pub header as varint
|
|
40
|
-
export const MULTICODEC_X25519_PUB_HEADER = new Uint8Array([0xec, 0x01]);
|
|
41
|
-
// multicodec x25519-priv header as varint
|
|
42
|
-
export const MULTICODEC_X25519_PRIV_HEADER = new Uint8Array([0x82, 0x26]);
|
|
43
|
-
// multicode secp256k1-pub header as varint
|
|
44
|
-
export const MULTICODEC_SECP256K1_PUB_HEADER = new Uint8Array([0xe7, 0x01]);
|
|
45
|
-
// multicode secp256k1-priv header as varint
|
|
46
|
-
export const MULTICODEC_SECP256K1_PRIV_HEADER = new Uint8Array([0x13, 0x01]);
|
|
47
|
-
// multicodec bls12381g2-pub header as varint
|
|
48
|
-
export const MULTICODEC_BLS12381_G2_PUB_HEADER = new Uint8Array([0xeb, 0x01]);
|
|
49
|
-
// multicodec bls12381g2-priv header as varint
|
|
50
|
-
export const MULTICODEC_BLS12381_G2_PRIV_HEADER = new Uint8Array([0x8a, 0x26]);
|
|
51
|
-
|
|
52
|
-
export const base64 = {
|
|
53
|
-
encode: (unencoded: any): string => {
|
|
54
|
-
return Buffer.from(unencoded || '').toString('base64');
|
|
55
|
-
},
|
|
56
|
-
decode: (encoded: any): Uint8Array => {
|
|
57
|
-
return new Uint8Array(Buffer.from(encoded || '', 'base64').buffer);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export const utf8 = {
|
|
62
|
-
encode: (unencoded: string): Uint8Array => {
|
|
63
|
-
return new TextEncoder().encode(unencoded)
|
|
64
|
-
},
|
|
65
|
-
decode: (encoded: Uint8Array): string => {
|
|
66
|
-
return new TextDecoder().decode(encoded);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const base64url = {
|
|
71
|
-
encode: (unencoded: any): string => {
|
|
72
|
-
const encoded = base64.encode(unencoded);
|
|
73
|
-
return encoded.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
|
74
|
-
},
|
|
75
|
-
decode: (encoded: any): Uint8Array => {
|
|
76
|
-
encoded = encoded.replace(/-/g, '+').replace(/_/g, '/');
|
|
77
|
-
while (encoded.length % 4) encoded += '=';
|
|
78
|
-
return base64.decode(encoded);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export const base58 = {
|
|
83
|
-
encode: (unencoded: Uint8Array): string => {
|
|
84
|
-
return b58.encode(unencoded);
|
|
85
|
-
},
|
|
86
|
-
decode: (encoded: string): Uint8Array => {
|
|
87
|
-
return b58.decode(encoded);
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export const multibase = {
|
|
92
|
-
encode: (val: Uint8Array, encoding: 'base58btc' | 'base64url'): string => {
|
|
93
|
-
if (encoding === 'base58btc') {
|
|
94
|
-
const baseEncoded = base58.encode(val);
|
|
95
|
-
return MULTIBASE_BASE58BTC_HEADER + baseEncoded;
|
|
96
|
-
} else if (encoding === 'base64url') {
|
|
97
|
-
return MULTIBASE_BASE64URL_HEADER + base64url.encode(val);
|
|
98
|
-
}
|
|
99
|
-
throw new Error('Invalid multibase encoding.');
|
|
100
|
-
},
|
|
101
|
-
decode: (val: string): Uint8Array => {
|
|
102
|
-
if (val.startsWith(MULTIBASE_BASE58BTC_HEADER)) {
|
|
103
|
-
return base58.decode(val.substring(1));
|
|
104
|
-
} else if (val.startsWith(MULTIBASE_BASE64URL_HEADER)) {
|
|
105
|
-
return base64url.decode(val.substring(1));
|
|
106
|
-
}
|
|
107
|
-
throw new Error('Multibase value does not have expected header.');
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
export const multikey = {
|
|
112
|
-
encode: (header: Uint8Array, val: Uint8Array): string => {
|
|
113
|
-
const mcBytes = new Uint8Array(header.length + val.length);
|
|
114
|
-
mcBytes.set(header);
|
|
115
|
-
mcBytes.set(val, header.length);
|
|
116
|
-
return multibase.encode(mcBytes, 'base58btc');
|
|
117
|
-
},
|
|
118
|
-
decode: (header: Uint8Array, val: string): Uint8Array => {
|
|
119
|
-
const mcValue = multibase.decode(val);
|
|
120
|
-
for (let i = 0; i < header.length; i++) {
|
|
121
|
-
if (mcValue[i] !== header[i]) {
|
|
122
|
-
throw new Error('Multikey value does not have expected header.');
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return mcValue.slice(header.length);
|
|
126
|
-
}
|
|
127
|
-
}
|
package/src/utils/hash.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export async function sha256Bytes(input: string | Uint8Array): Promise<Uint8Array> {
|
|
2
|
-
const data = typeof input === 'string' ? new TextEncoder().encode(input) : input;
|
|
3
|
-
const digest = await (globalThis.crypto as any).subtle.digest('SHA-256', data);
|
|
4
|
-
return new Uint8Array(digest);
|
|
5
|
-
}
|
|
6
|
-
|
package/src/utils/retry.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
export interface RetryOptions {
|
|
2
|
-
maxRetries?: number;
|
|
3
|
-
baseDelayMs?: number;
|
|
4
|
-
maxDelayMs?: number;
|
|
5
|
-
backoffFactor?: number;
|
|
6
|
-
jitterFactor?: number; // 0..1
|
|
7
|
-
isRetriable?: (error: unknown) => boolean;
|
|
8
|
-
onRetry?: (attempt: number, delayMs: number, error: unknown) => void;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const DEFAULTS: Required<RetryOptions> = {
|
|
12
|
-
maxRetries: 3,
|
|
13
|
-
baseDelayMs: 300,
|
|
14
|
-
maxDelayMs: 10_000,
|
|
15
|
-
backoffFactor: 2,
|
|
16
|
-
jitterFactor: 0.1,
|
|
17
|
-
isRetriable: () => true,
|
|
18
|
-
onRetry: () => {}
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function sleep(ms: number): Promise<void> {
|
|
22
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function computeDelay(attempt: number, opts: Required<RetryOptions>): number {
|
|
26
|
-
const exp = opts.baseDelayMs * Math.pow(opts.backoffFactor, attempt);
|
|
27
|
-
const withJitter = exp + ((Math.random() * 2 - 1) * opts.jitterFactor * exp);
|
|
28
|
-
return Math.min(Math.max(0, Math.floor(withJitter)), opts.maxDelayMs);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export async function withRetry<T>(fn: () => Promise<T>, options: RetryOptions = {}): Promise<T> {
|
|
32
|
-
const opts: Required<RetryOptions> = { ...DEFAULTS, ...options } as any;
|
|
33
|
-
let lastError: unknown;
|
|
34
|
-
for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {
|
|
35
|
-
try {
|
|
36
|
-
return await fn();
|
|
37
|
-
} catch (err) {
|
|
38
|
-
lastError = err;
|
|
39
|
-
if (attempt >= opts.maxRetries || !opts.isRetriable(err)) break;
|
|
40
|
-
const delay = computeDelay(attempt, opts);
|
|
41
|
-
opts.onRetry(attempt + 1, delay, err);
|
|
42
|
-
await sleep(delay);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
throw lastError;
|
|
46
|
-
}
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
import { StructuredError } from './telemetry';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Maximum number of satoshis in Bitcoin's total supply (21 million BTC)
|
|
5
|
-
* 21,000,000 BTC * 100,000,000 satoshis/BTC = 2,100,000,000,000,000 satoshis
|
|
6
|
-
*/
|
|
7
|
-
export const MAX_SATOSHI_SUPPLY = 2_100_000_000_000_000;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Validation result interface for satoshi number validation
|
|
11
|
-
*/
|
|
12
|
-
export interface SatoshiValidationResult {
|
|
13
|
-
valid: boolean;
|
|
14
|
-
error?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Validates a satoshi number for use in Bitcoin ordinals and did:btco DIDs.
|
|
19
|
-
*
|
|
20
|
-
* @param satoshi - The satoshi identifier to validate (string or number)
|
|
21
|
-
* @returns Validation result with descriptive error if invalid
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* const result = validateSatoshiNumber('123456');
|
|
26
|
-
* if (!result.valid) {
|
|
27
|
-
* throw new Error(result.error);
|
|
28
|
-
* }
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export function validateSatoshiNumber(satoshi: string | number): SatoshiValidationResult {
|
|
32
|
-
// Check for null, undefined, or empty string
|
|
33
|
-
if (satoshi === null || satoshi === undefined || satoshi === '') {
|
|
34
|
-
return {
|
|
35
|
-
valid: false,
|
|
36
|
-
error: 'Satoshi identifier cannot be null, undefined, or empty string'
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Convert to string for validation
|
|
41
|
-
const satoshiStr = String(satoshi).trim();
|
|
42
|
-
|
|
43
|
-
// Check for empty string after trimming
|
|
44
|
-
if (satoshiStr === '') {
|
|
45
|
-
return {
|
|
46
|
-
valid: false,
|
|
47
|
-
error: 'Satoshi identifier cannot be empty or whitespace-only string'
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Check for numeric format (must be all digits, no decimals, no scientific notation)
|
|
52
|
-
if (!/^[0-9]+$/.test(satoshiStr)) {
|
|
53
|
-
return {
|
|
54
|
-
valid: false,
|
|
55
|
-
error: 'Satoshi identifier must be a non-negative integer (no decimals, no scientific notation, no non-numeric characters)'
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Convert to number for range validation
|
|
60
|
-
const satoshiNum = Number(satoshiStr);
|
|
61
|
-
|
|
62
|
-
// Check for valid number conversion
|
|
63
|
-
if (!Number.isFinite(satoshiNum)) {
|
|
64
|
-
return {
|
|
65
|
-
valid: false,
|
|
66
|
-
error: 'Satoshi identifier must be a finite number'
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Check for decimals (would be truncated by Number())
|
|
71
|
-
if (satoshiNum !== Math.floor(satoshiNum)) {
|
|
72
|
-
return {
|
|
73
|
-
valid: false,
|
|
74
|
-
error: 'Satoshi identifier cannot contain decimal places'
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Check for negative numbers
|
|
79
|
-
if (satoshiNum < 0) {
|
|
80
|
-
return {
|
|
81
|
-
valid: false,
|
|
82
|
-
error: 'Satoshi identifier must be non-negative (>= 0)'
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Check for maximum supply range
|
|
87
|
-
if (satoshiNum > MAX_SATOSHI_SUPPLY) {
|
|
88
|
-
return {
|
|
89
|
-
valid: false,
|
|
90
|
-
error: `Satoshi identifier must be within Bitcoin's total supply (0 to ${MAX_SATOSHI_SUPPLY.toLocaleString()})`
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return { valid: true };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Parses a satoshi identifier from various formats and validates it.
|
|
99
|
-
*
|
|
100
|
-
* Supported formats:
|
|
101
|
-
* - Plain satoshi number: "123456"
|
|
102
|
-
* - did:btco DID: "did:btco:123456", "did:btco:test:123456", "did:btco:sig:123456"
|
|
103
|
-
* - Ordinal notation: "123456" (same as plain number, for future extensions)
|
|
104
|
-
*
|
|
105
|
-
* @param identifier - The identifier to parse
|
|
106
|
-
* @returns The extracted satoshi number
|
|
107
|
-
* @throws {StructuredError} If the identifier format is invalid or satoshi is invalid
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* ```typescript
|
|
111
|
-
* const satoshi = parseSatoshiIdentifier('did:btco:123456');
|
|
112
|
-
* console.log(satoshi); // 123456
|
|
113
|
-
* ```
|
|
114
|
-
*/
|
|
115
|
-
export function parseSatoshiIdentifier(identifier: string): number {
|
|
116
|
-
if (!identifier || typeof identifier !== 'string') {
|
|
117
|
-
throw new StructuredError(
|
|
118
|
-
'INVALID_SATOSHI_IDENTIFIER',
|
|
119
|
-
'Satoshi identifier must be a non-empty string'
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const trimmed = identifier.trim();
|
|
124
|
-
|
|
125
|
-
if (trimmed === '') {
|
|
126
|
-
throw new StructuredError(
|
|
127
|
-
'INVALID_SATOSHI_IDENTIFIER',
|
|
128
|
-
'Satoshi identifier cannot be empty or whitespace-only'
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
let satoshiStr: string;
|
|
133
|
-
|
|
134
|
-
// Check if it's a did:btco DID
|
|
135
|
-
if (trimmed.startsWith('did:btco:')) {
|
|
136
|
-
const parts = trimmed.split(':');
|
|
137
|
-
|
|
138
|
-
// Handle different network prefixes:
|
|
139
|
-
// did:btco:123456 (mainnet)
|
|
140
|
-
// did:btco:test:123456 (testnet)
|
|
141
|
-
// did:btco:sig:123456 (signet)
|
|
142
|
-
if (parts.length === 3) {
|
|
143
|
-
// Mainnet format: did:btco:satoshi
|
|
144
|
-
satoshiStr = parts[2];
|
|
145
|
-
} else if (parts.length === 4) {
|
|
146
|
-
// Network-specific format: did:btco:network:satoshi
|
|
147
|
-
const network = parts[2];
|
|
148
|
-
if (network !== 'test' && network !== 'sig') {
|
|
149
|
-
throw new StructuredError(
|
|
150
|
-
'INVALID_SATOSHI_IDENTIFIER',
|
|
151
|
-
`Invalid did:btco DID format: unsupported network "${network}"`
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
satoshiStr = parts[3];
|
|
155
|
-
} else {
|
|
156
|
-
throw new StructuredError(
|
|
157
|
-
'INVALID_SATOSHI_IDENTIFIER',
|
|
158
|
-
'Invalid did:btco DID format: expected "did:btco:satoshi" or "did:btco:network:satoshi"'
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
} else {
|
|
162
|
-
// Assume it's a plain satoshi number
|
|
163
|
-
satoshiStr = trimmed;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Validate the extracted satoshi
|
|
167
|
-
const validation = validateSatoshiNumber(satoshiStr);
|
|
168
|
-
if (!validation.valid) {
|
|
169
|
-
throw new StructuredError(
|
|
170
|
-
'INVALID_SATOSHI_IDENTIFIER',
|
|
171
|
-
validation.error || 'Invalid satoshi identifier'
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return Number(satoshiStr);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Validates a satoshi number and throws an error if invalid.
|
|
180
|
-
* Convenience wrapper around validateSatoshiNumber for code that expects exceptions.
|
|
181
|
-
*
|
|
182
|
-
* @param satoshi - The satoshi identifier to validate
|
|
183
|
-
* @throws {StructuredError} If the satoshi is invalid
|
|
184
|
-
*
|
|
185
|
-
* @example
|
|
186
|
-
* ```typescript
|
|
187
|
-
* assertValidSatoshi('123456'); // OK
|
|
188
|
-
* assertValidSatoshi(''); // throws StructuredError
|
|
189
|
-
* ```
|
|
190
|
-
*/
|
|
191
|
-
export function assertValidSatoshi(satoshi: string | number): void {
|
|
192
|
-
const result = validateSatoshiNumber(satoshi);
|
|
193
|
-
if (!result.valid) {
|
|
194
|
-
throw new StructuredError('INVALID_SATOSHI', result.error || 'Invalid satoshi identifier');
|
|
195
|
-
}
|
|
196
|
-
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import jsonld from 'jsonld';
|
|
2
|
-
import { DIDDocument, VerifiableCredential } from '../types';
|
|
3
|
-
|
|
4
|
-
type DocumentLoader = (url: string) => Promise<{
|
|
5
|
-
documentUrl: string;
|
|
6
|
-
document: any;
|
|
7
|
-
contextUrl: string | null;
|
|
8
|
-
}>;
|
|
9
|
-
|
|
10
|
-
// Import context documents from src/contexts
|
|
11
|
-
import credentialsV1Context from '../contexts/credentials-v1.json';
|
|
12
|
-
import credentialsV2Context from '../contexts/credentials-v2.json';
|
|
13
|
-
import dataIntegrityV2Context from '../contexts/data-integrity-v2.json';
|
|
14
|
-
import didsContext from '../contexts/dids.json';
|
|
15
|
-
import ed255192020Context from '../contexts/ed255192020.json';
|
|
16
|
-
import ordinalsContext from '../contexts/ordinals-plus.json';
|
|
17
|
-
import originalsContext from '../contexts/originals.json';
|
|
18
|
-
|
|
19
|
-
// Full context documents for proper canonicalization
|
|
20
|
-
const PRELOADED_CONTEXTS: Record<string, any> = {
|
|
21
|
-
// W3C and standard contexts
|
|
22
|
-
'https://www.w3.org/2018/credentials/v1': credentialsV1Context,
|
|
23
|
-
'https://www.w3.org/ns/credentials/v2': credentialsV2Context,
|
|
24
|
-
'https://w3id.org/security/data-integrity/v2': dataIntegrityV2Context,
|
|
25
|
-
'https://www.w3.org/ns/did/v1': didsContext,
|
|
26
|
-
'https://w3id.org/security/suites/ed25519-2020/v1': ed255192020Context,
|
|
27
|
-
|
|
28
|
-
// Custom contexts
|
|
29
|
-
'https://ordinals.plus/vocab/v1': ordinalsContext,
|
|
30
|
-
|
|
31
|
-
// Originals network contexts (all three networks use the same context document)
|
|
32
|
-
'https://originals.build/context': originalsContext, // Legacy
|
|
33
|
-
'https://pichu.originals.build/context': originalsContext, // Production
|
|
34
|
-
'https://cleffa.originals.build/context': originalsContext, // Staging
|
|
35
|
-
'https://magby.originals.build/context': originalsContext, // Development
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const defaultDocumentLoader: DocumentLoader = async (url: string) => {
|
|
40
|
-
const preloaded = PRELOADED_CONTEXTS[url];
|
|
41
|
-
if (preloaded) {
|
|
42
|
-
return { documentUrl: url, document: preloaded, contextUrl: null };
|
|
43
|
-
}
|
|
44
|
-
throw new Error(`Document not found in PRELOADED_CONTEXTS: ${url}`);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export function serializeDIDDocument(didDoc: DIDDocument): string {
|
|
48
|
-
// Serialize to JSON-LD with proper context
|
|
49
|
-
return JSON.stringify(didDoc, null, 2);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function deserializeDIDDocument(data: string): DIDDocument {
|
|
53
|
-
// Parse from JSON-LD
|
|
54
|
-
try {
|
|
55
|
-
const parsed = JSON.parse(data);
|
|
56
|
-
return parsed as DIDDocument;
|
|
57
|
-
} catch (error) {
|
|
58
|
-
throw new Error('Invalid DID Document JSON');
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function serializeCredential(vc: VerifiableCredential): string {
|
|
63
|
-
// Serialize VC to JSON-LD
|
|
64
|
-
return JSON.stringify(vc, null, 2);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function deserializeCredential(data: string): VerifiableCredential {
|
|
68
|
-
// Parse VC from JSON-LD
|
|
69
|
-
try {
|
|
70
|
-
const parsed = JSON.parse(data);
|
|
71
|
-
return parsed as VerifiableCredential;
|
|
72
|
-
} catch (error) {
|
|
73
|
-
throw new Error('Invalid Verifiable Credential JSON');
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export async function canonicalizeDocument(
|
|
78
|
-
doc: any,
|
|
79
|
-
options: { documentLoader?: DocumentLoader } = {}
|
|
80
|
-
): Promise<string> {
|
|
81
|
-
try {
|
|
82
|
-
return await jsonld.canonize(doc, {
|
|
83
|
-
algorithm: 'URDNA2015',
|
|
84
|
-
format: 'application/n-quads',
|
|
85
|
-
documentLoader: options.documentLoader ?? defaultDocumentLoader,
|
|
86
|
-
useNative: false,
|
|
87
|
-
rdfDirection: 'i18n-datatype',
|
|
88
|
-
safe: false // Disable safe mode to allow custom contexts
|
|
89
|
-
} as any);
|
|
90
|
-
} catch (error: any) {
|
|
91
|
-
const message = error?.message ?? String(error);
|
|
92
|
-
throw new Error(`Failed to canonicalize document: ${message}`);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
package/src/utils/telemetry.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
export type TelemetryLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
2
|
-
|
|
3
|
-
export interface TelemetryEvent {
|
|
4
|
-
name: string;
|
|
5
|
-
level?: TelemetryLevel;
|
|
6
|
-
attributes?: Record<string, unknown>;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface TelemetryHooks {
|
|
10
|
-
onEvent?: (event: TelemetryEvent) => void;
|
|
11
|
-
onError?: (error: StructuredError) => void;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class StructuredError extends Error {
|
|
15
|
-
public readonly code: string;
|
|
16
|
-
public readonly details?: Record<string, unknown>;
|
|
17
|
-
constructor(code: string, message: string, details?: Record<string, unknown>) {
|
|
18
|
-
super(message);
|
|
19
|
-
this.name = 'StructuredError';
|
|
20
|
-
this.code = code;
|
|
21
|
-
this.details = details;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function emitTelemetry(hooks: TelemetryHooks | undefined, event: TelemetryEvent): void {
|
|
26
|
-
if (hooks && typeof hooks.onEvent === 'function') {
|
|
27
|
-
try {
|
|
28
|
-
hooks.onEvent({ level: 'info', ...event });
|
|
29
|
-
} catch (_) {}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function emitError(hooks: TelemetryHooks | undefined, error: StructuredError): void {
|
|
34
|
-
if (hooks && typeof hooks.onError === 'function') {
|
|
35
|
-
try {
|
|
36
|
-
hooks.onError(error);
|
|
37
|
-
} catch (_) {}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|