@dwn-protocol/id-sdk 0.2.5 → 0.2.6

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.
Files changed (99) hide show
  1. package/package.json +2 -3
  2. package/src/agent/app-data-store.ts +0 -365
  3. package/src/agent/did-manager.ts +0 -393
  4. package/src/agent/dwn-manager.ts +0 -548
  5. package/src/agent/identity-manager.ts +0 -165
  6. package/src/agent/index.ts +0 -19
  7. package/src/agent/json-rpc.ts +0 -107
  8. package/src/agent/key-manager.ts +0 -302
  9. package/src/agent/kms-local.ts +0 -412
  10. package/src/agent/outbox.ts +0 -128
  11. package/src/agent/rpc-client.ts +0 -223
  12. package/src/agent/store-managed-did.ts +0 -295
  13. package/src/agent/store-managed-identity.ts +0 -243
  14. package/src/agent/store-managed-key.ts +0 -754
  15. package/src/agent/sync-manager.ts +0 -631
  16. package/src/agent/test-managed-agent.ts +0 -299
  17. package/src/agent/types/agent.ts +0 -145
  18. package/src/agent/types/managed-key.ts +0 -442
  19. package/src/agent/utils.ts +0 -190
  20. package/src/common/convert.ts +0 -424
  21. package/src/common/index.ts +0 -9
  22. package/src/common/multicodec.ts +0 -176
  23. package/src/common/object.ts +0 -43
  24. package/src/common/stores.ts +0 -125
  25. package/src/common/stream-node.ts +0 -381
  26. package/src/common/stream.ts +0 -406
  27. package/src/common/type-utils.ts +0 -117
  28. package/src/common/types.ts +0 -48
  29. package/src/credentials/credential-bbs.ts +0 -419
  30. package/src/credentials/credential.ts +0 -324
  31. package/src/credentials/index.ts +0 -5
  32. package/src/credentials/presentation.ts +0 -182
  33. package/src/credentials/status-list.ts +0 -365
  34. package/src/credentials/utils.ts +0 -58
  35. package/src/credentials/validators.ts +0 -52
  36. package/src/crypto/algorithms-api/aes/base.ts +0 -49
  37. package/src/crypto/algorithms-api/aes/ctr.ts +0 -51
  38. package/src/crypto/algorithms-api/aes/index.ts +0 -2
  39. package/src/crypto/algorithms-api/crypto-algorithm.ts +0 -127
  40. package/src/crypto/algorithms-api/crypto-key.ts +0 -56
  41. package/src/crypto/algorithms-api/ec/base.ts +0 -39
  42. package/src/crypto/algorithms-api/ec/ecdh.ts +0 -53
  43. package/src/crypto/algorithms-api/ec/ecdsa.ts +0 -37
  44. package/src/crypto/algorithms-api/ec/eddsa.ts +0 -30
  45. package/src/crypto/algorithms-api/ec/index.ts +0 -4
  46. package/src/crypto/algorithms-api/errors.ts +0 -29
  47. package/src/crypto/algorithms-api/index.ts +0 -6
  48. package/src/crypto/algorithms-api/pbkdf/index.ts +0 -1
  49. package/src/crypto/algorithms-api/pbkdf/pbkdf2.ts +0 -91
  50. package/src/crypto/crypto-algorithms/aes-ctr.ts +0 -70
  51. package/src/crypto/crypto-algorithms/bbs.ts +0 -110
  52. package/src/crypto/crypto-algorithms/ecdh.ts +0 -115
  53. package/src/crypto/crypto-algorithms/ecdsa.ts +0 -111
  54. package/src/crypto/crypto-algorithms/eddsa.ts +0 -110
  55. package/src/crypto/crypto-algorithms/index.ts +0 -6
  56. package/src/crypto/crypto-algorithms/pbkdf2.ts +0 -54
  57. package/src/crypto/crypto-primitives/aes-ctr.ts +0 -131
  58. package/src/crypto/crypto-primitives/aes-gcm.ts +0 -138
  59. package/src/crypto/crypto-primitives/bbs.ts +0 -183
  60. package/src/crypto/crypto-primitives/concat-kdf.ts +0 -207
  61. package/src/crypto/crypto-primitives/ed25519.ts +0 -201
  62. package/src/crypto/crypto-primitives/index.ts +0 -10
  63. package/src/crypto/crypto-primitives/pbkdf2.ts +0 -78
  64. package/src/crypto/crypto-primitives/secp256k1.ts +0 -322
  65. package/src/crypto/crypto-primitives/x25519.ts +0 -101
  66. package/src/crypto/crypto-primitives/xchacha20-poly1305.ts +0 -46
  67. package/src/crypto/crypto-primitives/xchacha20.ts +0 -34
  68. package/src/crypto/index.ts +0 -8
  69. package/src/crypto/jose.ts +0 -948
  70. package/src/crypto/types/crypto-key.ts +0 -4
  71. package/src/crypto/types/iddwn-crypto.ts +0 -119
  72. package/src/crypto/utils.ts +0 -200
  73. package/src/did-api.ts +0 -72
  74. package/src/dids/dht.ts +0 -412
  75. package/src/dids/did-dht.ts +0 -436
  76. package/src/dids/did-ion.ts +0 -613
  77. package/src/dids/did-key.ts +0 -791
  78. package/src/dids/did-resolver.ts +0 -107
  79. package/src/dids/index.ts +0 -9
  80. package/src/dids/resolver-cache-level.ts +0 -82
  81. package/src/dids/resolver-cache-noop.ts +0 -25
  82. package/src/dids/types.ts +0 -278
  83. package/src/dids/utils.ts +0 -129
  84. package/src/dwn-api.ts +0 -584
  85. package/src/iddwn.ts +0 -241
  86. package/src/identity-agent/index.ts +0 -270
  87. package/src/index.ts +0 -26
  88. package/src/interfaces/metadata.ts +0 -163
  89. package/src/interfaces/queue.ts +0 -108
  90. package/src/interfaces/services.ts +0 -122
  91. package/src/interfaces/transactions.ts +0 -220
  92. package/src/protocol.ts +0 -68
  93. package/src/proxy-agent/index.ts +0 -255
  94. package/src/record.ts +0 -521
  95. package/src/service-options.ts +0 -62
  96. package/src/typings/decentralized-identity__ion-pow-sdk.d.ts +0 -7
  97. package/src/user-agent/index.ts +0 -295
  98. package/src/utils.ts +0 -29
  99. package/src/vc-api.ts +0 -505
@@ -1,412 +0,0 @@
1
- import type { IDCrypto } from '../crypto/index.js';
2
- import type { RequireOnly } from '../common/index.js';
3
-
4
- import * as cryptoUtils from '../crypto/utils.js';
5
- import {
6
- EcdhAlgorithm,
7
- EcdsaAlgorithm,
8
- EdDsaAlgorithm,
9
- AesCtrAlgorithm,
10
- CryptoAlgorithm,
11
- } from '../crypto/index.js';
12
-
13
- import {
14
- ManagedKey,
15
- PortableKey,
16
- SignOptions,
17
- VerifyOptions,
18
- DecryptOptions,
19
- EncryptOptions,
20
- ManagedKeyPair,
21
- ManagedKeyStore,
22
- GenerateKeyType,
23
- PortableKeyPair,
24
- ImportKeyOptions,
25
- UpdateKeyOptions,
26
- DeriveBitsOptions,
27
- ManagedPrivateKey,
28
- GenerateKeyOptions,
29
- KeyManagementSystem,
30
- GenerateKeyOptionTypes,
31
- } from './types/managed-key.js';
32
-
33
- import { isManagedKey, isManagedKeyPair } from './utils.js';
34
- import { KeyStoreMemory, PrivateKeyStoreMemory } from './store-managed-key.js';
35
- import { IDManagedAgent } from './types/agent.js';
36
-
37
- export type AlgorithmImplementation = typeof CryptoAlgorithm & { new(): CryptoAlgorithm; };
38
-
39
- export type AlgorithmImplementations = {
40
- [algorithmName: string]: AlgorithmImplementation;
41
- };
42
-
43
- export type KmsOptions = {
44
- agent?: IDManagedAgent;
45
- cryptoAlgorithms?: AlgorithmImplementations;
46
- keyStore?: ManagedKeyStore<string, ManagedKey | ManagedKeyPair>;
47
- kmsName: string;
48
- privateKeyStore?: ManagedKeyStore<string, ManagedPrivateKey>;
49
- }
50
-
51
- // Map key operations to algorithm specs to implementations.
52
- export const defaultAlgorithms: AlgorithmImplementations = {
53
- 'AES-CTR' : AesCtrAlgorithm,
54
- ECDH : EcdhAlgorithm,
55
- ECDSA : EcdsaAlgorithm,
56
- EdDSA : EdDsaAlgorithm,
57
- };
58
-
59
- export class LocalKms implements KeyManagementSystem {
60
- /**
61
- * Holds the instance of a `IDManagedAgent` that represents the current
62
- * execution context for the `KeyManager`. This agent is utilized
63
- * to interact with other agent components. It's vital
64
- * to ensure this instance is set to correctly contextualize
65
- * operations within the broader agent framework.
66
- */
67
- private _agent?: IDManagedAgent;
68
- private _name: string;
69
- private _keyStore: ManagedKeyStore<string, ManagedKey | ManagedKeyPair>;
70
- private _privateKeyStore: ManagedKeyStore<string, ManagedPrivateKey>;
71
- private _supportedAlgorithms: Map<string, AlgorithmImplementation> = new Map();
72
-
73
- constructor(options: KmsOptions) {
74
- const { agent, kmsName, keyStore, privateKeyStore } = options;
75
- this._agent = agent;
76
- this._name = kmsName;
77
- this._keyStore = keyStore ?? new KeyStoreMemory();
78
- this._privateKeyStore = privateKeyStore ?? new PrivateKeyStoreMemory();
79
-
80
- // Merge the default and custom algorithms and register with the KMS.
81
- const cryptoAlgorithms = {...defaultAlgorithms, ...options.cryptoAlgorithms};
82
- this.registerSupportedAlgorithms(cryptoAlgorithms);
83
- }
84
-
85
- /**
86
- * Retrieves the `IDManagedAgent` execution context.
87
- * If the `agent` instance proprety is undefined, it will throw an error.
88
- *
89
- * @returns The `IDManagedAgent` instance that represents the current execution
90
- * context.
91
- *
92
- * @throws Will throw an error if the `agent` instance property is undefined.
93
- */
94
- get agent(): IDManagedAgent {
95
- if (this._agent === undefined) {
96
- throw new Error('KeyManager: Unable to determine agent execution context.');
97
- }
98
-
99
- return this._agent;
100
- }
101
-
102
- set agent(agent: IDManagedAgent) {
103
- this._agent = agent;
104
- }
105
-
106
- async decrypt(options: DecryptOptions): Promise<Uint8Array> {
107
- const { algorithm, data, keyRef } = options;
108
-
109
- // Retrieve the ManagedKey from the KMS key metadata store.
110
- const key = await this.getKey({ keyRef });
111
-
112
- if (isManagedKey(key)) {
113
- const privateManagedKey = await this._privateKeyStore.getKey({
114
- id : key.id,
115
- agent : this.agent
116
- });
117
-
118
- if (privateManagedKey !== undefined) {
119
- // Construct a CryptoKey object from the key metadata and private key material.
120
- const privateCryptoKey = this.toCryptoKey({ ...key, material: privateManagedKey.material });
121
-
122
- // Decrypt the data.
123
- const cryptoAlgorithm = this.getAlgorithm(algorithm);
124
- const plaintext = cryptoAlgorithm.decrypt({ algorithm, key: privateCryptoKey, data });
125
-
126
- return plaintext;
127
- }
128
- }
129
-
130
- throw new Error(`Operation failed: 'decrypt'. Key not found: ${keyRef}`);
131
- }
132
-
133
- async deriveBits(options: DeriveBitsOptions): Promise<Uint8Array> {
134
- let { algorithm, baseKeyRef, length } = options;
135
-
136
- // Retrieve the ManagedKeyPair from the KMS key metadata store.
137
- const ownKeyPair = await this.getKey({ keyRef: baseKeyRef });
138
-
139
- if (isManagedKeyPair(ownKeyPair)) {
140
- const privateManagedKey = await this._privateKeyStore.getKey({
141
- id : ownKeyPair.privateKey.id,
142
- agent : this.agent
143
- });
144
-
145
- if (privateManagedKey !== undefined) {
146
- // Construct a CryptoKey object from the key metadata and private key material.
147
- const privateCryptoKey = this.toCryptoKey({ ...ownKeyPair.privateKey, material: privateManagedKey.material });
148
-
149
- // Derive the shared secret.
150
- const cryptoAlgorithm = this.getAlgorithm(algorithm);
151
- const sharedSecret = cryptoAlgorithm.deriveBits({ algorithm, baseKey: privateCryptoKey, length: length ?? null });
152
-
153
- return sharedSecret;
154
- }
155
- }
156
-
157
- throw new Error(`Operation failed: 'deriveBits'. Key not found: ${baseKeyRef}`);
158
- }
159
-
160
- async encrypt(options: EncryptOptions): Promise<Uint8Array> {
161
- const { algorithm, data, keyRef } = options;
162
-
163
- // Retrieve the ManagedKey from the KMS key metadata store.
164
- const key = await this.getKey({ keyRef });
165
-
166
- if (isManagedKey(key)) {
167
- const privateManagedKey = await this._privateKeyStore.getKey({
168
- id : key.id,
169
- agent : this.agent
170
- });
171
-
172
- if (privateManagedKey !== undefined) {
173
- // Construct a CryptoKey object from the key metadata and private key material.
174
- const privateCryptoKey = this.toCryptoKey({ ...key, material: privateManagedKey.material });
175
-
176
- // Encrypt the data.
177
- const cryptoAlgorithm = this.getAlgorithm(algorithm);
178
- const ciphertext = cryptoAlgorithm.encrypt({ algorithm, key: privateCryptoKey, data });
179
-
180
- return ciphertext;
181
- }
182
- }
183
-
184
- throw new Error(`Operation failed: 'encrypt'. Key not found: ${keyRef}`);
185
- }
186
-
187
- async generateKey<T extends GenerateKeyOptionTypes>(options: GenerateKeyOptions<T>): Promise<GenerateKeyType<T>> {
188
- let { algorithm, alias, extractable, keyUsages, metadata } = options;
189
-
190
- // Get crypto algorithm implementation.
191
- const cryptoAlgorithm = this.getAlgorithm(algorithm);
192
-
193
- // Generate the key.
194
- extractable ??= true; // Default to extractable if not specified.
195
- const cryptoKey: any = await cryptoAlgorithm.generateKey({ algorithm, extractable, keyUsages });
196
-
197
- // Create a ManagedKey or ManagedKeyPair using the generated key and store the private key material.
198
- let managedKeyOrKeyPair: GenerateKeyType<T>;
199
- if (cryptoUtils.isCryptoKeyPair(cryptoKey)) {
200
- const privateKeyType = cryptoKey.privateKey.type as IDCrypto.PrivateKeyType;
201
- const id = await this._privateKeyStore.importKey({
202
- key : { material: cryptoKey.privateKey.material, type: privateKeyType},
203
- agent : this.agent
204
- });
205
- const managedKeyPair: ManagedKeyPair = {
206
- privateKey : this.toManagedKey({ ...cryptoKey.privateKey, id, alias, metadata }),
207
- publicKey : this.toManagedKey({ ...cryptoKey.publicKey, material: cryptoKey.publicKey.material, id, alias, metadata })
208
- };
209
- managedKeyOrKeyPair = managedKeyPair as GenerateKeyType<T>;
210
- } else {
211
- const keyType = cryptoKey.type as IDCrypto.PrivateKeyType;
212
- const id = await this._privateKeyStore.importKey({
213
- key : { material: cryptoKey.material, type: keyType },
214
- agent : this.agent
215
- });
216
- managedKeyOrKeyPair = this.toManagedKey({ ...cryptoKey, id, alias, metadata }) as GenerateKeyType<T>;
217
- }
218
-
219
- // Store the ManagedKey or ManagedKeyPair in the KMS key store.
220
- await this._keyStore.importKey({ key: managedKeyOrKeyPair, agent: this.agent });
221
-
222
- return managedKeyOrKeyPair;
223
- }
224
-
225
- async getKey(options: { keyRef: string }): Promise<ManagedKey | ManagedKeyPair | undefined> {
226
- const keyOrKeyPair = this._keyStore.getKey({ id: options.keyRef, agent: this.agent });
227
- return keyOrKeyPair;
228
- }
229
-
230
- async importKey(options: PortableKeyPair): Promise<ManagedKeyPair>;
231
- async importKey(options: PortableKey): Promise<ManagedKey>;
232
- async importKey(options: ImportKeyOptions): Promise<ManagedKey | ManagedKeyPair> {
233
-
234
- if ('privateKey' in options) {
235
- // Asymmetric key pair import.
236
- const { privateKey, publicKey } = options;
237
- if (privateKey.type === 'public' && publicKey.type === 'private')
238
- throw new Error(`Import failed due to private and public key mismatch`);
239
- if (!(privateKey.type === 'private' && publicKey.type === 'public'))
240
- throw new TypeError(`Out of range: '${privateKey.type}, ${publicKey.type}'. Must be 'private, public'`);
241
- const id = await this._privateKeyStore.importKey({
242
- key : { material: privateKey.material, type: privateKey.type },
243
- agent : this.agent
244
- });
245
- const managedKeyPair = {
246
- privateKey : this.toManagedKey({ ...privateKey, id, material: undefined }),
247
- publicKey : this.toManagedKey({ ...publicKey, material: publicKey.material, id })
248
- };
249
- await this._keyStore.importKey({ key: managedKeyPair, agent: this.agent });
250
- return managedKeyPair;
251
- }
252
-
253
- const keyType = options.type;
254
- switch (keyType) {
255
- case 'private': {
256
- // Asymmetric private key import.
257
- const material = options.material;
258
- const id = await this._privateKeyStore.importKey({
259
- key : { material, type: keyType },
260
- agent : this.agent
261
- });
262
- const privateManagedKey = this.toManagedKey({ ...options, material: undefined, id });
263
- await this._keyStore.importKey({ key: privateManagedKey, agent: this.agent });
264
- return privateManagedKey;
265
- }
266
-
267
- case 'public': {
268
- // Asymmetric public key import.
269
- const material = options.material;
270
- const publicManagedKey = this.toManagedKey({ ...options, material, id: '' });
271
- publicManagedKey.id = await this._keyStore.importKey({ key: publicManagedKey, agent: this.agent });
272
- return publicManagedKey;
273
- }
274
-
275
- case 'secret': {
276
- // Symmetric secret key import.
277
- const material = options.material;
278
- const id = await this._privateKeyStore.importKey({
279
- key : { material, type: keyType },
280
- agent : this.agent
281
- });
282
- const secretManagedKey = this.toManagedKey({ ...options, material: undefined, id });
283
- await this._keyStore.importKey({ key: secretManagedKey, agent: this.agent });
284
- return secretManagedKey;
285
- }
286
-
287
- default:
288
- throw new TypeError(`Out of range: '${keyType}'. Must be one of 'private, public, secret'`);
289
- }
290
- }
291
-
292
- async sign(options: SignOptions): Promise<Uint8Array> {
293
- const { algorithm, data, keyRef } = options;
294
-
295
- // Retrieve the ManagedKeyPair from the KMS key metadata store.
296
- const keyPair = await this.getKey({ keyRef });
297
-
298
- if (isManagedKeyPair(keyPair)) {
299
- const privateManagedKey = await this._privateKeyStore.getKey({
300
- id : keyPair.privateKey.id,
301
- agent : this.agent
302
- });
303
-
304
- if (privateManagedKey !== undefined) {
305
- // Construct a CryptoKey object from the key metadata and private key material.
306
- const privateCryptoKey = this.toCryptoKey({ ...keyPair.privateKey, material: privateManagedKey.material });
307
-
308
- // Sign the data.
309
- const cryptoAlgorithm = this.getAlgorithm(algorithm);
310
- const signature = cryptoAlgorithm.sign({ algorithm, key: privateCryptoKey, data });
311
-
312
- return signature;
313
- }
314
- }
315
-
316
- throw new Error(`Operation failed: 'sign'. Key not found: ${keyRef}`);
317
- }
318
-
319
- async updateKey(options: UpdateKeyOptions): Promise<boolean> {
320
- const { keyRef, alias, metadata } = options;
321
-
322
- const keyOrKeyPair = await this.getKey({ keyRef });
323
-
324
- if (!keyOrKeyPair) {
325
- throw new Error(`Key not found: '${keyRef}'`);
326
- }
327
-
328
- const keyId = (isManagedKeyPair(keyOrKeyPair))
329
- ? keyOrKeyPair.publicKey.id
330
- : keyOrKeyPair.id;
331
-
332
- // Update the KMS key metadata store.
333
- return this._keyStore.updateKey({ id: keyId, alias, metadata, agent: this.agent });
334
- }
335
-
336
- async verify(options: VerifyOptions): Promise<boolean> {
337
- const { algorithm, data, keyRef, signature } = options;
338
-
339
- // Retrieve the ManagedKeyPair from the KMS key metadata store.
340
- const keyPair = await this.getKey({ keyRef });
341
-
342
- if (isManagedKeyPair(keyPair)) {
343
- if (keyPair.publicKey.material === undefined) {
344
- throw new Error(`Required property missing: 'material'`);
345
- }
346
- // Construct a CryptoKey object from the key metadata and private key material.
347
- const publicCryptoKey = this.toCryptoKey({
348
- ...keyPair.publicKey,
349
- material: keyPair.publicKey.material
350
- });
351
-
352
- // Verify the signature and data.
353
- const cryptoAlgorithm = this.getAlgorithm(algorithm);
354
- const isValid = cryptoAlgorithm.verify({ algorithm, key: publicCryptoKey, signature, data });
355
-
356
- return isValid;
357
- }
358
-
359
- throw new Error(`Operation failed: 'verify'. Key not found: ${keyRef}`);
360
- }
361
-
362
- private getAlgorithm(algorithmIdentifier: IDCrypto.AlgorithmIdentifier): CryptoAlgorithm {
363
- cryptoUtils.checkRequiredProperty({ property: 'name', inObject: algorithmIdentifier });
364
- const algorithm = this._supportedAlgorithms.get(algorithmIdentifier.name.toUpperCase());
365
-
366
- if (algorithm === undefined) {
367
- throw new Error(`The algorithm '${algorithmIdentifier.name}' is not supported`);
368
- }
369
-
370
- return algorithm.create();
371
- }
372
-
373
- private registerSupportedAlgorithms(cryptoAlgorithms: AlgorithmImplementations): void {
374
- for (const [name, implementation] of Object.entries(cryptoAlgorithms)) {
375
- // Add the algorithm name and its implementation to the supported algorithms map,
376
- // upper-cased to allow for case-insensitive.
377
- this._supportedAlgorithms.set(name.toUpperCase(), implementation);
378
- }
379
- }
380
-
381
- private toCryptoKey(managedKey:
382
- RequireOnly<ManagedKey, 'algorithm' | 'extractable' | 'material' | 'type' | 'usages'>
383
- ): IDCrypto.CryptoKey {
384
-
385
- const cryptoKey: IDCrypto.CryptoKey = {
386
- algorithm : managedKey.algorithm,
387
- extractable : managedKey.extractable,
388
- material : managedKey.material,
389
- type : managedKey.type,
390
- usages : managedKey.usages
391
- };
392
-
393
- return cryptoKey;
394
- }
395
-
396
- private toManagedKey(options: Omit<IDCrypto.CryptoKey, 'material'> & RequireOnly<ManagedKey, 'id'>): ManagedKey {
397
- const managedKey: ManagedKey = {
398
- id : options.id,
399
- algorithm : options.algorithm,
400
- alias : options.alias,
401
- extractable : options.extractable,
402
- kms : this._name,
403
- material : (options.type === 'public') ? options.material : undefined,
404
- metadata : options.metadata,
405
- state : 'Enabled',
406
- type : options.type,
407
- usages : options.usages
408
- };
409
-
410
- return managedKey;
411
- }
412
- }
@@ -1,128 +0,0 @@
1
- import type { AbstractLevel } from 'abstract-level';
2
- import { Level } from 'level';
3
- import type { IDManagedAgent } from './types/agent.js';
4
- import type { DwnRpcRequest } from './rpc-client.js';
5
- import { Convert } from '../common/index.js';
6
-
7
- type LevelDatabase = AbstractLevel<string | Buffer | Uint8Array, string, string>;
8
-
9
- /**
10
- * Serialized entry stored in the outbox for replay. Uses the same shape as
11
- * the RPC payload so replay is a single sendDwnRequest per endpoint.
12
- */
13
- export type OutboxEntryPayload = {
14
- targetDid: string;
15
- dwnUrls: string[];
16
- message: Record<string, unknown>;
17
- dataBase64?: string;
18
- };
19
-
20
- export type OutboxOptions = {
21
- agent?: IDManagedAgent;
22
- dataPath?: string;
23
- db?: LevelDatabase;
24
- };
25
-
26
- /**
27
- * Persists outbound DWN send requests that failed due to network and replays
28
- * them when draining. Entries are stored in FIFO order (by key).
29
- */
30
- export class Outbox {
31
- private _agent?: IDManagedAgent;
32
- private _store: LevelDatabase;
33
-
34
- constructor(options: OutboxOptions = {}) {
35
- const { agent, dataPath = 'data/AGENT/OUTBOX', db } = options;
36
- this._agent = agent;
37
- if (db) {
38
- this._store = db.sublevel('outbox') as LevelDatabase;
39
- } else {
40
- this._store = new Level(dataPath) as LevelDatabase;
41
- }
42
- }
43
-
44
- get agent(): IDManagedAgent {
45
- if (this._agent === undefined) {
46
- throw new Error('Outbox: Unable to determine agent execution context.');
47
- }
48
- return this._agent;
49
- }
50
-
51
- set agent(agent: IDManagedAgent) {
52
- this._agent = agent;
53
- }
54
-
55
- /**
56
- * Enqueue a failed send for later replay. Payload must be the serializable
57
- * form (message object and optional data as base64).
58
- */
59
- async enqueue(entry: OutboxEntryPayload): Promise<void> {
60
- const key = `seq-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
61
- const value = JSON.stringify(entry);
62
- await this._store.put(key, value);
63
- }
64
-
65
- /**
66
- * Try each queued item: for each entry, try each dwnUrl until one succeeds;
67
- * on success delete from queue; on total failure leave in queue for next drain.
68
- */
69
- async drain(): Promise<void> {
70
- const agent = this.agent;
71
- const entries: [string, OutboxEntryPayload][] = [];
72
-
73
- for await (const [key, value] of this._store.iterator()) {
74
- if (!key.startsWith('seq-')) continue;
75
- try {
76
- const payload = JSON.parse(value as string) as OutboxEntryPayload;
77
- entries.push([key, payload]);
78
- } catch {
79
- // Skip malformed entries
80
- }
81
- }
82
-
83
- for (const [key, payload] of entries) {
84
- const { targetDid, dwnUrls, message, dataBase64 } = payload;
85
- let sent = false;
86
-
87
- for (const dwnUrl of dwnUrls) {
88
- try {
89
- const request: DwnRpcRequest = {
90
- dwnUrl,
91
- targetDid,
92
- message,
93
- ...(dataBase64 !== undefined
94
- ? {
95
- data: new Blob([
96
- new Uint8Array(Convert.base64Url(dataBase64).toUint8Array()),
97
- ]),
98
- }
99
- : {}),
100
- };
101
- await agent.rpcClient.sendDwnRequest(request);
102
- sent = true;
103
- break;
104
- } catch {
105
- // Try next endpoint
106
- }
107
- }
108
-
109
- if (sent) {
110
- await this._store.del(key);
111
- }
112
- }
113
- }
114
-
115
- /**
116
- * Clear all queued entries (for tests or reset).
117
- */
118
- async clear(): Promise<void> {
119
- const keys: string[] = [];
120
- for await (const [key] of this._store.iterator()) {
121
- if (key.startsWith('seq-')) keys.push(key);
122
- }
123
- await this._store.batch(keys.map((key) => ({ type: 'del' as const, key })) as any);
124
- }
125
- }
126
-
127
- /** @deprecated Use OutboxEntryPayload */
128
- export type OutboxEntry = OutboxEntryPayload;