@docknetwork/wallet-sdk-wasm 1.5.14 → 1.7.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.
- package/generate-docs.js +49 -0
- package/jsdoc.conf.json +29 -6
- package/lib/index.js +9 -1
- package/lib/index.mjs +9 -1
- package/lib/modules/network-manager.js +15 -12
- package/lib/modules/network-manager.mjs +15 -12
- package/lib/rpc-server.js +11 -1
- package/lib/rpc-server.mjs +11 -1
- package/lib/services/blockchain/cached-did-resolver.js +113 -0
- package/lib/services/blockchain/cached-did-resolver.mjs +109 -0
- package/lib/services/blockchain/index.js +11 -0
- package/lib/services/blockchain/index.mjs +11 -0
- package/lib/services/blockchain/service-rpc.js +12 -0
- package/lib/services/blockchain/service-rpc.mjs +12 -0
- package/lib/services/blockchain/service.js +161 -19
- package/lib/services/blockchain/service.mjs +162 -20
- package/lib/services/credential/bbs-revocation.js +11 -0
- package/lib/services/credential/bbs-revocation.mjs +11 -0
- package/lib/services/credential/bound-check.js +1 -1
- package/lib/services/credential/bound-check.mjs +1 -1
- package/lib/services/credential/config.js +4 -1
- package/lib/services/credential/config.mjs +4 -1
- package/lib/services/credential/delegatable-credentials.js +300 -0
- package/lib/services/credential/delegatable-credentials.mjs +263 -0
- package/lib/services/credential/index.js +53 -0
- package/lib/services/credential/index.mjs +18 -0
- package/lib/services/credential/pex-helpers.js +4 -4
- package/lib/services/credential/pex-helpers.mjs +4 -4
- package/lib/services/credential/sd-jwt.js +214 -0
- package/lib/services/credential/sd-jwt.mjs +200 -0
- package/lib/services/credential/service-rpc.js +9 -0
- package/lib/services/credential/service-rpc.mjs +9 -0
- package/lib/services/credential/service.js +324 -7
- package/lib/services/credential/service.mjs +324 -7
- package/lib/services/edv/index.js +1 -0
- package/lib/services/edv/index.mjs +1 -0
- package/lib/services/edv/service-rpc.js +23 -0
- package/lib/services/edv/service-rpc.mjs +23 -0
- package/lib/services/edv/service.js +226 -2
- package/lib/services/edv/service.mjs +223 -3
- package/lib/services/index.js +14 -0
- package/lib/services/index.mjs +14 -0
- package/lib/services/pex/config.js +4 -0
- package/lib/services/pex/config.mjs +4 -0
- package/lib/services/pex/service-rpc.js +4 -0
- package/lib/services/pex/service-rpc.mjs +4 -0
- package/lib/services/pex/service.js +7 -0
- package/lib/services/pex/service.mjs +7 -0
- package/lib/services/relay-service/service.js +124 -1
- package/lib/services/relay-service/service.mjs +124 -1
- package/lib/services/rpc-service-client.js +0 -3
- package/lib/services/rpc-service-client.mjs +0 -3
- package/lib/services/storage/index.js +19 -2
- package/lib/services/storage/index.mjs +24 -1
- package/lib/services/storage/service-rpc.js +7 -3
- package/lib/services/storage/service-rpc.mjs +7 -3
- package/lib/services/storage/service.js +4 -0
- package/lib/services/storage/service.mjs +4 -0
- package/lib/setup-nodejs.js +9 -1
- package/lib/setup-nodejs.mjs +9 -1
- package/lib/setup-tests.js +9 -1
- package/lib/setup-tests.mjs +9 -1
- package/lib/src/modules/event-manager.d.ts +0 -1
- package/lib/src/modules/event-manager.d.ts.map +1 -1
- package/lib/src/modules/network-manager.d.ts +2 -4
- package/lib/src/modules/network-manager.d.ts.map +1 -1
- package/lib/src/services/blockchain/cached-did-resolver.d.ts +28 -0
- package/lib/src/services/blockchain/cached-did-resolver.d.ts.map +1 -0
- package/lib/src/services/blockchain/cached-did-resolver.test.d.ts +2 -0
- package/lib/src/services/blockchain/cached-did-resolver.test.d.ts.map +1 -0
- package/lib/src/services/blockchain/configs.d.ts +1 -2
- package/lib/src/services/blockchain/configs.d.ts.map +1 -1
- package/lib/src/services/blockchain/service.d.ts +117 -19
- package/lib/src/services/blockchain/service.d.ts.map +1 -1
- package/lib/src/services/credential/bbs-revocation.d.ts +1 -1
- package/lib/src/services/credential/bbs-revocation.d.ts.map +1 -1
- package/lib/src/services/credential/bound-check.d.ts.map +1 -1
- package/lib/src/services/credential/config.d.ts.map +1 -1
- package/lib/src/services/credential/delegatable-credentials.d.ts +272 -0
- package/lib/src/services/credential/delegatable-credentials.d.ts.map +1 -0
- package/lib/src/services/credential/index.d.ts +4 -0
- package/lib/src/services/credential/index.d.ts.map +1 -1
- package/lib/src/services/credential/pex-helpers.d.ts +2 -2
- package/lib/src/services/credential/pex-helpers.d.ts.map +1 -1
- package/lib/src/services/credential/sd-jwt.test.d.ts +2 -0
- package/lib/src/services/credential/sd-jwt.test.d.ts.map +1 -0
- package/lib/src/services/credential/service.d.ts +274 -4
- package/lib/src/services/credential/service.d.ts.map +1 -1
- package/lib/src/services/dids/keypair-utils.d.ts +2 -2
- package/lib/src/services/dids/keypair-utils.d.ts.map +1 -1
- package/lib/src/services/dids/service.d.ts +35 -3
- package/lib/src/services/dids/service.d.ts.map +1 -1
- package/lib/src/services/edv/service.d.ts +201 -2
- package/lib/src/services/edv/service.d.ts.map +1 -1
- package/lib/src/services/pex/config.d.ts +1 -0
- package/lib/src/services/pex/config.d.ts.map +1 -1
- package/lib/src/services/pex/service.d.ts +1 -0
- package/lib/src/services/pex/service.d.ts.map +1 -1
- package/lib/src/services/relay-service/service.d.ts +148 -8
- package/lib/src/services/relay-service/service.d.ts.map +1 -1
- package/lib/src/services/rpc-service-client.d.ts +2 -2
- package/lib/src/services/rpc-service-client.d.ts.map +1 -1
- package/lib/src/services/storage/index.d.ts +1 -1
- package/lib/src/services/storage/index.d.ts.map +1 -1
- package/lib/src/services/storage/service-rpc.d.ts +9 -0
- package/lib/src/services/storage/service-rpc.d.ts.map +1 -0
- package/lib/src/services/storage/service.d.ts +1 -0
- package/lib/src/services/storage/service.d.ts.map +1 -1
- package/lib/src/services/util-crypto/service.d.ts +2 -2
- package/lib/src/services/util-crypto/service.d.ts.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/wallet/rpc-storage-interface.js +13 -3
- package/lib/wallet/rpc-storage-interface.mjs +11 -1
- package/lib/wallet/rpc-storage-wallet.js +10 -0
- package/lib/wallet/rpc-storage-wallet.mjs +10 -0
- package/package.json +29 -16
- package/rollup.config.mjs +5 -3
- package/src/globals.d.ts +3 -0
- package/src/modules/network-manager.ts +15 -14
- package/src/services/blockchain/cached-did-resolver.test.ts +288 -0
- package/src/services/blockchain/cached-did-resolver.ts +126 -0
- package/src/services/blockchain/configs.ts +1 -2
- package/src/services/blockchain/service-rpc.js +12 -0
- package/src/services/blockchain/service.ts +167 -20
- package/src/services/credential/bound-check.ts +1 -1
- package/src/services/credential/config.ts +7 -1
- package/src/services/credential/delegatable-credentials.ts +409 -0
- package/src/services/credential/index.ts +16 -0
- package/src/services/credential/pex-helpers.js +4 -4
- package/src/services/credential/pex-helpers.test.js +2 -2
- package/src/services/credential/sd-jwt.test.ts +718 -0
- package/src/services/credential/sd-jwt.ts +231 -0
- package/src/services/credential/service-rpc.js +9 -0
- package/src/services/credential/service.ts +328 -7
- package/src/services/edv/index.test.js +229 -0
- package/src/services/edv/service-rpc.js +23 -0
- package/src/services/edv/service.ts +272 -1
- package/src/services/pex/config.ts +4 -0
- package/src/services/pex/service-rpc.js +4 -0
- package/src/services/pex/service.ts +13 -0
- package/src/services/pex/tests/pex-service.test.js +210 -0
- package/src/services/relay-service/service.ts +130 -1
- package/src/services/rpc-service-client.js +0 -3
- package/src/services/storage/index.js +15 -1
- package/src/services/storage/service-rpc.js +7 -3
- package/src/services/storage/service.ts +5 -0
|
@@ -2,8 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
var StorageInterface = require('@docknetwork/universal-wallet/storage/storage-interface');
|
|
4
4
|
var uuid = require('uuid');
|
|
5
|
-
var
|
|
5
|
+
var services_storage_index = require('../services/storage/index.js');
|
|
6
6
|
var core_logger = require('../core/logger.js');
|
|
7
|
+
require('../services/storage/service.js');
|
|
8
|
+
require('../services/storage/service-rpc.js');
|
|
9
|
+
require('../services/rpc-service-client.js');
|
|
10
|
+
require('assert');
|
|
11
|
+
require('../rpc-client.js');
|
|
12
|
+
require('json-rpc-2.0');
|
|
13
|
+
require('../core/crypto.js');
|
|
14
|
+
require('crypto');
|
|
15
|
+
require('../logger.js');
|
|
16
|
+
require('../rpc-util.js');
|
|
7
17
|
|
|
8
18
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
19
|
|
|
@@ -25,7 +35,7 @@ class RpcStorageInterface extends StorageInterface__default["default"] {
|
|
|
25
35
|
let data;
|
|
26
36
|
try {
|
|
27
37
|
core_logger.Logger.debug(`Wallet: Loading storage from ${directory}`);
|
|
28
|
-
data = await
|
|
38
|
+
data = await services_storage_index.storageService.getItem(directory);
|
|
29
39
|
|
|
30
40
|
this.documents = typeof data === 'string' ? JSON.parse(data) : data;
|
|
31
41
|
|
|
@@ -47,7 +57,7 @@ class RpcStorageInterface extends StorageInterface__default["default"] {
|
|
|
47
57
|
}
|
|
48
58
|
|
|
49
59
|
updateLocalStorage() {
|
|
50
|
-
|
|
60
|
+
services_storage_index.storageService.setItem(this.directory, JSON.stringify(this.documents));
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
async get({id}) {
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import StorageInterface from '@docknetwork/universal-wallet/storage/storage-interface';
|
|
2
2
|
import { v4 } from 'uuid';
|
|
3
|
-
import { storageService } from '../services/storage/
|
|
3
|
+
import { storageService } from '../services/storage/index.mjs';
|
|
4
4
|
import { Logger } from '../core/logger.mjs';
|
|
5
|
+
import '../services/storage/service.mjs';
|
|
6
|
+
import '../services/storage/service-rpc.mjs';
|
|
7
|
+
import '../services/rpc-service-client.mjs';
|
|
8
|
+
import 'assert';
|
|
9
|
+
import '../rpc-client.mjs';
|
|
10
|
+
import 'json-rpc-2.0';
|
|
11
|
+
import '../core/crypto.mjs';
|
|
12
|
+
import 'crypto';
|
|
13
|
+
import '../logger.mjs';
|
|
14
|
+
import '../rpc-util.mjs';
|
|
5
15
|
|
|
6
16
|
function generateDocumentId() {
|
|
7
17
|
return `doc:${v4()}`;
|
|
@@ -4,8 +4,18 @@ var StorageWallet = require('@docknetwork/universal-wallet/storage-wallet');
|
|
|
4
4
|
var wallet_rpcStorageInterface = require('./rpc-storage-interface.js');
|
|
5
5
|
require('@docknetwork/universal-wallet/storage/storage-interface');
|
|
6
6
|
require('uuid');
|
|
7
|
+
require('../services/storage/index.js');
|
|
7
8
|
require('../services/storage/service.js');
|
|
9
|
+
require('../services/storage/service-rpc.js');
|
|
10
|
+
require('../services/rpc-service-client.js');
|
|
11
|
+
require('assert');
|
|
12
|
+
require('../rpc-client.js');
|
|
13
|
+
require('json-rpc-2.0');
|
|
14
|
+
require('../core/crypto.js');
|
|
15
|
+
require('crypto');
|
|
8
16
|
require('../core/logger.js');
|
|
17
|
+
require('../logger.js');
|
|
18
|
+
require('../rpc-util.js');
|
|
9
19
|
|
|
10
20
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
11
21
|
|
|
@@ -2,8 +2,18 @@ import StorageWallet from '@docknetwork/universal-wallet/storage-wallet';
|
|
|
2
2
|
import RpcStorageInterface from './rpc-storage-interface.mjs';
|
|
3
3
|
import '@docknetwork/universal-wallet/storage/storage-interface';
|
|
4
4
|
import 'uuid';
|
|
5
|
+
import '../services/storage/index.mjs';
|
|
5
6
|
import '../services/storage/service.mjs';
|
|
7
|
+
import '../services/storage/service-rpc.mjs';
|
|
8
|
+
import '../services/rpc-service-client.mjs';
|
|
9
|
+
import 'assert';
|
|
10
|
+
import '../rpc-client.mjs';
|
|
11
|
+
import 'json-rpc-2.0';
|
|
12
|
+
import '../core/crypto.mjs';
|
|
13
|
+
import 'crypto';
|
|
6
14
|
import '../core/logger.mjs';
|
|
15
|
+
import '../logger.mjs';
|
|
16
|
+
import '../rpc-util.mjs';
|
|
7
17
|
|
|
8
18
|
class RpcWallet extends StorageWallet {
|
|
9
19
|
constructor(id, storageOptions = {}) {
|
package/package.json
CHANGED
|
@@ -1,46 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docknetwork/wallet-sdk-wasm",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"license": "https://github.com/docknetwork/
|
|
3
|
+
"version": "1.7.6",
|
|
4
|
+
"license": "https://github.com/docknetwork/wallet-sdk/LICENSE",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "git+https://github.com/docknetwork/
|
|
7
|
+
"url": "git+https://github.com/docknetwork/wallet-sdk.git",
|
|
8
8
|
"directory": "packages/wasm"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"prepublishOnly": "npm run build",
|
|
12
12
|
"build:babel": "rm -rf lib && NODE_ENV=production babel src/ --out-dir lib --copy-files",
|
|
13
|
-
"build": "rm -rf lib && rollup -c && node ../../scripts/fix-build-imports.js ./lib"
|
|
13
|
+
"build": "rm -rf lib && rollup -c && node ../../scripts/fix-build-imports.js ./lib",
|
|
14
|
+
"docs": "node generate-docs.js",
|
|
15
|
+
"docs:jsdoc": "jsdoc -c jsdoc.conf.json -r src/"
|
|
14
16
|
},
|
|
15
17
|
"resolutions": {
|
|
16
18
|
"p-limit": "2.3.0"
|
|
17
19
|
},
|
|
18
20
|
"dependencies": {
|
|
19
|
-
"p-limit": "2.3.0",
|
|
20
21
|
"@astronautlabs/jsonpath": "^1.1.2",
|
|
21
|
-
"@
|
|
22
|
-
"@docknetwork/wallet-sdk-dids": "^1.5.14",
|
|
22
|
+
"@cedar-policy/cedar-wasm": "^4.5.0",
|
|
23
23
|
"@cosmjs/proto-signing": "^0.32.4",
|
|
24
|
-
"@docknetwork/cheqd-blockchain-api": "4.
|
|
25
|
-
"@docknetwork/cheqd-blockchain-modules": "4.0.
|
|
26
|
-
"@
|
|
24
|
+
"@docknetwork/cheqd-blockchain-api": "4.1.1",
|
|
25
|
+
"@docknetwork/cheqd-blockchain-modules": "4.0.8",
|
|
26
|
+
"@docknetwork/credential-sdk": "0.54.16",
|
|
27
|
+
"@docknetwork/universal-wallet": "^2.0.1",
|
|
28
|
+
"@docknetwork/vc-delegation-engine": "1.0.3",
|
|
29
|
+
"@docknetwork/wallet-sdk-dids": "^1.7.6",
|
|
27
30
|
"@noble/hashes": "1.8.0",
|
|
28
|
-
"@
|
|
31
|
+
"@scure/bip39": "^1.6.0",
|
|
32
|
+
"@sd-jwt/crypto-nodejs": "^0.15.0",
|
|
33
|
+
"@sd-jwt/sd-jwt-vc": "^0.15.1",
|
|
29
34
|
"@sphereon/oid4vci-client": "^0.16.0",
|
|
30
35
|
"@sphereon/oid4vci-common": "^0.16.0",
|
|
36
|
+
"@sphereon/pex": "^1.1.4",
|
|
31
37
|
"axios": "^0.25.0",
|
|
38
|
+
"axios-retry": "^3.2.5",
|
|
39
|
+
"base64url": "^3.0.1",
|
|
40
|
+
"cwait": "1.1.2",
|
|
41
|
+
"futoin-hkdf": "^1.5.3",
|
|
32
42
|
"json-rpc-2.0": "^0.2.16",
|
|
43
|
+
"jsonld": "^6.0.0",
|
|
44
|
+
"p-limit": "2.3.0",
|
|
33
45
|
"uuid": "^8.3.2",
|
|
34
|
-
"winston": "^3.3.3"
|
|
35
|
-
"cwait": "1.1.2",
|
|
36
|
-
"axios-retry": "^3.2.5",
|
|
37
|
-
"@sphereon/pex": "^1.1.4"
|
|
46
|
+
"winston": "^3.3.3"
|
|
38
47
|
},
|
|
39
48
|
"devDependencies": {
|
|
40
49
|
"@babel/node": "^7.16.0",
|
|
41
|
-
"sinon": "^12.0.1",
|
|
42
50
|
"jest": "29.6.1",
|
|
51
|
+
"sinon": "^12.0.1",
|
|
43
52
|
"ts-jest": "29.1.0",
|
|
44
53
|
"typescript": "^5.0.4"
|
|
54
|
+
},
|
|
55
|
+
"overrides": {
|
|
56
|
+
"@digitalbazaar/http-client": "^3.4.1",
|
|
57
|
+
"base58-universal": "2.0.0"
|
|
45
58
|
}
|
|
46
59
|
}
|
package/rollup.config.mjs
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import json from '@rollup/plugin-json';
|
|
2
|
-
import
|
|
2
|
+
import _multiInput from 'rollup-plugin-multi-input';
|
|
3
3
|
import commonjs from '@rollup/plugin-commonjs';
|
|
4
4
|
import flow from 'rollup-plugin-flow';
|
|
5
5
|
import typescript from '@rollup/plugin-typescript';
|
|
6
6
|
|
|
7
|
+
const multiInput = _multiInput.default || _multiInput;
|
|
8
|
+
|
|
7
9
|
export default async function () {
|
|
8
10
|
return [
|
|
9
11
|
{
|
|
10
12
|
plugins: [
|
|
11
|
-
multiInput
|
|
13
|
+
multiInput(),
|
|
12
14
|
json(),
|
|
13
15
|
flow({
|
|
14
16
|
all: true,
|
|
@@ -17,7 +19,7 @@ export default async function () {
|
|
|
17
19
|
commonjs(),
|
|
18
20
|
typescript(),
|
|
19
21
|
],
|
|
20
|
-
input: ['src/**/*.ts', 'src/**/*.js', '!src/**/*.test.ts', '!src/**/*.test.js'],
|
|
22
|
+
input: ['src/**/*.ts', 'src/**/*.js', '!src/**/*.test.ts', '!src/**/*.test.js', '!src/**/*.d.ts'],
|
|
21
23
|
output: [
|
|
22
24
|
{
|
|
23
25
|
dir: 'lib',
|
package/src/globals.d.ts
ADDED
|
@@ -3,35 +3,36 @@ import assert from 'assert';
|
|
|
3
3
|
|
|
4
4
|
export type NetworkInfo = {
|
|
5
5
|
name: string,
|
|
6
|
-
|
|
7
|
-
addressPrefix: number,
|
|
8
|
-
cheqdApiUrl: string,
|
|
6
|
+
cheqdApiUrl: string | string[],
|
|
9
7
|
};
|
|
10
8
|
|
|
11
9
|
export type NetworkId = 'mainnet' | 'testnet' | 'local' | 'custom';
|
|
12
10
|
|
|
13
|
-
export const
|
|
11
|
+
export const BLOCKCHAIN_NETWORKS : Record<NetworkId, NetworkInfo> = {
|
|
14
12
|
mainnet: {
|
|
15
13
|
name: 'Cheqd Mainnet',
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
cheqdApiUrl: [
|
|
15
|
+
'https://mainnet.cheqd.docknode.io',
|
|
16
|
+
'https://rpc.cheqd.net',
|
|
17
|
+
],
|
|
19
18
|
},
|
|
20
19
|
testnet: {
|
|
21
20
|
name: 'Cheqd Testnet',
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
cheqdApiUrl: [
|
|
22
|
+
'https://testnet.cheqd.docknode.io',
|
|
23
|
+
'https://api.cheqd.network',
|
|
24
|
+
],
|
|
25
25
|
},
|
|
26
26
|
local: {
|
|
27
27
|
name: 'Local Node',
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
cheqdApiUrl: [
|
|
29
|
+
'http://localhost:8080',
|
|
30
|
+
],
|
|
30
31
|
},
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
function getNetworkInfo(networkId): NetworkInfo {
|
|
34
|
-
const networkInfo =
|
|
35
|
+
const networkInfo = BLOCKCHAIN_NETWORKS[networkId];
|
|
35
36
|
|
|
36
37
|
assert(!!networkInfo, `Network ${networkId} not found`);
|
|
37
38
|
|
|
@@ -57,7 +58,7 @@ export class NetworkManager {
|
|
|
57
58
|
* @param {string} networkId
|
|
58
59
|
*/
|
|
59
60
|
setNetworkId(networkId: NetworkId) {
|
|
60
|
-
assert(!!
|
|
61
|
+
assert(!!BLOCKCHAIN_NETWORKS[networkId], `invalid networkId ${networkId}`);
|
|
61
62
|
|
|
62
63
|
this.networkId = networkId;
|
|
63
64
|
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { CachedDIDResolver } from './cached-did-resolver';
|
|
2
|
+
import { storageService } from '../storage';
|
|
3
|
+
|
|
4
|
+
const mockStorageService = {
|
|
5
|
+
getItem: jest.fn(),
|
|
6
|
+
setItem: jest.fn(),
|
|
7
|
+
removeItem: jest.fn(),
|
|
8
|
+
getAllKeys: jest.fn(),
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
jest.mock('../storage', () => ({
|
|
12
|
+
storageService: mockStorageService,
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
const mockRouter = {
|
|
16
|
+
resolve: jest.fn(),
|
|
17
|
+
supports: jest.fn(),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
describe('CachedDIDResolver', () => {
|
|
21
|
+
let resolver: CachedDIDResolver;
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
jest.clearAllMocks();
|
|
25
|
+
mockStorageService.getItem.mockResolvedValue(null);
|
|
26
|
+
mockStorageService.getAllKeys.mockResolvedValue([]);
|
|
27
|
+
resolver = new CachedDIDResolver(mockRouter);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('constructor', () => {
|
|
31
|
+
it('should initialize with default TTL', () => {
|
|
32
|
+
expect(resolver).toBeDefined();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should initialize with custom TTL', () => {
|
|
36
|
+
const customTtl = 60000; // 1 minute
|
|
37
|
+
const resolverWithCustomTtl = new CachedDIDResolver(mockRouter, { ttl: customTtl });
|
|
38
|
+
expect(resolverWithCustomTtl).toBeDefined();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('resolve', () => {
|
|
43
|
+
const testDid = 'did:example:123';
|
|
44
|
+
const testResult = { id: testDid, publicKey: [] };
|
|
45
|
+
|
|
46
|
+
it('should resolve DID and cache the result on cache miss', async () => {
|
|
47
|
+
mockRouter.resolve.mockResolvedValue(testResult);
|
|
48
|
+
mockStorageService.getItem.mockResolvedValue(null);
|
|
49
|
+
|
|
50
|
+
const result = await resolver.resolve(testDid);
|
|
51
|
+
|
|
52
|
+
expect(mockRouter.resolve).toHaveBeenCalledWith(testDid);
|
|
53
|
+
expect(result).toEqual(testResult);
|
|
54
|
+
expect(mockStorageService.setItem).toHaveBeenCalledWith(
|
|
55
|
+
`did-cache:${testDid}`,
|
|
56
|
+
JSON.stringify({
|
|
57
|
+
value: testResult,
|
|
58
|
+
id: testDid,
|
|
59
|
+
timestamp: expect.any(Number),
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should use result.id for cache key instead of input did', async () => {
|
|
65
|
+
const inputDid = 'did:example:input';
|
|
66
|
+
const resultDid = 'did:example:resolved';
|
|
67
|
+
const testResultWithDifferentId = { id: resultDid, publicKey: [] };
|
|
68
|
+
|
|
69
|
+
mockRouter.resolve.mockResolvedValue(testResultWithDifferentId);
|
|
70
|
+
mockStorageService.getItem.mockResolvedValue(null);
|
|
71
|
+
|
|
72
|
+
const result = await resolver.resolve(inputDid);
|
|
73
|
+
|
|
74
|
+
expect(result).toEqual(testResultWithDifferentId);
|
|
75
|
+
// Should use result.id (resultDid) for the cache key, not inputDid
|
|
76
|
+
expect(mockStorageService.setItem).toHaveBeenCalledWith(
|
|
77
|
+
`did-cache:${resultDid}`,
|
|
78
|
+
JSON.stringify({
|
|
79
|
+
value: testResultWithDifferentId,
|
|
80
|
+
id: resultDid,
|
|
81
|
+
timestamp: expect.any(Number),
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should return cached result on cache hit', async () => {
|
|
87
|
+
const cachedData = {
|
|
88
|
+
value: testResult,
|
|
89
|
+
id: testDid,
|
|
90
|
+
timestamp: Date.now(),
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
mockStorageService.getItem.mockResolvedValue(JSON.stringify(cachedData));
|
|
94
|
+
|
|
95
|
+
const result = await resolver.resolve(testDid);
|
|
96
|
+
|
|
97
|
+
expect(result).toEqual(testResult);
|
|
98
|
+
expect(mockRouter.resolve).not.toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should return stale value immediately and refresh in background when cache entry is expired', async () => {
|
|
102
|
+
const expiredTimestamp = Date.now() - (8 * 24 * 60 * 60 * 1000); // 8 days ago (expired)
|
|
103
|
+
const staleResult = { id: testDid, publicKey: [], stale: true };
|
|
104
|
+
const freshResult = { id: testDid, publicKey: [], fresh: true };
|
|
105
|
+
|
|
106
|
+
const cachedData = {
|
|
107
|
+
value: staleResult,
|
|
108
|
+
id: testDid,
|
|
109
|
+
timestamp: expiredTimestamp,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
mockStorageService.getItem.mockResolvedValue(JSON.stringify(cachedData));
|
|
113
|
+
mockRouter.resolve.mockResolvedValue(freshResult);
|
|
114
|
+
|
|
115
|
+
const result = await resolver.resolve(testDid);
|
|
116
|
+
|
|
117
|
+
// Should return stale value immediately
|
|
118
|
+
expect(result).toEqual(staleResult);
|
|
119
|
+
|
|
120
|
+
// Background refresh should be triggered (not awaited)
|
|
121
|
+
// Give it time to complete
|
|
122
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
123
|
+
|
|
124
|
+
expect(mockRouter.resolve).toHaveBeenCalledWith(testDid);
|
|
125
|
+
expect(mockStorageService.setItem).toHaveBeenCalledWith(
|
|
126
|
+
`did-cache:${testDid}`,
|
|
127
|
+
JSON.stringify({
|
|
128
|
+
value: freshResult,
|
|
129
|
+
id: testDid,
|
|
130
|
+
timestamp: expect.any(Number),
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('should handle corrupted cache data gracefully', async () => {
|
|
136
|
+
const testDid = 'did:example:corrupted';
|
|
137
|
+
const testResult = { id: testDid, publicKey: [] };
|
|
138
|
+
|
|
139
|
+
// Return invalid JSON from storage
|
|
140
|
+
mockStorageService.getItem.mockResolvedValue('invalid json {');
|
|
141
|
+
mockRouter.resolve.mockResolvedValue(testResult);
|
|
142
|
+
|
|
143
|
+
const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
144
|
+
|
|
145
|
+
const result = await resolver.resolve(testDid);
|
|
146
|
+
|
|
147
|
+
expect(consoleSpy).toHaveBeenCalledWith('Error parsing cache entry:', expect.any(Error));
|
|
148
|
+
expect(mockRouter.resolve).toHaveBeenCalledWith(testDid);
|
|
149
|
+
expect(result).toEqual(testResult);
|
|
150
|
+
|
|
151
|
+
consoleSpy.mockRestore();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('getCachedDIDs', () => {
|
|
156
|
+
it('should return empty array when no cached DIDs exist', async () => {
|
|
157
|
+
mockStorageService.getAllKeys.mockResolvedValue([]);
|
|
158
|
+
|
|
159
|
+
const cachedDIDs = await resolver.getCachedDIDs();
|
|
160
|
+
|
|
161
|
+
expect(cachedDIDs).toEqual([]);
|
|
162
|
+
expect(mockStorageService.getAllKeys).toHaveBeenCalled();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should return list of cached DIDs', async () => {
|
|
166
|
+
const allKeys = [
|
|
167
|
+
'did-cache:did:example:123',
|
|
168
|
+
'did-cache:did:example:456',
|
|
169
|
+
'did-cache:did:dock:789',
|
|
170
|
+
'other-key:something',
|
|
171
|
+
'user-preference:theme',
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
mockStorageService.getAllKeys.mockResolvedValue(allKeys);
|
|
175
|
+
|
|
176
|
+
const cachedDIDs = await resolver.getCachedDIDs();
|
|
177
|
+
|
|
178
|
+
expect(cachedDIDs).toEqual([
|
|
179
|
+
'did:example:123',
|
|
180
|
+
'did:example:456',
|
|
181
|
+
'did:dock:789',
|
|
182
|
+
]);
|
|
183
|
+
expect(mockStorageService.getAllKeys).toHaveBeenCalled();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should handle empty storage correctly', async () => {
|
|
187
|
+
mockStorageService.getAllKeys.mockResolvedValue([]);
|
|
188
|
+
|
|
189
|
+
const cachedDIDs = await resolver.getCachedDIDs();
|
|
190
|
+
|
|
191
|
+
expect(cachedDIDs).toEqual([]);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('clearCache', () => {
|
|
196
|
+
it('should clear specific DID from cache', async () => {
|
|
197
|
+
const didToRemove = 'did:example:123';
|
|
198
|
+
|
|
199
|
+
await resolver.clearCache(didToRemove);
|
|
200
|
+
|
|
201
|
+
expect(mockStorageService.removeItem).toHaveBeenCalledWith(`did-cache:${didToRemove}`);
|
|
202
|
+
expect(mockStorageService.removeItem).toHaveBeenCalledTimes(1);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should clear entire cache when no DID specified', async () => {
|
|
206
|
+
const allKeys = [
|
|
207
|
+
'did-cache:did:example:123',
|
|
208
|
+
'did-cache:did:example:456',
|
|
209
|
+
'other-key:something',
|
|
210
|
+
];
|
|
211
|
+
|
|
212
|
+
mockStorageService.getAllKeys.mockResolvedValue(allKeys);
|
|
213
|
+
|
|
214
|
+
await resolver.clearCache();
|
|
215
|
+
|
|
216
|
+
expect(mockStorageService.getAllKeys).toHaveBeenCalled();
|
|
217
|
+
expect(mockStorageService.removeItem).toHaveBeenCalledWith('did-cache:did:example:123');
|
|
218
|
+
expect(mockStorageService.removeItem).toHaveBeenCalledWith('did-cache:did:example:456');
|
|
219
|
+
expect(mockStorageService.removeItem).not.toHaveBeenCalledWith('other-key:something');
|
|
220
|
+
expect(mockStorageService.removeItem).toHaveBeenCalledTimes(2);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should handle clearing cache when no cached entries exist', async () => {
|
|
224
|
+
mockStorageService.getAllKeys.mockResolvedValue([]);
|
|
225
|
+
|
|
226
|
+
await resolver.clearCache();
|
|
227
|
+
|
|
228
|
+
expect(mockStorageService.getAllKeys).toHaveBeenCalled();
|
|
229
|
+
expect(mockStorageService.removeItem).not.toHaveBeenCalled();
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe('supports', () => {
|
|
234
|
+
it('should delegate to router supports method', () => {
|
|
235
|
+
const testId = 'did:example:123';
|
|
236
|
+
mockRouter.supports.mockReturnValue(true);
|
|
237
|
+
|
|
238
|
+
const result = resolver.supports(testId);
|
|
239
|
+
|
|
240
|
+
expect(mockRouter.supports).toHaveBeenCalledWith(testId);
|
|
241
|
+
expect(result).toBe(true);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should return false when router does not support DID', () => {
|
|
245
|
+
const testId = 'did:unsupported:123';
|
|
246
|
+
mockRouter.supports.mockReturnValue(false);
|
|
247
|
+
|
|
248
|
+
const result = resolver.supports(testId);
|
|
249
|
+
|
|
250
|
+
expect(mockRouter.supports).toHaveBeenCalledWith(testId);
|
|
251
|
+
expect(result).toBe(false);
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
describe('background refresh', () => {
|
|
256
|
+
it('should handle background refresh failure gracefully', async () => {
|
|
257
|
+
const testDid = 'did:example:refresh-fail';
|
|
258
|
+
const expiredTimestamp = Date.now() - (8 * 24 * 60 * 60 * 1000);
|
|
259
|
+
const staleResult = { id: testDid, publicKey: [] };
|
|
260
|
+
|
|
261
|
+
const cachedData = {
|
|
262
|
+
value: staleResult,
|
|
263
|
+
id: testDid,
|
|
264
|
+
timestamp: expiredTimestamp,
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
mockStorageService.getItem.mockResolvedValue(JSON.stringify(cachedData));
|
|
268
|
+
mockRouter.resolve.mockRejectedValue(new Error('Network error'));
|
|
269
|
+
|
|
270
|
+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
271
|
+
|
|
272
|
+
const result = await resolver.resolve(testDid);
|
|
273
|
+
|
|
274
|
+
expect(result).toEqual(staleResult);
|
|
275
|
+
|
|
276
|
+
// Wait for background refresh to complete
|
|
277
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
278
|
+
|
|
279
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
280
|
+
'Background refresh failed for:',
|
|
281
|
+
testDid,
|
|
282
|
+
expect.any(Error)
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
consoleSpy.mockRestore();
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { storageService } from '../storage';
|
|
2
|
+
|
|
3
|
+
interface CacheEntry {
|
|
4
|
+
value: any;
|
|
5
|
+
id: string;
|
|
6
|
+
timestamp: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface CacheOptions {
|
|
10
|
+
ttl?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface DIDResolver {
|
|
14
|
+
resolve(did: string): Promise<any>;
|
|
15
|
+
supports(id: string): boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class CachedDIDResolver {
|
|
19
|
+
private router: DIDResolver;
|
|
20
|
+
private ttl: number;
|
|
21
|
+
private readonly CACHE_PREFIX = 'did-cache:';
|
|
22
|
+
|
|
23
|
+
constructor(router: DIDResolver, cacheOptions: CacheOptions = {}) {
|
|
24
|
+
this.router = router;
|
|
25
|
+
// 1 hour default
|
|
26
|
+
this.ttl = cacheOptions.ttl || 60 * 60 * 1000;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private getCacheKey(did: string): string {
|
|
30
|
+
return `${this.CACHE_PREFIX}${did}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
private async getCacheEntry(did: string): Promise<CacheEntry | null> {
|
|
35
|
+
const key = this.getCacheKey(did);
|
|
36
|
+
const data = await storageService.getItem(key);
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
return data ? JSON.parse(data) : null;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error('Error parsing cache entry:', error);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private async setCacheEntry(did: string, entry: CacheEntry): Promise<void> {
|
|
47
|
+
const key = this.getCacheKey(did);
|
|
48
|
+
await storageService.setItem(key, JSON.stringify(entry));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async getCachedDIDs(): Promise<string[]> {
|
|
52
|
+
const allKeys = await storageService.getAllKeys();
|
|
53
|
+
const cachedDIDs: string[] = [];
|
|
54
|
+
|
|
55
|
+
allKeys.forEach(key => {
|
|
56
|
+
if (key.startsWith(this.CACHE_PREFIX)) {
|
|
57
|
+
cachedDIDs.push(key.replace(this.CACHE_PREFIX, ''));
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return cachedDIDs;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async resolve(did: string): Promise<any> {
|
|
65
|
+
const cached = await this.getCacheEntry(did);
|
|
66
|
+
|
|
67
|
+
if (cached) {
|
|
68
|
+
if (Date.now() - cached.timestamp < this.ttl) {
|
|
69
|
+
console.log('Cache hit for:', did);
|
|
70
|
+
return cached.value;
|
|
71
|
+
} else {
|
|
72
|
+
console.log('Cache expired for:', did, 'returning stale value and refreshing in background');
|
|
73
|
+
this.refreshInBackground(did);
|
|
74
|
+
return cached.value;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log('Cache miss, resolving:', did);
|
|
79
|
+
const result = await this.router.resolve(did);
|
|
80
|
+
|
|
81
|
+
await this.setCacheEntry(result.id, {
|
|
82
|
+
value: result,
|
|
83
|
+
id: result.id,
|
|
84
|
+
timestamp: Date.now()
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private async refreshInBackground(did: string): Promise<void> {
|
|
91
|
+
try {
|
|
92
|
+
console.log('Refreshing cache in background for:', did);
|
|
93
|
+
const result = await this.router.resolve(did);
|
|
94
|
+
|
|
95
|
+
await this.setCacheEntry(did, {
|
|
96
|
+
value: result,
|
|
97
|
+
id: did,
|
|
98
|
+
timestamp: Date.now()
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
console.log('Background refresh completed for:', did);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.warn('Background refresh failed for:', did, error);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* if the did is provided, it will remove the specific did from the cache
|
|
109
|
+
* otherwise, it will clear the entire cache
|
|
110
|
+
* @param did
|
|
111
|
+
*/
|
|
112
|
+
async clearCache(did?: string): Promise<void> {
|
|
113
|
+
if (did) {
|
|
114
|
+
const key = this.getCacheKey(did);
|
|
115
|
+
await storageService.removeItem(key);
|
|
116
|
+
} else {
|
|
117
|
+
const allKeys = await storageService.getAllKeys();
|
|
118
|
+
const cacheKeys = allKeys.filter(key => key.startsWith(this.CACHE_PREFIX));
|
|
119
|
+
await Promise.all(cacheKeys.map(key => storageService.removeItem(key)));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
supports(id: string): boolean {
|
|
124
|
+
return this.router.supports(id);
|
|
125
|
+
}
|
|
126
|
+
}
|