@abtnode/util 1.17.6-beta-20251216-223535-283b9ffe → 1.17.6-beta-20251217-144034-62fafb94
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/lib/did-document.js +200 -10
- package/package.json +7 -7
package/lib/did-document.js
CHANGED
|
@@ -3,6 +3,7 @@ const { toBase64, toBase58, toDid } = require('@ocap/util');
|
|
|
3
3
|
const { joinURL } = require('ufo');
|
|
4
4
|
const pRetry = require('p-retry');
|
|
5
5
|
const debug = require('debug')('@abtnode/util:did-document');
|
|
6
|
+
const { BLOCKLET_CONFIGURABLE_KEY } = require('@blocklet/constant');
|
|
6
7
|
|
|
7
8
|
const sleep = require('./sleep');
|
|
8
9
|
const axios = require('./axios');
|
|
@@ -20,8 +21,17 @@ const getDID = (address) => {
|
|
|
20
21
|
return `did:abt:${address}`;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
|
-
const update = async ({
|
|
24
|
-
|
|
24
|
+
const update = async ({
|
|
25
|
+
id,
|
|
26
|
+
services,
|
|
27
|
+
didRegistryUrl,
|
|
28
|
+
wallet,
|
|
29
|
+
alsoKnownAs = [],
|
|
30
|
+
blockletServerVersion,
|
|
31
|
+
name,
|
|
32
|
+
capabilities,
|
|
33
|
+
}) => {
|
|
34
|
+
debug('starting update did document', { didRegistryUrl });
|
|
25
35
|
|
|
26
36
|
const did = getDID(wallet.address);
|
|
27
37
|
const time = new Date().toISOString();
|
|
@@ -45,6 +55,14 @@ const update = async ({ id, services, didRegistryUrl, wallet, alsoKnownAs = [],
|
|
|
45
55
|
updated: time,
|
|
46
56
|
};
|
|
47
57
|
|
|
58
|
+
if (name) {
|
|
59
|
+
document.name = name;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (capabilities) {
|
|
63
|
+
document.capabilities = capabilities;
|
|
64
|
+
}
|
|
65
|
+
|
|
48
66
|
const proof = {
|
|
49
67
|
type: 'Ed25519Signature',
|
|
50
68
|
created: time,
|
|
@@ -63,6 +81,8 @@ const update = async ({ id, services, didRegistryUrl, wallet, alsoKnownAs = [],
|
|
|
63
81
|
};
|
|
64
82
|
|
|
65
83
|
const DEFAULT_RETRY_COUNT = 6;
|
|
84
|
+
const DEFAULT_DEBOUNCE_TIME = 3000;
|
|
85
|
+
|
|
66
86
|
const getRetryCount = () => {
|
|
67
87
|
try {
|
|
68
88
|
let retryCount = parseInt(process.env.ABT_NODE_UPDATE_DID_DOCUMENT_RETRY_COUNT, 10);
|
|
@@ -75,14 +95,60 @@ const getRetryCount = () => {
|
|
|
75
95
|
}
|
|
76
96
|
};
|
|
77
97
|
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
98
|
+
const getDebounceTime = () => {
|
|
99
|
+
try {
|
|
100
|
+
let debounceTime = parseInt(process.env.ABT_NODE_DID_DOCUMENT_DEBOUNCE_TIME, 10);
|
|
101
|
+
debounceTime = Number.isNaN(debounceTime) ? DEFAULT_DEBOUNCE_TIME : debounceTime;
|
|
102
|
+
return debounceTime;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
return DEFAULT_DEBOUNCE_TIME;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const pendingUpdates = new Map();
|
|
109
|
+
const updateTimers = new Map();
|
|
110
|
+
|
|
111
|
+
const updateWithRetry = (...args) => {
|
|
112
|
+
const params = args[0];
|
|
113
|
+
const did = toDid(params.id);
|
|
114
|
+
|
|
115
|
+
return new Promise((resolve, reject) => {
|
|
116
|
+
if (updateTimers.has(did)) {
|
|
117
|
+
clearTimeout(updateTimers.get(did));
|
|
118
|
+
debug('cancelled pending update for did', { did });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
pendingUpdates.set(did, { args, resolve, reject });
|
|
122
|
+
|
|
123
|
+
const timer = setTimeout(async () => {
|
|
124
|
+
const pending = pendingUpdates.get(did);
|
|
125
|
+
pendingUpdates.delete(did);
|
|
126
|
+
updateTimers.delete(did);
|
|
127
|
+
|
|
128
|
+
if (!pending) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
debug('executing debounced update for did', { did });
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const result = await pRetry(() => update(...pending.args), {
|
|
136
|
+
retries: getRetryCount(),
|
|
137
|
+
onFailedAttempt: async (error) => {
|
|
138
|
+
debug('update did document failed', error);
|
|
139
|
+
await sleep(10 * 1000);
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
pending.resolve(result);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
pending.reject(error);
|
|
145
|
+
}
|
|
146
|
+
}, getDebounceTime());
|
|
147
|
+
|
|
148
|
+
updateTimers.set(did, timer);
|
|
149
|
+
debug('scheduled update for did', { did, debounceTime: getDebounceTime() });
|
|
85
150
|
});
|
|
151
|
+
};
|
|
86
152
|
|
|
87
153
|
const getServerServices = ({ ips, wallet, domain }) => {
|
|
88
154
|
const records = ips.map((ip) => ({
|
|
@@ -148,6 +214,83 @@ const updateServerDocument = async ({ ips, wallet, didRegistryUrl, domain, block
|
|
|
148
214
|
return updateWithRetry({ id: getDID(wallet.address), services, didRegistryUrl, wallet, blockletServerVersion });
|
|
149
215
|
};
|
|
150
216
|
|
|
217
|
+
// Fetch existing DID document from registry
|
|
218
|
+
const getDidDocument = async ({ did, didRegistryUrl }) => {
|
|
219
|
+
const fullDid = getDID(did);
|
|
220
|
+
const resolveUrl = joinURL(didRegistryUrl, '/.well-known/did-resolver/resolve', fullDid);
|
|
221
|
+
|
|
222
|
+
debug('fetching did document', { did: fullDid, resolveUrl });
|
|
223
|
+
|
|
224
|
+
const response = await axios.get(resolveUrl, {
|
|
225
|
+
timeout: 10 * 1000,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
return response.data?.didDocument || null;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// Internal function to update blocklet state only
|
|
232
|
+
const updateBlockletStateOnlyInternal = async ({ did, state, didRegistryUrl, wallet, blockletServerVersion }) => {
|
|
233
|
+
if (['0', 'false', 0, false].includes(process.env.ABT_NODE_DID_DOCUMENT_UPDATE)) {
|
|
234
|
+
throw new Error('Did Document update is disabled');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
debug('updating blocklet state only', { did, state });
|
|
238
|
+
|
|
239
|
+
// Fetch current DID document from registry
|
|
240
|
+
const currentDoc = await getDidDocument({ did, didRegistryUrl });
|
|
241
|
+
|
|
242
|
+
if (!currentDoc) {
|
|
243
|
+
throw new Error(`Failed to fetch DID document for ${did} from registry`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Only update state if the path exists
|
|
247
|
+
if (currentDoc.capabilities?.blocklet?.metadata) {
|
|
248
|
+
currentDoc.capabilities.blocklet.metadata.state = state;
|
|
249
|
+
} else {
|
|
250
|
+
throw new Error(`DID document for ${did} does not have capabilities.blocklet.metadata structure`);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Update timestamp
|
|
254
|
+
const time = new Date().toISOString();
|
|
255
|
+
currentDoc.updated = time;
|
|
256
|
+
|
|
257
|
+
// Remove old proof before re-signing
|
|
258
|
+
delete currentDoc.proof;
|
|
259
|
+
|
|
260
|
+
// Generate new proof with updated document
|
|
261
|
+
const controllerDid = getDID(wallet.address);
|
|
262
|
+
const proof = {
|
|
263
|
+
type: 'Ed25519Signature',
|
|
264
|
+
created: time,
|
|
265
|
+
verificationMethod: `${controllerDid}#key-1`,
|
|
266
|
+
jws: toBase64(await wallet.sign(stringify(currentDoc))),
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
currentDoc.proof = proof;
|
|
270
|
+
|
|
271
|
+
debug('update blocklet state only - sending to registry', { did, state, didRegistryUrl });
|
|
272
|
+
|
|
273
|
+
// Send directly to registry without reconstructing
|
|
274
|
+
return axios.post(joinURL(didRegistryUrl, '/.well-known/did-resolver/registries'), currentDoc, {
|
|
275
|
+
timeout: 10 * 1000,
|
|
276
|
+
headers: { 'X-Blocklet-Server-Version': blockletServerVersion },
|
|
277
|
+
});
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Update only blocklet state (e.g., to 'deleted') by fetching current document from registry with retry
|
|
281
|
+
// This function preserves the complete DID document structure and only modifies the state field
|
|
282
|
+
const updateBlockletStateOnly = (params) => {
|
|
283
|
+
debug('updateBlockletStateOnly with retry', { did: params.did });
|
|
284
|
+
|
|
285
|
+
return pRetry(() => updateBlockletStateOnlyInternal(params), {
|
|
286
|
+
retries: getRetryCount(),
|
|
287
|
+
onFailedAttempt: async (error) => {
|
|
288
|
+
debug('update blocklet state only failed', error);
|
|
289
|
+
await sleep(10 * 1000);
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
};
|
|
293
|
+
|
|
151
294
|
const updateBlockletDocument = ({
|
|
152
295
|
blocklet,
|
|
153
296
|
slpDid,
|
|
@@ -159,6 +302,11 @@ const updateBlockletDocument = ({
|
|
|
159
302
|
alsoKnownAs = [],
|
|
160
303
|
serverDid,
|
|
161
304
|
blockletServerVersion,
|
|
305
|
+
name,
|
|
306
|
+
state,
|
|
307
|
+
owner,
|
|
308
|
+
launcher,
|
|
309
|
+
domains,
|
|
162
310
|
}) => {
|
|
163
311
|
const { appPid } = blocklet;
|
|
164
312
|
if (['0', 'false', 0, false].includes(process.env.ABT_NODE_DID_DOCUMENT_UPDATE)) {
|
|
@@ -166,16 +314,58 @@ const updateBlockletDocument = ({
|
|
|
166
314
|
}
|
|
167
315
|
|
|
168
316
|
const services = getBlockletServices({ appPid, slpDid, daemonDidDomain, domain, slpDomain, serverDid });
|
|
169
|
-
|
|
317
|
+
|
|
318
|
+
const tagMap = new Set(blocklet.meta?.keywords || []);
|
|
319
|
+
tagMap.add('type:blocklet');
|
|
320
|
+
|
|
321
|
+
const metadata = {
|
|
322
|
+
name: blocklet.environments.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_NAME)?.value,
|
|
323
|
+
description: blocklet.environments.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_DESCRIPTION)?.value,
|
|
324
|
+
icon: blocklet.environments.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO)?.value,
|
|
325
|
+
tags: [],
|
|
326
|
+
state,
|
|
327
|
+
owner,
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
if (launcher) {
|
|
331
|
+
tagMap.add('launcher:app');
|
|
332
|
+
metadata.launcher = launcher;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
metadata.tags = Array.from(tagMap);
|
|
336
|
+
|
|
337
|
+
const capabilities = {
|
|
338
|
+
blocklet: {
|
|
339
|
+
metadata,
|
|
340
|
+
domains,
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
debug('update blocklet document', { appPid, capabilities });
|
|
345
|
+
|
|
346
|
+
return updateWithRetry({
|
|
347
|
+
id: appPid,
|
|
348
|
+
services,
|
|
349
|
+
didRegistryUrl,
|
|
350
|
+
alsoKnownAs,
|
|
351
|
+
wallet,
|
|
352
|
+
blockletServerVersion,
|
|
353
|
+
name,
|
|
354
|
+
capabilities,
|
|
355
|
+
});
|
|
170
356
|
};
|
|
171
357
|
|
|
172
358
|
module.exports = {
|
|
173
359
|
DEFAULT_RETRY_COUNT,
|
|
360
|
+
DEFAULT_DEBOUNCE_TIME,
|
|
174
361
|
updateServerDocument,
|
|
175
362
|
updateBlockletDocument,
|
|
363
|
+
updateBlockletStateOnly,
|
|
364
|
+
getDidDocument,
|
|
176
365
|
getDID,
|
|
177
366
|
getServerServices,
|
|
178
367
|
getBlockletServices,
|
|
179
368
|
updateWithRetry,
|
|
180
369
|
getRetryCount,
|
|
370
|
+
getDebounceTime,
|
|
181
371
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.17.6-beta-
|
|
6
|
+
"version": "1.17.6-beta-20251217-144034-62fafb94",
|
|
7
7
|
"description": "ArcBlock's JavaScript utility",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
"author": "polunzh <polunzh@gmail.com> (http://github.com/polunzh)",
|
|
19
19
|
"license": "Apache-2.0",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@abtnode/constant": "1.17.6-beta-
|
|
22
|
-
"@abtnode/db-cache": "1.17.6-beta-
|
|
21
|
+
"@abtnode/constant": "1.17.6-beta-20251217-144034-62fafb94",
|
|
22
|
+
"@abtnode/db-cache": "1.17.6-beta-20251217-144034-62fafb94",
|
|
23
23
|
"@arcblock/did": "^1.27.15",
|
|
24
24
|
"@arcblock/event-hub": "^1.27.15",
|
|
25
25
|
"@arcblock/pm2": "^6.0.12",
|
|
26
|
-
"@blocklet/constant": "1.17.6-beta-
|
|
26
|
+
"@blocklet/constant": "1.17.6-beta-20251217-144034-62fafb94",
|
|
27
27
|
"@blocklet/error": "^0.3.5",
|
|
28
|
-
"@blocklet/meta": "1.17.6-beta-
|
|
28
|
+
"@blocklet/meta": "1.17.6-beta-20251217-144034-62fafb94",
|
|
29
29
|
"@blocklet/xss": "^0.3.13",
|
|
30
30
|
"@ocap/client": "^1.27.15",
|
|
31
31
|
"@ocap/mcrypto": "^1.27.15",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"through2-filter": "^3.0.0",
|
|
80
80
|
"through2-map": "^3.0.0",
|
|
81
81
|
"to-semver": "^3.0.0",
|
|
82
|
-
"transliteration": "
|
|
82
|
+
"transliteration": "2.3.5",
|
|
83
83
|
"ufo": "^1.5.3",
|
|
84
84
|
"which": "^2.0.2"
|
|
85
85
|
},
|
|
@@ -90,5 +90,5 @@
|
|
|
90
90
|
"express": "^4.18.2",
|
|
91
91
|
"fs-extra": "^11.2.0"
|
|
92
92
|
},
|
|
93
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "9f47bf4e66af87c562f846e5470f45491506ab36"
|
|
94
94
|
}
|