@did-btcr2/api 0.2.1 → 0.3.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 +1 -1
- package/dist/browser.js +149910 -127351
- package/dist/browser.mjs +149186 -126627
- package/dist/cjs/api.js +210 -150
- package/dist/cjs/api.js.map +1 -1
- package/dist/cjs/bitcoin.js +110 -0
- package/dist/cjs/bitcoin.js.map +1 -0
- package/dist/cjs/cas.js +90 -0
- package/dist/cjs/cas.js.map +1 -0
- package/dist/cjs/crypto.js +425 -0
- package/dist/cjs/crypto.js.map +1 -0
- package/dist/cjs/did.js +70 -0
- package/dist/cjs/did.js.map +1 -0
- package/dist/cjs/helpers.js +28 -0
- package/dist/cjs/helpers.js.map +1 -0
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/kms.js +73 -0
- package/dist/cjs/kms.js.map +1 -0
- package/dist/cjs/method.js +262 -0
- package/dist/cjs/method.js.map +1 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/api.js +210 -150
- package/dist/esm/api.js.map +1 -1
- package/dist/esm/bitcoin.js +110 -0
- package/dist/esm/bitcoin.js.map +1 -0
- package/dist/esm/cas.js +90 -0
- package/dist/esm/cas.js.map +1 -0
- package/dist/esm/crypto.js +425 -0
- package/dist/esm/crypto.js.map +1 -0
- package/dist/esm/did.js +70 -0
- package/dist/esm/did.js.map +1 -0
- package/dist/esm/helpers.js +28 -0
- package/dist/esm/helpers.js.map +1 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/kms.js +73 -0
- package/dist/esm/kms.js.map +1 -0
- package/dist/esm/method.js +262 -0
- package/dist/esm/method.js.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/types/api.d.ts +107 -97
- package/dist/types/api.d.ts.map +1 -1
- package/dist/types/bitcoin.d.ts +64 -0
- package/dist/types/bitcoin.d.ts.map +1 -0
- package/dist/types/cas.d.ts +70 -0
- package/dist/types/cas.d.ts.map +1 -0
- package/dist/types/crypto.d.ts +310 -0
- package/dist/types/crypto.d.ts.map +1 -0
- package/dist/types/did.d.ts +51 -0
- package/dist/types/did.d.ts.map +1 -0
- package/dist/types/helpers.d.ts +10 -0
- package/dist/types/helpers.d.ts.map +1 -0
- package/dist/types/index.d.ts +15 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/kms.d.ts +49 -0
- package/dist/types/kms.d.ts.map +1 -0
- package/dist/types/method.d.ts +117 -0
- package/dist/types/method.d.ts.map +1 -0
- package/dist/types/types.d.ts +128 -0
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +7 -6
- package/src/api.ts +246 -262
- package/src/bitcoin.ts +129 -0
- package/src/cas.ts +121 -0
- package/src/crypto.ts +525 -0
- package/src/did.ts +75 -0
- package/src/helpers.ts +35 -0
- package/src/index.ts +37 -1
- package/src/kms.ts +95 -0
- package/src/method.ts +331 -0
- package/src/types.ts +122 -0
package/dist/cjs/api.js
CHANGED
|
@@ -1,179 +1,239 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import { SchnorrKeyPair } from '@did-btcr2/keypair';
|
|
2
|
+
import { BitcoinApi } from './bitcoin.js';
|
|
3
|
+
import { CasApi } from './cas.js';
|
|
4
|
+
import { CryptoApi } from './crypto.js';
|
|
5
|
+
import { DidApi } from './did.js';
|
|
6
|
+
import { assertString, NOOP_LOGGER } from './helpers.js';
|
|
7
|
+
import { KeyManagerApi } from './kms.js';
|
|
8
|
+
import { DidMethodApi } from './method.js';
|
|
9
|
+
/**
|
|
10
|
+
* Main DidBtcr2Api facade — the primary entry point for the SDK.
|
|
11
|
+
*
|
|
12
|
+
* Exposes sub-facades for Bitcoin, DID Method, KeyPair, Crypto, and
|
|
13
|
+
* KeyManager operations. Created via the {@link createApi} factory.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export class DidBtcr2Api {
|
|
17
|
+
/** Cryptographic operations (keypair, multikey, cryptosuite, proof). */
|
|
18
|
+
crypto;
|
|
19
|
+
/** DID identifier operations (encode, decode, generate, parse). */
|
|
20
|
+
did;
|
|
21
|
+
/** Key management operations. */
|
|
22
|
+
kms;
|
|
23
|
+
#btcConfig;
|
|
24
|
+
#btc;
|
|
25
|
+
#casConfig;
|
|
26
|
+
#cas;
|
|
27
|
+
#btcr2;
|
|
28
|
+
#log;
|
|
29
|
+
#disposed = false;
|
|
30
|
+
constructor(config) {
|
|
31
|
+
this.#btcConfig = config?.btc;
|
|
32
|
+
this.#casConfig = config?.cas;
|
|
33
|
+
this.#log = config?.logger ?? NOOP_LOGGER;
|
|
34
|
+
this.kms = new KeyManagerApi(config?.kms);
|
|
35
|
+
this.did = new DidApi();
|
|
36
|
+
this.crypto = new CryptoApi();
|
|
19
37
|
}
|
|
20
|
-
}
|
|
21
|
-
export class MultikeyApi {
|
|
22
38
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
39
|
+
* Bitcoin API sub-facade (lazily initialized).
|
|
40
|
+
* Only available when `btc` config was provided to the constructor.
|
|
41
|
+
* @throws {Error} If the instance has been disposed or no Bitcoin config was provided.
|
|
25
42
|
*/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
43
|
+
get btc() {
|
|
44
|
+
this.#assertNotDisposed();
|
|
45
|
+
if (!this.#btc) {
|
|
46
|
+
if (!this.#btcConfig) {
|
|
47
|
+
throw new Error('Bitcoin not configured. Pass a btc config to createApi(), e.g.: '
|
|
48
|
+
+ 'createApi({ btc: { network: \'regtest\' } })');
|
|
49
|
+
}
|
|
50
|
+
this.#btc = new BitcoinApi(this.#btcConfig);
|
|
51
|
+
}
|
|
52
|
+
return this.#btc;
|
|
32
53
|
}
|
|
33
|
-
/**
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
/* =========================
|
|
50
|
-
* Sub-facade: Bitcoin
|
|
51
|
-
* ========================= */
|
|
52
|
-
export class BitcoinApi {
|
|
53
|
-
rest;
|
|
54
|
-
rpc;
|
|
55
|
-
defaultConfirmations;
|
|
56
|
-
constructor(cfg) {
|
|
57
|
-
const restCfg = {
|
|
58
|
-
host: cfg?.rest?.host ?? DEFAULT_REST_CONFIG.host,
|
|
59
|
-
...cfg?.rest
|
|
60
|
-
};
|
|
61
|
-
const rpcCfg = {
|
|
62
|
-
...DEFAULT_RPC_CONFIG,
|
|
63
|
-
...cfg?.rpc
|
|
64
|
-
};
|
|
65
|
-
this.rest = new BitcoinRestClient(restCfg);
|
|
66
|
-
this.rpc = new BitcoinCoreRpcClient(rpcCfg);
|
|
67
|
-
this.defaultConfirmations = cfg?.defaultConfirmations ?? DEFAULT_BLOCK_CONFIRMATIONS;
|
|
68
|
-
}
|
|
69
|
-
/** Fetch a transaction by txid via REST. */
|
|
70
|
-
async getTransaction(txid) {
|
|
71
|
-
return await this.rest.transaction.get(txid);
|
|
54
|
+
/**
|
|
55
|
+
* CAS API sub-facade (lazily initialized).
|
|
56
|
+
* Only available when `cas` config was provided to the constructor.
|
|
57
|
+
* @throws {Error} If the instance has been disposed or no CAS config was provided.
|
|
58
|
+
*/
|
|
59
|
+
get cas() {
|
|
60
|
+
this.#assertNotDisposed();
|
|
61
|
+
if (!this.#cas) {
|
|
62
|
+
if (!this.#casConfig) {
|
|
63
|
+
throw new Error('CAS not configured. Pass a cas config to createApi(), e.g.: '
|
|
64
|
+
+ 'createApi({ cas: { helia: await createHelia() } })');
|
|
65
|
+
}
|
|
66
|
+
this.#cas = new CasApi(this.#casConfig);
|
|
67
|
+
}
|
|
68
|
+
return this.#cas;
|
|
72
69
|
}
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
/**
|
|
71
|
+
* DID Method API sub-facade (lazily initialized with bitcoin + CAS wiring).
|
|
72
|
+
* @throws {Error} If the instance has been disposed.
|
|
73
|
+
*/
|
|
74
|
+
get btcr2() {
|
|
75
|
+
this.#assertNotDisposed();
|
|
76
|
+
if (!this.#btcr2) {
|
|
77
|
+
this.#btcr2 = new DidMethodApi(this.#btcConfig ? this.btc : undefined, this.#casConfig ? this.cas : undefined, this.#log);
|
|
78
|
+
}
|
|
79
|
+
return this.#btcr2;
|
|
76
80
|
}
|
|
77
|
-
/**
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Whether this API instance has been disposed.
|
|
83
|
+
*/
|
|
84
|
+
get disposed() {
|
|
85
|
+
return this.#disposed;
|
|
80
86
|
}
|
|
81
|
-
/**
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Create a DID using either deterministic (KEY) or external (EXTERNAL) mode.
|
|
89
|
+
* @param type The creation mode.
|
|
90
|
+
* @param genesisBytes Public key bytes (deterministic) or document bytes (external).
|
|
91
|
+
* @param options Creation options (idType is set for you).
|
|
92
|
+
* @returns The created DID identifier string.
|
|
93
|
+
*/
|
|
94
|
+
createDid(type, genesisBytes, options) {
|
|
95
|
+
this.#assertNotDisposed();
|
|
96
|
+
return type === 'deterministic'
|
|
97
|
+
? this.btcr2.createDeterministic(genesisBytes, options)
|
|
98
|
+
: this.btcr2.createExternal(genesisBytes, options);
|
|
84
99
|
}
|
|
85
|
-
}
|
|
86
|
-
/* =========================
|
|
87
|
-
* Sub-facade: KeyManager
|
|
88
|
-
* ========================= */
|
|
89
|
-
// export class KeyManagerApi {
|
|
90
|
-
// readonly impl: IMethodKeyManager;
|
|
91
|
-
// constructor(params?: ApiKeyManagerConfig) {
|
|
92
|
-
// this.impl = new MethodKeyManager(params);
|
|
93
|
-
// }
|
|
94
|
-
// setActive(keyUri: string) {
|
|
95
|
-
// this.impl.activeKeyUri = keyUri;
|
|
96
|
-
// }
|
|
97
|
-
// export(keyUri: string) {
|
|
98
|
-
// return this.impl.export(keyUri);
|
|
99
|
-
// }
|
|
100
|
-
// import(mk: SchnorrMultikey, opts?: { importKey?: boolean; active?: boolean }) {
|
|
101
|
-
// return this.impl.import(mk, opts);
|
|
102
|
-
// }
|
|
103
|
-
// sign(keyUri: string, hash: HashBytes): Promise<SignatureBytes> {
|
|
104
|
-
// return this.impl.sign(keyUri, hash);
|
|
105
|
-
// }
|
|
106
|
-
// }
|
|
107
|
-
/* =========================
|
|
108
|
-
* Sub-facade: DID / CRUD
|
|
109
|
-
* ========================= */
|
|
110
|
-
export class DidApi {
|
|
111
100
|
/**
|
|
112
|
-
*
|
|
101
|
+
* Generate a new DID, create the keypair, and import it into the KMS.
|
|
102
|
+
* @param options Optional settings.
|
|
103
|
+
* @param options.setActive Whether to set the imported key as active in the KMS (default `true`).
|
|
104
|
+
* @param options.network Network for the generated DID (default `'regtest'`).
|
|
105
|
+
* @returns The generated DID string and KMS key identifier.
|
|
113
106
|
*/
|
|
114
|
-
|
|
115
|
-
|
|
107
|
+
generateDid(options) {
|
|
108
|
+
this.#assertNotDisposed();
|
|
109
|
+
const { keyPair, did } = this.did.generate(options?.network);
|
|
110
|
+
const kp = SchnorrKeyPair.fromJSON(keyPair);
|
|
111
|
+
const keyId = this.kms.import(kp, { setActive: options?.setActive ?? true });
|
|
112
|
+
return { did, keyId };
|
|
116
113
|
}
|
|
117
114
|
/**
|
|
118
|
-
*
|
|
115
|
+
* Resolve a DID, automatically injecting the configured Bitcoin connection.
|
|
116
|
+
* @param did The DID to resolve.
|
|
117
|
+
* @param options Optional resolution options.
|
|
118
|
+
* @returns The resolution result.
|
|
119
119
|
*/
|
|
120
|
-
async
|
|
121
|
-
|
|
120
|
+
async resolveDid(did, options) {
|
|
121
|
+
this.#assertNotDisposed();
|
|
122
|
+
return await this.btcr2.resolve(did, options);
|
|
122
123
|
}
|
|
123
124
|
/**
|
|
124
|
-
* Resolve DID
|
|
125
|
+
* Resolve a DID and return a discriminated result instead of throwing.
|
|
126
|
+
* Useful when resolution failure is an expected outcome (e.g. checking
|
|
127
|
+
* whether a DID exists before creating it).
|
|
128
|
+
* @param did The DID to resolve.
|
|
129
|
+
* @param options Optional resolution options.
|
|
130
|
+
* @returns A {@link ResolutionResult} with `ok: true` on success or
|
|
131
|
+
* `ok: false` with error details on failure.
|
|
125
132
|
*/
|
|
126
|
-
async
|
|
127
|
-
|
|
133
|
+
async tryResolveDid(did, options) {
|
|
134
|
+
this.#assertNotDisposed();
|
|
135
|
+
assertString(did, 'did');
|
|
136
|
+
try {
|
|
137
|
+
const raw = await this.btcr2.resolve(did, options);
|
|
138
|
+
if (raw.didDocument) {
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
document: raw.didDocument,
|
|
142
|
+
metadata: raw.didDocumentMetadata,
|
|
143
|
+
raw,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
ok: false,
|
|
148
|
+
error: raw.didResolutionMetadata?.error ?? 'unknown',
|
|
149
|
+
errorMessage: raw.didResolutionMetadata?.errorMessage,
|
|
150
|
+
raw,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
return {
|
|
155
|
+
ok: false,
|
|
156
|
+
error: 'internalError',
|
|
157
|
+
errorMessage: err.message,
|
|
158
|
+
raw: {
|
|
159
|
+
didDocument: null,
|
|
160
|
+
didDocumentMetadata: {},
|
|
161
|
+
didResolutionMetadata: { error: 'internalError', errorMessage: err.message },
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
128
165
|
}
|
|
129
166
|
/**
|
|
130
|
-
* Update a DID
|
|
131
|
-
*
|
|
132
|
-
*
|
|
167
|
+
* Update a DID document: resolve the current state, apply patches, sign, and announce.
|
|
168
|
+
* Automatically injects the configured Bitcoin connection.
|
|
169
|
+
*
|
|
170
|
+
* If `sourceDocument` and `sourceVersionId` are both provided, resolution
|
|
171
|
+
* is skipped. Otherwise the DID is resolved first to obtain them.
|
|
172
|
+
* @param params The update parameters.
|
|
173
|
+
* @returns The signed update.
|
|
133
174
|
*/
|
|
134
|
-
async
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
175
|
+
async updateDid({ did, patches, verificationMethodId, beaconId, sourceDocument, sourceVersionId, }) {
|
|
176
|
+
this.#assertNotDisposed();
|
|
177
|
+
assertString(did, 'did');
|
|
178
|
+
let doc = sourceDocument;
|
|
179
|
+
let versionId = sourceVersionId;
|
|
180
|
+
if (!doc || versionId === undefined) {
|
|
181
|
+
const resolution = await this.resolveDid(did);
|
|
182
|
+
if (!resolution.didDocument) {
|
|
183
|
+
const meta = resolution.didResolutionMetadata;
|
|
184
|
+
const detail = meta?.error ? `: ${meta.error}` : '.';
|
|
185
|
+
const extra = meta?.errorMessage ? ` ${meta.errorMessage}` : '';
|
|
186
|
+
throw new Error(`Failed to resolve DID ${did} for update${detail}${extra}`, { cause: meta });
|
|
187
|
+
}
|
|
188
|
+
doc = doc ?? resolution.didDocument;
|
|
189
|
+
if (versionId === undefined) {
|
|
190
|
+
const rawVersionId = resolution.didDocumentMetadata?.versionId;
|
|
191
|
+
if (rawVersionId === undefined || rawVersionId === null) {
|
|
192
|
+
throw new Error(`Resolution of DID ${did} succeeded but returned no versionId in metadata. `
|
|
193
|
+
+ 'Provide sourceVersionId explicitly.');
|
|
194
|
+
}
|
|
195
|
+
const parsed = Number(rawVersionId);
|
|
196
|
+
if (!Number.isFinite(parsed)) {
|
|
197
|
+
throw new Error(`Resolution of DID ${did} returned a non-numeric versionId: ${String(rawVersionId)}.`);
|
|
198
|
+
}
|
|
199
|
+
versionId = parsed;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return await this.btcr2.update({
|
|
203
|
+
sourceDocument: doc,
|
|
139
204
|
patches,
|
|
140
|
-
sourceVersionId,
|
|
205
|
+
sourceVersionId: versionId,
|
|
141
206
|
verificationMethodId,
|
|
142
207
|
beaconId,
|
|
143
|
-
signingMaterial,
|
|
144
|
-
bitcoin,
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
/** Deactivate convenience: applies the standard `deactivated: true` patch. */
|
|
148
|
-
async deactivate() {
|
|
149
|
-
// This class is a stub in method right now; expose a narrow wrapper for future expansion.
|
|
150
|
-
// return DidBtcr2.deactivate({ identifier, patch }); // No-op holder; implement when core adds behavior.
|
|
151
|
-
throw new NotImplementedError('DidApi.deactivate is not implemented yet.', {
|
|
152
|
-
type: 'DID_API_METHOD_NOT_IMPLEMENTED',
|
|
153
|
-
name: 'NOT_IMPLEMENTED_ERROR'
|
|
154
208
|
});
|
|
155
209
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
this
|
|
168
|
-
this
|
|
169
|
-
this
|
|
170
|
-
|
|
171
|
-
|
|
210
|
+
/**
|
|
211
|
+
* Release internal references. After disposal, accessing `btc`, `btcr2`,
|
|
212
|
+
* or calling top-level methods will throw.
|
|
213
|
+
*
|
|
214
|
+
* Note: the underlying {@link BitcoinConnection} does not hold persistent
|
|
215
|
+
* connections, so this is primarily a guard against accidental reuse.
|
|
216
|
+
*/
|
|
217
|
+
dispose() {
|
|
218
|
+
this.#btc = undefined;
|
|
219
|
+
this.#cas = undefined;
|
|
220
|
+
this.#btcr2 = undefined;
|
|
221
|
+
this.#btcConfig = undefined;
|
|
222
|
+
this.#casConfig = undefined;
|
|
223
|
+
this.#disposed = true;
|
|
224
|
+
}
|
|
225
|
+
#assertNotDisposed() {
|
|
226
|
+
if (this.#disposed) {
|
|
227
|
+
throw new Error('This DidBtcr2Api instance has been disposed and can no longer be used.');
|
|
228
|
+
}
|
|
172
229
|
}
|
|
173
230
|
}
|
|
174
|
-
|
|
175
|
-
*
|
|
176
|
-
*
|
|
231
|
+
/**
|
|
232
|
+
* Create a new {@link DidBtcr2Api} instance with the given configuration.
|
|
233
|
+
* @param config Optional configuration for the API.
|
|
234
|
+
* @returns The created DidBtcr2Api instance.
|
|
235
|
+
* @public
|
|
236
|
+
*/
|
|
177
237
|
export function createApi(config) {
|
|
178
238
|
return new DidBtcr2Api(config);
|
|
179
239
|
}
|
package/dist/cjs/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { BitcoinConnection } from '@did-btcr2/bitcoin';
|
|
2
|
+
import { assertString } from './helpers.js';
|
|
3
|
+
/**
|
|
4
|
+
* Bitcoin network operations sub-facade.
|
|
5
|
+
* Always backed by a {@link BitcoinConnection} so it can be passed to
|
|
6
|
+
* resolve/update without extra configuration.
|
|
7
|
+
*
|
|
8
|
+
* Lazily initialized by {@link DidBtcr2Api} to avoid connection overhead
|
|
9
|
+
* when Bitcoin features are not used.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export class BitcoinApi {
|
|
13
|
+
/** The underlying BitcoinConnection used for all operations. */
|
|
14
|
+
connection;
|
|
15
|
+
/** REST client for the active network. */
|
|
16
|
+
get rest() {
|
|
17
|
+
return this.connection.rest;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* RPC client for the active network, or `undefined` if not configured.
|
|
21
|
+
* Use {@link requireRpc} when RPC is expected to be available.
|
|
22
|
+
*/
|
|
23
|
+
get rpc() {
|
|
24
|
+
return this.connection.rpc;
|
|
25
|
+
}
|
|
26
|
+
/** Whether an RPC client is available for this network. */
|
|
27
|
+
get hasRpc() {
|
|
28
|
+
return this.connection.rpc !== undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* RPC client for the active network.
|
|
32
|
+
* @throws {Error} If RPC was not configured for this network.
|
|
33
|
+
*/
|
|
34
|
+
requireRpc() {
|
|
35
|
+
const client = this.connection.rpc;
|
|
36
|
+
if (!client) {
|
|
37
|
+
throw new Error('RPC client not configured. Pass an rpc config when creating the BitcoinApi, e.g.: '
|
|
38
|
+
+ '{ network: \'regtest\', rpc: { host: \'http://localhost:18443\', username: \'u\', password: \'p\' } }');
|
|
39
|
+
}
|
|
40
|
+
return client;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a BitcoinApi for a specific network with optional endpoint overrides.
|
|
44
|
+
* Uses BitcoinConnection.forNetwork() — no env vars consulted.
|
|
45
|
+
* @param cfg The network and optional REST/RPC overrides.
|
|
46
|
+
*/
|
|
47
|
+
constructor(cfg) {
|
|
48
|
+
let executor = cfg.executor;
|
|
49
|
+
// Wrap the default fetch with a timeout if configured and no custom
|
|
50
|
+
// executor was provided.
|
|
51
|
+
if (!executor && cfg.timeoutMs !== undefined) {
|
|
52
|
+
const ms = cfg.timeoutMs;
|
|
53
|
+
executor = (req) => fetch(req.url, {
|
|
54
|
+
method: req.method,
|
|
55
|
+
headers: req.headers,
|
|
56
|
+
body: req.body,
|
|
57
|
+
signal: AbortSignal.timeout(ms),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
this.connection = BitcoinConnection.forNetwork(cfg.network, {
|
|
61
|
+
rest: cfg.rest,
|
|
62
|
+
rpc: cfg.rpc,
|
|
63
|
+
executor,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Fetch a transaction by txid via REST.
|
|
68
|
+
* @param txid The transaction ID (64-character hex string).
|
|
69
|
+
* @returns The fetched transaction.
|
|
70
|
+
*/
|
|
71
|
+
async getTransaction(txid) {
|
|
72
|
+
assertString(txid, 'txid');
|
|
73
|
+
return await this.rest.transaction.get(txid);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Broadcast a raw tx (hex) via REST.
|
|
77
|
+
* @param rawTxHex The raw transaction hex string.
|
|
78
|
+
*/
|
|
79
|
+
async send(rawTxHex) {
|
|
80
|
+
assertString(rawTxHex, 'rawTxHex');
|
|
81
|
+
return await this.rest.transaction.send(rawTxHex);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get UTXOs for an address via REST.
|
|
85
|
+
* @param address The Bitcoin address.
|
|
86
|
+
*/
|
|
87
|
+
async getUtxos(address) {
|
|
88
|
+
assertString(address, 'address');
|
|
89
|
+
return await this.rest.address.getUtxos(address);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get a block by hash or height via REST.
|
|
93
|
+
* @param params Block identifier — at least one of `hash` or `height` is required.
|
|
94
|
+
*/
|
|
95
|
+
async getBlock(params) {
|
|
96
|
+
if (!params.hash && params.height === undefined) {
|
|
97
|
+
throw new Error('getBlock requires at least one of hash or height.');
|
|
98
|
+
}
|
|
99
|
+
return await this.rest.block.get({ blockhash: params.hash, height: params.height });
|
|
100
|
+
}
|
|
101
|
+
/** Convert BTC to satoshis (integer-safe string-split arithmetic). */
|
|
102
|
+
static btcToSats(btc) {
|
|
103
|
+
return BitcoinConnection.btcToSats(btc);
|
|
104
|
+
}
|
|
105
|
+
/** Convert satoshis to BTC (integer-safe string-split arithmetic). */
|
|
106
|
+
static satsToBtc(sats) {
|
|
107
|
+
return BitcoinConnection.satsToBtc(sats);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=bitcoin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitcoin.js","sourceRoot":"","sources":["../../src/bitcoin.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/cas.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { canonicalize, decode as decodeHash } from '@did-btcr2/common';
|
|
2
|
+
import { CID } from 'multiformats/cid';
|
|
3
|
+
import * as raw from 'multiformats/codecs/raw';
|
|
4
|
+
import { create as createDigest } from 'multiformats/hashes/digest';
|
|
5
|
+
import { sha256 } from 'multiformats/hashes/sha2';
|
|
6
|
+
import { assertString } from './helpers.js';
|
|
7
|
+
/**
|
|
8
|
+
* Default {@link CasExecutor} backed by IPFS via Helia.
|
|
9
|
+
*
|
|
10
|
+
* Stores/retrieves data as raw blocks (`0x55` codec) with SHA-256 hashing.
|
|
11
|
+
* The CID is deterministically derived from the content hash, so lookups
|
|
12
|
+
* by base64url SHA-256 hash translate directly to CID lookups.
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export class IpfsCasExecutor {
|
|
16
|
+
#helia;
|
|
17
|
+
constructor(helia) {
|
|
18
|
+
this.#helia = helia;
|
|
19
|
+
}
|
|
20
|
+
async retrieve(hash) {
|
|
21
|
+
const hashBytes = decodeHash(hash, 'base64url');
|
|
22
|
+
const cid = CID.create(1, raw.code, createDigest(sha256.code, hashBytes));
|
|
23
|
+
try {
|
|
24
|
+
return await this.#helia.blockstore.get(cid);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async publish(data) {
|
|
31
|
+
const digest = await sha256.digest(data);
|
|
32
|
+
const cid = CID.createV1(raw.code, digest);
|
|
33
|
+
await this.#helia.blockstore.put(cid, data);
|
|
34
|
+
// Return base64url-encoded hash (no padding)
|
|
35
|
+
return btoa(String.fromCharCode(...digest.bytes.slice(2)))
|
|
36
|
+
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Content-Addressed Storage API sub-facade.
|
|
41
|
+
*
|
|
42
|
+
* Provides `publish` and `retrieve` for JSON objects using their
|
|
43
|
+
* JCS-canonicalized SHA-256 hash as the content address.
|
|
44
|
+
*
|
|
45
|
+
* By default uses IPFS (via Helia). Inject a custom {@link CasExecutor}
|
|
46
|
+
* to use a different CAS backend.
|
|
47
|
+
*
|
|
48
|
+
* Lazily initialized by {@link DidBtcr2Api} to avoid startup overhead
|
|
49
|
+
* when CAS features are not used.
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
export class CasApi {
|
|
53
|
+
#executor;
|
|
54
|
+
constructor(config) {
|
|
55
|
+
if (config.executor) {
|
|
56
|
+
this.#executor = config.executor;
|
|
57
|
+
}
|
|
58
|
+
else if (config.helia) {
|
|
59
|
+
this.#executor = new IpfsCasExecutor(config.helia);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
throw new Error('CAS configuration requires either an executor or a Helia instance. '
|
|
63
|
+
+ 'Example: createApi({ cas: { helia: await createHelia() } })');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Retrieve a JSON object from the CAS by its base64url SHA-256 hash.
|
|
68
|
+
* @param hash Base64url-encoded SHA-256 hash of the JCS-canonicalized object.
|
|
69
|
+
* @returns The parsed JSON object, or `null` if not found.
|
|
70
|
+
*/
|
|
71
|
+
async retrieve(hash) {
|
|
72
|
+
assertString(hash, 'hash');
|
|
73
|
+
const bytes = await this.#executor.retrieve(hash);
|
|
74
|
+
if (!bytes)
|
|
75
|
+
return null;
|
|
76
|
+
return JSON.parse(new TextDecoder().decode(bytes));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Publish a JSON object to the CAS.
|
|
80
|
+
* The object is JCS-canonicalized before storage; the returned hash
|
|
81
|
+
* matches what {@link canonicalHash} would produce.
|
|
82
|
+
* @param object The JSON object to publish.
|
|
83
|
+
* @returns The base64url-encoded SHA-256 hash (content address).
|
|
84
|
+
*/
|
|
85
|
+
async publish(object) {
|
|
86
|
+
const bytes = new TextEncoder().encode(canonicalize(object));
|
|
87
|
+
return await this.#executor.publish(bytes);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=cas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cas.js","sourceRoot":"","sources":["../../src/cas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEvE,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,GAAG,MAAM,yBAAyB,CAAC;AAC/C,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAgB5C;;;;;;;GAOG;AACH,MAAM,OAAO,eAAe;IACjB,MAAM,CAAQ;IAEvB,YAAY,KAAY;QACtB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAY;QACzB,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;QAC1E,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAgB;QAC5B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC3C,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC5C,6CAA6C;QAC7C,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;aACvD,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAChE,CAAC;CACF;AAaD;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,MAAM;IACR,SAAS,CAAc;IAEhC,YAAY,MAAiB;QAC3B,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACpB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC;QACnC,CAAC;aAAM,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACxB,IAAI,CAAC,SAAS,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CACb,qEAAqE;kBACnE,6DAA6D,CAChE,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,IAAY;QACzB,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC3B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAW,CAAC;IAC/D,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,MAA6B,CAAC,CAAC,CAAC;QACpF,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;CACF"}
|