@abtnode/core 1.17.5-beta-20251208-123021-e8c53f96 → 1.17.5-beta-20251211-104355-426d7eb6
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/blocklet/manager/disk.js +49 -13
- package/lib/blocklet/manager/helper/blue-green-start-blocklet.js +100 -70
- package/lib/blocklet/migration-dist/migration.cjs +10 -2
- package/lib/event/index.js +39 -0
- package/lib/migrations/index.js +4 -4
- package/lib/monitor/blocklet-runtime-monitor.js +3 -5
- package/lib/states/blocklet-child.js +119 -0
- package/lib/states/blocklet.js +264 -11
- package/lib/states/index.js +4 -1
- package/lib/util/blocklet.js +116 -51
- package/lib/util/default-node-config.js +5 -1
- package/lib/util/migration-sqlite-to-postgres.js +79 -6
- package/package.json +24 -24
package/lib/states/blocklet.js
CHANGED
|
@@ -145,6 +145,8 @@ const getExternalPortsFromMeta = (meta) =>
|
|
|
145
145
|
const formatBlocklet = (blocklet, phase, dek) => {
|
|
146
146
|
if (phase === 'onRead') {
|
|
147
147
|
blocklet.status = getBlockletStatus(blocklet);
|
|
148
|
+
// Ensure children exists before forEachBlockletSync accesses it
|
|
149
|
+
blocklet.children = blocklet.children || [];
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
forEachBlockletSync(blocklet, (b) => {
|
|
@@ -253,6 +255,200 @@ class BlockletState extends BaseState {
|
|
|
253
255
|
// @didMap: { [did: string]: metaDid: string }
|
|
254
256
|
this.didMap = new Map();
|
|
255
257
|
this.statusLocks = new Map();
|
|
258
|
+
|
|
259
|
+
// BlockletChildState instance passed from outside
|
|
260
|
+
this.BlockletChildState = config.BlockletChildState || null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Load children for a blocklet
|
|
265
|
+
* @param {string} blockletId - The blocklet ID
|
|
266
|
+
* @returns {Promise<Array>} - Array of children
|
|
267
|
+
*/
|
|
268
|
+
async loadChildren(blockletId) {
|
|
269
|
+
if (!this.BlockletChildState || !blockletId) {
|
|
270
|
+
return [];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const children = await this.BlockletChildState.getChildrenByParentId(blockletId);
|
|
274
|
+
// Ensure children is always an array
|
|
275
|
+
if (!Array.isArray(children)) {
|
|
276
|
+
return [];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return children.map((child) => {
|
|
280
|
+
// Ensure meta is an object and has required fields
|
|
281
|
+
const meta = child.meta || {};
|
|
282
|
+
if (!meta.did) {
|
|
283
|
+
logger.warn('loadChildren: child missing meta.did', { childId: child.id, parentBlockletId: blockletId });
|
|
284
|
+
}
|
|
285
|
+
if (!meta.name && !meta.bundleName) {
|
|
286
|
+
logger.warn('loadChildren: child missing meta.name and meta.bundleName', {
|
|
287
|
+
childId: child.id,
|
|
288
|
+
childDid: meta.did,
|
|
289
|
+
parentBlockletId: blockletId,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const childObj = {
|
|
294
|
+
id: child.id,
|
|
295
|
+
mountPoint: child.mountPoint,
|
|
296
|
+
meta,
|
|
297
|
+
bundleSource: child.bundleSource || {},
|
|
298
|
+
source: child.source || 0,
|
|
299
|
+
deployedFrom: child.deployedFrom || '',
|
|
300
|
+
mode: child.mode || 'production',
|
|
301
|
+
status: child.status || 0,
|
|
302
|
+
ports: child.ports || {},
|
|
303
|
+
children: child.children || [],
|
|
304
|
+
migratedFrom: child.migratedFrom || [],
|
|
305
|
+
installedAt: child.installedAt,
|
|
306
|
+
startedAt: child.startedAt,
|
|
307
|
+
stoppedAt: child.stoppedAt,
|
|
308
|
+
pausedAt: child.pausedAt,
|
|
309
|
+
operator: child.operator,
|
|
310
|
+
inProgressStart: child.inProgressStart,
|
|
311
|
+
greenStatus: child.greenStatus,
|
|
312
|
+
greenPorts: child.greenPorts,
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// Recursively load children for this child
|
|
316
|
+
if (child.children && child.children.length > 0) {
|
|
317
|
+
// Note: children array now contains IDs, need to load them
|
|
318
|
+
// This will be handled by forEachComponentV2 or similar methods
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return childObj;
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Save children to BlockletChild table
|
|
327
|
+
* @param {string} blockletId - The parent blocklet ID
|
|
328
|
+
* @param {string} blockletDid - The parent blocklet DID
|
|
329
|
+
* @param {Array} children - Array of children to save
|
|
330
|
+
*/
|
|
331
|
+
async saveChildren(blockletId, blockletDid, children) {
|
|
332
|
+
if (!this.BlockletChildState) {
|
|
333
|
+
logger.warn('BlockletChildState is not initialized, cannot save children');
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (!blockletId || !blockletDid) {
|
|
338
|
+
logger.warn('saveChildren called with invalid blockletId or blockletDid', { blockletId, blockletDid });
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (!children || children.length === 0) {
|
|
343
|
+
// If no children provided, delete all existing children
|
|
344
|
+
await this.BlockletChildState.deleteByParentId(blockletId);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Get existing children
|
|
349
|
+
const existingChildren = await this.BlockletChildState.getChildrenByParentId(blockletId);
|
|
350
|
+
const existingChildrenMap = new Map();
|
|
351
|
+
existingChildren.forEach((child) => {
|
|
352
|
+
existingChildrenMap.set(child.childDid, child);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// Track which children should be kept
|
|
356
|
+
const childrenToKeep = new Set();
|
|
357
|
+
|
|
358
|
+
// Process each child: update if exists, insert if new
|
|
359
|
+
for (const child of children) {
|
|
360
|
+
const childDid = child.meta?.did;
|
|
361
|
+
if (!childDid) {
|
|
362
|
+
logger.warn('saveChildren: child missing meta.did, skipping', {
|
|
363
|
+
blockletId,
|
|
364
|
+
blockletDid,
|
|
365
|
+
child: child.meta?.name || 'unknown',
|
|
366
|
+
});
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
childrenToKeep.add(childDid);
|
|
371
|
+
|
|
372
|
+
const existingChild = existingChildrenMap.get(childDid);
|
|
373
|
+
const updates = {};
|
|
374
|
+
|
|
375
|
+
// Only update fields that have changed or are necessary
|
|
376
|
+
// Fields that should be updated: meta, bundleSource, source, deployedFrom, mode, ports, children, migratedFrom
|
|
377
|
+
// Fields that should be preserved if not provided: status, installedAt, startedAt, stoppedAt, pausedAt, operator, inProgressStart, greenStatus, greenPorts
|
|
378
|
+
|
|
379
|
+
// Always update these fields
|
|
380
|
+
if (child.mountPoint !== undefined) updates.mountPoint = child.mountPoint;
|
|
381
|
+
if (child.meta !== undefined) updates.meta = child.meta;
|
|
382
|
+
if (child.bundleSource !== undefined) updates.bundleSource = child.bundleSource;
|
|
383
|
+
if (child.source !== undefined) updates.source = child.source;
|
|
384
|
+
if (child.deployedFrom !== undefined) updates.deployedFrom = child.deployedFrom;
|
|
385
|
+
if (child.mode !== undefined) updates.mode = child.mode;
|
|
386
|
+
if (child.ports !== undefined) updates.ports = child.ports;
|
|
387
|
+
if (child.children !== undefined) updates.children = child.children || [];
|
|
388
|
+
if (child.migratedFrom !== undefined) updates.migratedFrom = child.migratedFrom;
|
|
389
|
+
|
|
390
|
+
// Only update status-related fields if explicitly provided
|
|
391
|
+
if (child.status !== undefined) updates.status = child.status;
|
|
392
|
+
if (child.installedAt !== undefined) updates.installedAt = child.installedAt;
|
|
393
|
+
if (child.startedAt !== undefined) updates.startedAt = child.startedAt;
|
|
394
|
+
if (child.stoppedAt !== undefined) updates.stoppedAt = child.stoppedAt;
|
|
395
|
+
if (child.pausedAt !== undefined) updates.pausedAt = child.pausedAt;
|
|
396
|
+
if (child.operator !== undefined) updates.operator = child.operator;
|
|
397
|
+
if (child.inProgressStart !== undefined) updates.inProgressStart = child.inProgressStart;
|
|
398
|
+
if (child.greenStatus !== undefined) updates.greenStatus = child.greenStatus;
|
|
399
|
+
if (child.greenPorts !== undefined) updates.greenPorts = child.greenPorts;
|
|
400
|
+
|
|
401
|
+
try {
|
|
402
|
+
if (existingChild) {
|
|
403
|
+
// Update existing child only if there are changes
|
|
404
|
+
if (Object.keys(updates).length > 0) {
|
|
405
|
+
await this.BlockletChildState.update({ id: existingChild.id }, { $set: updates });
|
|
406
|
+
}
|
|
407
|
+
} else {
|
|
408
|
+
// Insert new child
|
|
409
|
+
await this.BlockletChildState.insert({
|
|
410
|
+
parentBlockletId: blockletId,
|
|
411
|
+
parentBlockletDid: blockletDid,
|
|
412
|
+
childDid,
|
|
413
|
+
mountPoint: child.mountPoint,
|
|
414
|
+
meta: child.meta,
|
|
415
|
+
bundleSource: child.bundleSource,
|
|
416
|
+
source: child.source || 0,
|
|
417
|
+
deployedFrom: child.deployedFrom || '',
|
|
418
|
+
mode: child.mode || 'production',
|
|
419
|
+
status: child.status || 0,
|
|
420
|
+
ports: child.ports || {},
|
|
421
|
+
children: child.children || [],
|
|
422
|
+
migratedFrom: child.migratedFrom || [],
|
|
423
|
+
installedAt: child.installedAt,
|
|
424
|
+
startedAt: child.startedAt,
|
|
425
|
+
stoppedAt: child.stoppedAt,
|
|
426
|
+
pausedAt: child.pausedAt,
|
|
427
|
+
operator: child.operator,
|
|
428
|
+
inProgressStart: child.inProgressStart,
|
|
429
|
+
greenStatus: child.greenStatus,
|
|
430
|
+
greenPorts: child.greenPorts,
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
} catch (error) {
|
|
434
|
+
logger.error('saveChildren: failed to save child', {
|
|
435
|
+
blockletId,
|
|
436
|
+
blockletDid,
|
|
437
|
+
childDid,
|
|
438
|
+
isUpdate: !!existingChild,
|
|
439
|
+
error: error.message,
|
|
440
|
+
});
|
|
441
|
+
throw error;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Delete children that are no longer in the list
|
|
446
|
+
const childrenToDelete = existingChildren.filter((child) => !childrenToKeep.has(child.childDid));
|
|
447
|
+
if (childrenToDelete.length > 0) {
|
|
448
|
+
for (const childToDelete of childrenToDelete) {
|
|
449
|
+
await this.BlockletChildState.remove({ id: childToDelete.id });
|
|
450
|
+
}
|
|
451
|
+
}
|
|
256
452
|
}
|
|
257
453
|
|
|
258
454
|
/**
|
|
@@ -268,7 +464,15 @@ class BlockletState extends BaseState {
|
|
|
268
464
|
}
|
|
269
465
|
|
|
270
466
|
const doc = await this.findOne({ $or: getConditions(did) });
|
|
271
|
-
|
|
467
|
+
if (!doc) {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Load children from BlockletChild table
|
|
472
|
+
const children = await this.loadChildren(doc.id);
|
|
473
|
+
doc.children = children;
|
|
474
|
+
|
|
475
|
+
return formatBlocklet(doc, 'onRead', decryptSk ? this.config.dek : null);
|
|
272
476
|
}
|
|
273
477
|
|
|
274
478
|
async getBlockletMetaDid(did) {
|
|
@@ -304,7 +508,16 @@ class BlockletState extends BaseState {
|
|
|
304
508
|
|
|
305
509
|
async getBlocklets(query = {}, projection = {}, sort = { createdAt: -1 }) {
|
|
306
510
|
const docs = await this.find(query, projection, sort);
|
|
307
|
-
|
|
511
|
+
const result = [];
|
|
512
|
+
|
|
513
|
+
for (const doc of docs.filter(Boolean)) {
|
|
514
|
+
// Load children for each blocklet
|
|
515
|
+
const children = await this.loadChildren(doc.id);
|
|
516
|
+
doc.children = children;
|
|
517
|
+
result.push(formatBlocklet(doc, 'onRead', this.config.dek));
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return result;
|
|
308
521
|
}
|
|
309
522
|
|
|
310
523
|
async deleteBlocklet(did) {
|
|
@@ -313,6 +526,11 @@ class BlockletState extends BaseState {
|
|
|
313
526
|
throw new CustomError(404, `Try to remove non-existing blocklet ${did}`);
|
|
314
527
|
}
|
|
315
528
|
|
|
529
|
+
// Delete children from BlockletChild table
|
|
530
|
+
if (this.BlockletChildState) {
|
|
531
|
+
await this.BlockletChildState.deleteByParentId(doc.id);
|
|
532
|
+
}
|
|
533
|
+
|
|
316
534
|
await this.remove({ id: doc.id });
|
|
317
535
|
|
|
318
536
|
this.didMap.delete(doc.meta?.did);
|
|
@@ -376,7 +594,6 @@ class BlockletState extends BaseState {
|
|
|
376
594
|
deployedFrom,
|
|
377
595
|
ports,
|
|
378
596
|
environments: [],
|
|
379
|
-
children,
|
|
380
597
|
migratedFrom,
|
|
381
598
|
externalSk,
|
|
382
599
|
externalSkSource,
|
|
@@ -384,6 +601,10 @@ class BlockletState extends BaseState {
|
|
|
384
601
|
});
|
|
385
602
|
|
|
386
603
|
doc = await this.findOne({ id: doc.id });
|
|
604
|
+
doc.children = children;
|
|
605
|
+
|
|
606
|
+
// Save children to BlockletChild table
|
|
607
|
+
await this.saveChildren(doc.id, doc.meta.did, children);
|
|
387
608
|
|
|
388
609
|
this.emit('add', doc);
|
|
389
610
|
|
|
@@ -403,6 +624,15 @@ class BlockletState extends BaseState {
|
|
|
403
624
|
const formatted = formatBlocklet(omit(cloneDeep(updates), ['vaults']), 'onUpdate', this.config.dek);
|
|
404
625
|
const [, [updated]] = await this.update({ id: doc.id }, { $set: formatted });
|
|
405
626
|
|
|
627
|
+
// If children are being updated, set them on the updated object before calculating status
|
|
628
|
+
// This ensures getBlockletStatus can correctly calculate status based on children
|
|
629
|
+
if (updates.children !== undefined) {
|
|
630
|
+
updated.children = updates.children;
|
|
631
|
+
if (this.BlockletChildState) {
|
|
632
|
+
await this.saveChildren(updated.id, updated.meta.did, updates.children);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
406
636
|
updated.status = getBlockletStatus(updated);
|
|
407
637
|
|
|
408
638
|
return updated;
|
|
@@ -475,10 +705,13 @@ class BlockletState extends BaseState {
|
|
|
475
705
|
meta: omit(sanitized, ['htmlAst']),
|
|
476
706
|
source,
|
|
477
707
|
deployedFrom,
|
|
478
|
-
children,
|
|
479
708
|
ports,
|
|
480
709
|
});
|
|
481
710
|
|
|
711
|
+
// Save children to BlockletChild table
|
|
712
|
+
await this.saveChildren(newDoc.id, newDoc.meta.did, children);
|
|
713
|
+
newDoc.children = children;
|
|
714
|
+
|
|
482
715
|
this.emit('upgrade', newDoc);
|
|
483
716
|
return newDoc;
|
|
484
717
|
} finally {
|
|
@@ -630,9 +863,10 @@ class BlockletState extends BaseState {
|
|
|
630
863
|
});
|
|
631
864
|
|
|
632
865
|
if (actuallyRefreshedDids.length > 0) {
|
|
633
|
-
await this.updateBlocklet(did, {
|
|
634
|
-
|
|
635
|
-
|
|
866
|
+
await this.updateBlocklet(did, {});
|
|
867
|
+
|
|
868
|
+
// Save updated children to BlockletChild table
|
|
869
|
+
await this.saveChildren(blocklet.id, blocklet.meta.did, blocklet.children);
|
|
636
870
|
}
|
|
637
871
|
|
|
638
872
|
return {
|
|
@@ -643,7 +877,7 @@ class BlockletState extends BaseState {
|
|
|
643
877
|
}
|
|
644
878
|
|
|
645
879
|
async getServices() {
|
|
646
|
-
const blocklets = await this.getBlocklets({}, { meta: 1,
|
|
880
|
+
const blocklets = await this.getBlocklets({}, { meta: 1, ports: 1 });
|
|
647
881
|
const services = [];
|
|
648
882
|
|
|
649
883
|
blocklets.forEach((blocklet) => {
|
|
@@ -681,7 +915,7 @@ class BlockletState extends BaseState {
|
|
|
681
915
|
* @return {Object} { <did> : { interfaceName } }
|
|
682
916
|
*/
|
|
683
917
|
async groupAllInterfaces() {
|
|
684
|
-
const blocklets = await this.getBlocklets({}, { meta: 1
|
|
918
|
+
const blocklets = await this.getBlocklets({}, { meta: 1 });
|
|
685
919
|
const result = {};
|
|
686
920
|
const fillResult = (component, { id }) => {
|
|
687
921
|
const { interfaces } = component.meta;
|
|
@@ -701,6 +935,22 @@ class BlockletState extends BaseState {
|
|
|
701
935
|
return result;
|
|
702
936
|
}
|
|
703
937
|
|
|
938
|
+
/**
|
|
939
|
+
* Reset the blocklet state by clearing all blocklets and their children
|
|
940
|
+
* This overrides BaseState.reset() to handle foreign key constraints
|
|
941
|
+
*/
|
|
942
|
+
async reset() {
|
|
943
|
+
// First, delete all children to avoid foreign key constraint errors
|
|
944
|
+
if (this.BlockletChildState) {
|
|
945
|
+
const allBlocklets = await this.getBlocklets({}, { id: 1 });
|
|
946
|
+
for (const blocklet of allBlocklets) {
|
|
947
|
+
await this.BlockletChildState.deleteByParentId(blocklet.id);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
// Then call parent reset to clear the blocklets table
|
|
951
|
+
return super.reset();
|
|
952
|
+
}
|
|
953
|
+
|
|
704
954
|
/**
|
|
705
955
|
* @param {Did} did blocklet did
|
|
706
956
|
* @param {BlockletStatus} status blocklet status
|
|
@@ -764,14 +1014,17 @@ class BlockletState extends BaseState {
|
|
|
764
1014
|
|
|
765
1015
|
const shouldSetStatus = status === BlockletStatus.downloading || status === BlockletStatus.waiting;
|
|
766
1016
|
const updateData = {
|
|
767
|
-
children: doc.children,
|
|
768
1017
|
operator,
|
|
769
1018
|
};
|
|
770
1019
|
if (shouldSetStatus) {
|
|
771
1020
|
updateData.status = status;
|
|
772
1021
|
}
|
|
773
1022
|
|
|
1023
|
+
updateData.children = doc.children;
|
|
1024
|
+
|
|
774
1025
|
const res = await this.updateBlocklet(did, updateData);
|
|
1026
|
+
|
|
1027
|
+
res.children = doc.children;
|
|
775
1028
|
return res;
|
|
776
1029
|
} finally {
|
|
777
1030
|
await lock.releaseLock(lockName);
|
|
@@ -902,7 +1155,7 @@ class BlockletState extends BaseState {
|
|
|
902
1155
|
}
|
|
903
1156
|
|
|
904
1157
|
async _getOccupiedPorts() {
|
|
905
|
-
const blocklets = await this.getBlocklets({}, { port: 1, ports: 1, meta: 1
|
|
1158
|
+
const blocklets = await this.getBlocklets({}, { port: 1, ports: 1, meta: 1 });
|
|
906
1159
|
|
|
907
1160
|
const occupiedExternalPorts = new Map();
|
|
908
1161
|
const occupiedInternalPorts = new Map();
|
package/lib/states/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const logger = require('@abtnode/logger')('@abtnode/core:states');
|
|
|
4
4
|
|
|
5
5
|
const NodeState = require('./node');
|
|
6
6
|
const BlockletState = require('./blocklet');
|
|
7
|
+
const BlockletChildState = require('./blocklet-child');
|
|
7
8
|
const NotificationState = require('./notification');
|
|
8
9
|
const SiteState = require('./site');
|
|
9
10
|
const AccessKeyState = require('./access-key');
|
|
@@ -33,7 +34,8 @@ const init = (dataDirs, config = {}) => {
|
|
|
33
34
|
const notificationState = new NotificationState(models.Notification, config, models);
|
|
34
35
|
|
|
35
36
|
const nodeState = new NodeState(models.Server, config, dataDirs, notificationState);
|
|
36
|
-
const
|
|
37
|
+
const blockletChildState = new BlockletChildState(models.BlockletChild, config);
|
|
38
|
+
const blockletState = new BlockletState(models.Blocklet, { ...config, BlockletChildState: blockletChildState });
|
|
37
39
|
const siteState = new SiteState(models.Site, config);
|
|
38
40
|
const accessKeyState = new AccessKeyState(models.AccessKey, config);
|
|
39
41
|
const webhookState = new WebhookState(models.WebHook, config);
|
|
@@ -52,6 +54,7 @@ const init = (dataDirs, config = {}) => {
|
|
|
52
54
|
return {
|
|
53
55
|
node: nodeState,
|
|
54
56
|
blocklet: blockletState,
|
|
57
|
+
blockletChild: blockletChildState,
|
|
55
58
|
notification: notificationState,
|
|
56
59
|
site: siteState,
|
|
57
60
|
accessKey: accessKeyState,
|
package/lib/util/blocklet.js
CHANGED
|
@@ -416,36 +416,6 @@ const getBlockletConfigObj = (blocklet, { excludeSecure } = {}) => {
|
|
|
416
416
|
|
|
417
417
|
return obj;
|
|
418
418
|
};
|
|
419
|
-
/**
|
|
420
|
-
* set 'configs', configObj', 'environmentObj' to blocklet TODO
|
|
421
|
-
* @param {*} blocklet
|
|
422
|
-
* @param {*} configs
|
|
423
|
-
*/
|
|
424
|
-
const fillBlockletConfigs = (blocklet, configs) => {
|
|
425
|
-
blocklet.configs = configs || [];
|
|
426
|
-
blocklet.configObj = getBlockletConfigObj(blocklet);
|
|
427
|
-
blocklet.environments = blocklet.environments || [];
|
|
428
|
-
blocklet.environmentObj = blocklet.environments.reduce((acc, x) => {
|
|
429
|
-
acc[x.key] = templateReplace(x.value, blocklet);
|
|
430
|
-
return acc;
|
|
431
|
-
}, {});
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
const ensureBlockletExpanded = async (_meta, appDir) => {
|
|
435
|
-
const bundlePath = path.join(appDir, BLOCKLET_BUNDLE_FILE);
|
|
436
|
-
if (fs.existsSync(bundlePath)) {
|
|
437
|
-
try {
|
|
438
|
-
const nodeModulesPath = path.join(appDir, 'node_modules');
|
|
439
|
-
if (fs.existsSync(nodeModulesPath)) {
|
|
440
|
-
fs.removeSync(nodeModulesPath);
|
|
441
|
-
}
|
|
442
|
-
await expandBundle(bundlePath, appDir);
|
|
443
|
-
fs.removeSync(bundlePath);
|
|
444
|
-
} catch (err) {
|
|
445
|
-
throw new Error(`Failed to expand blocklet bundle: ${err.message}`);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
};
|
|
449
419
|
|
|
450
420
|
const getAppSystemEnvironments = (blocklet, nodeInfo, dataDirs) => {
|
|
451
421
|
const { did, name, title, description } = blocklet.meta;
|
|
@@ -562,6 +532,81 @@ const getComponentSystemEnvironments = (blocklet) => {
|
|
|
562
532
|
};
|
|
563
533
|
};
|
|
564
534
|
|
|
535
|
+
/**
|
|
536
|
+
* set 'configs', configObj', 'environmentObj' to blocklet TODO
|
|
537
|
+
* @param {*} blocklet
|
|
538
|
+
* @param {*} configs
|
|
539
|
+
* @param {*} options - Optional: { rootBlocklet, nodeInfo, dataDirs }
|
|
540
|
+
*/
|
|
541
|
+
const fillBlockletConfigs = (blocklet, configs, options = {}) => {
|
|
542
|
+
blocklet.configs = configs || [];
|
|
543
|
+
blocklet.configObj = getBlockletConfigObj(blocklet);
|
|
544
|
+
blocklet.environments = blocklet.environments || [];
|
|
545
|
+
blocklet.environmentObj = blocklet.environments.reduce((acc, x) => {
|
|
546
|
+
acc[x.key] = templateReplace(x.value, blocklet);
|
|
547
|
+
return acc;
|
|
548
|
+
}, {});
|
|
549
|
+
|
|
550
|
+
// After migration: ensure all component system environments are set from blocklet.env if available
|
|
551
|
+
// This ensures children loaded from blocklet_children table have all required env vars in environmentObj
|
|
552
|
+
if (blocklet.env) {
|
|
553
|
+
try {
|
|
554
|
+
const componentSystemEnvs = getComponentSystemEnvironments(blocklet);
|
|
555
|
+
// Only set env vars that are not already set
|
|
556
|
+
Object.entries(componentSystemEnvs).forEach(([key, value]) => {
|
|
557
|
+
if (value !== undefined && value !== null && !blocklet.environmentObj[key]) {
|
|
558
|
+
blocklet.environmentObj[key] = value;
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
} catch (error) {
|
|
562
|
+
// If getting component system environments fails, log warning but continue
|
|
563
|
+
logger.warn('fillBlockletConfigs: failed to get component system environments', {
|
|
564
|
+
blockletDid: blocklet.meta?.did,
|
|
565
|
+
error: error.message,
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// For children: also set app-level environment variables from root blocklet
|
|
571
|
+
// This ensures children have app-level env vars like BLOCKLET_APP_ID
|
|
572
|
+
const { rootBlocklet, nodeInfo, dataDirs } = options;
|
|
573
|
+
if (rootBlocklet && nodeInfo && dataDirs && blocklet !== rootBlocklet) {
|
|
574
|
+
try {
|
|
575
|
+
const appSystemEnvs = getAppSystemEnvironments(rootBlocklet, nodeInfo, dataDirs);
|
|
576
|
+
const appOverwrittenEnvs = getAppOverwrittenEnvironments(rootBlocklet, nodeInfo);
|
|
577
|
+
// Only set env vars that are not already set
|
|
578
|
+
Object.entries({ ...appSystemEnvs, ...appOverwrittenEnvs }).forEach(([key, value]) => {
|
|
579
|
+
if (value !== undefined && value !== null && !blocklet.environmentObj[key]) {
|
|
580
|
+
blocklet.environmentObj[key] = value;
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
} catch (error) {
|
|
584
|
+
// If getting app system environments fails, log warning but continue
|
|
585
|
+
logger.warn('fillBlockletConfigs: failed to get app system environments', {
|
|
586
|
+
blockletDid: blocklet.meta?.did,
|
|
587
|
+
rootDid: rootBlocklet.meta?.did,
|
|
588
|
+
error: error.message,
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
const ensureBlockletExpanded = async (_meta, appDir) => {
|
|
595
|
+
const bundlePath = path.join(appDir, BLOCKLET_BUNDLE_FILE);
|
|
596
|
+
if (fs.existsSync(bundlePath)) {
|
|
597
|
+
try {
|
|
598
|
+
const nodeModulesPath = path.join(appDir, 'node_modules');
|
|
599
|
+
if (fs.existsSync(nodeModulesPath)) {
|
|
600
|
+
fs.removeSync(nodeModulesPath);
|
|
601
|
+
}
|
|
602
|
+
await expandBundle(bundlePath, appDir);
|
|
603
|
+
fs.removeSync(bundlePath);
|
|
604
|
+
} catch (err) {
|
|
605
|
+
throw new Error(`Failed to expand blocklet bundle: ${err.message}`);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
|
|
565
610
|
const getRuntimeEnvironments = (blocklet, nodeEnvironments, ancestors, isGreen = false) => {
|
|
566
611
|
const root = (ancestors || [])[0] || blocklet;
|
|
567
612
|
|
|
@@ -1970,21 +2015,44 @@ const _getBlocklet = async ({
|
|
|
1970
2015
|
|
|
1971
2016
|
await forEachBlocklet(blocklet, async (component, { id, level, ancestors }) => {
|
|
1972
2017
|
// component env
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
2018
|
+
try {
|
|
2019
|
+
// Validate component has required meta fields for getComponentDirs
|
|
2020
|
+
if (!component.meta) {
|
|
2021
|
+
throw new Error(`Component missing meta field: ${component.meta?.did || id}`);
|
|
2022
|
+
}
|
|
2023
|
+
if (!component.meta.name && !component.meta.bundleName) {
|
|
2024
|
+
throw new Error(
|
|
2025
|
+
`Component missing meta.name and meta.bundleName: ${component.meta.did || id}. ` +
|
|
2026
|
+
'This may indicate a migration issue with blocklet_children table.'
|
|
2027
|
+
);
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
component.env = {
|
|
2031
|
+
id,
|
|
2032
|
+
name: getComponentName(component, ancestors),
|
|
2033
|
+
processId: getComponentProcessId(component, ancestors),
|
|
2034
|
+
...getComponentDirs(component, {
|
|
2035
|
+
dataDirs,
|
|
2036
|
+
ensure: ensureIntegrity,
|
|
2037
|
+
ancestors,
|
|
2038
|
+
e2eMode: level === 0 ? e2eMode : false,
|
|
2039
|
+
}),
|
|
2040
|
+
};
|
|
2041
|
+
} catch (error) {
|
|
2042
|
+
logger.error('Failed to set component env in _getBlocklet', {
|
|
2043
|
+
componentDid: component.meta?.did,
|
|
2044
|
+
componentName: component.meta?.name,
|
|
2045
|
+
componentBundleName: component.meta?.bundleName,
|
|
2046
|
+
error: error.message,
|
|
2047
|
+
stack: error.stack,
|
|
2048
|
+
});
|
|
2049
|
+
throw error;
|
|
2050
|
+
}
|
|
1984
2051
|
|
|
1985
2052
|
// component config
|
|
1986
2053
|
const configs = await states.blockletExtras.getConfigs([...ancestors.map((x) => x.meta.did), component.meta.did]);
|
|
1987
|
-
|
|
2054
|
+
const rootBlocklet = ancestors.length > 0 ? ancestors[0] : blocklet;
|
|
2055
|
+
fillBlockletConfigs(component, configs, { rootBlocklet, nodeInfo, dataDirs });
|
|
1988
2056
|
});
|
|
1989
2057
|
|
|
1990
2058
|
if (getOptionalComponents) {
|
|
@@ -2052,7 +2120,7 @@ const getConfigFromPreferences = (blocklet) => {
|
|
|
2052
2120
|
return result;
|
|
2053
2121
|
};
|
|
2054
2122
|
|
|
2055
|
-
const shouldEnableSlpDomain = (
|
|
2123
|
+
const shouldEnableSlpDomain = (mode) => {
|
|
2056
2124
|
if (process.env.ABT_NODE_ENABLE_SLP_DOMAIN === 'true') {
|
|
2057
2125
|
return true;
|
|
2058
2126
|
}
|
|
@@ -2061,11 +2129,11 @@ const shouldEnableSlpDomain = ({ mode, launcher }) => {
|
|
|
2061
2129
|
return false;
|
|
2062
2130
|
}
|
|
2063
2131
|
|
|
2064
|
-
return isInServerlessMode({ mode })
|
|
2132
|
+
return isInServerlessMode({ mode });
|
|
2065
2133
|
};
|
|
2066
2134
|
|
|
2067
2135
|
const getBlockletURLForLauncher = ({ blocklet, nodeInfo }) => {
|
|
2068
|
-
const enableSlpDomain = shouldEnableSlpDomain(
|
|
2136
|
+
const enableSlpDomain = shouldEnableSlpDomain(nodeInfo.mode);
|
|
2069
2137
|
let didDomain = '';
|
|
2070
2138
|
if (enableSlpDomain) {
|
|
2071
2139
|
didDomain = getDidDomainForBlocklet({
|
|
@@ -2464,10 +2532,7 @@ const getBlockletDidDomainList = (blocklet, nodeInfo) => {
|
|
|
2464
2532
|
});
|
|
2465
2533
|
|
|
2466
2534
|
// eslint-disable-next-line no-use-before-define
|
|
2467
|
-
const enableSlpDomain = shouldEnableSlpDomain(
|
|
2468
|
-
mode: nodeInfo.mode,
|
|
2469
|
-
launcher: nodeInfo.launcher,
|
|
2470
|
-
});
|
|
2535
|
+
const enableSlpDomain = shouldEnableSlpDomain(nodeInfo.mode);
|
|
2471
2536
|
if (enableSlpDomain) {
|
|
2472
2537
|
// eslint-disable-next-line no-use-before-define
|
|
2473
2538
|
const slpDid = getSlpDid(nodeInfo.did, blocklet.appPid);
|
|
@@ -2672,10 +2737,10 @@ const getSlpDid = (serverDid, appPid) => {
|
|
|
2672
2737
|
const updateDidDocument = async ({ blocklet, nodeInfo }) => {
|
|
2673
2738
|
const alsoKnownAs = getBlockletKnownAs(blocklet);
|
|
2674
2739
|
const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
|
|
2675
|
-
const { mode,
|
|
2740
|
+
const { mode, did: serverDid } = nodeInfo;
|
|
2676
2741
|
|
|
2677
2742
|
let slpDid = null;
|
|
2678
|
-
const enableSlpDomain = shouldEnableSlpDomain(
|
|
2743
|
+
const enableSlpDomain = shouldEnableSlpDomain(mode);
|
|
2679
2744
|
if (enableSlpDomain) {
|
|
2680
2745
|
slpDid = getSlpDid(serverDid, blocklet.appPid);
|
|
2681
2746
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { BLOCKLET_LAUNCHER_URL, BLOCKLET_STORE, BLOCKLET_STORE_DEV } = require('@abtnode/constant');
|
|
1
|
+
const { BLOCKLET_LAUNCHER_URL, BLOCKLET_STORE, BLOCKLET_STORE_DEV, BLOCKLET_TEST_STORE } = require('@abtnode/constant');
|
|
2
2
|
const canPackageReadWrite = require('@abtnode/util/lib/can-pkg-rw');
|
|
3
3
|
|
|
4
4
|
const getDefaultAutoUpgrade = () => {
|
|
@@ -24,6 +24,10 @@ const defaultNodeConfigs = {
|
|
|
24
24
|
...BLOCKLET_STORE_DEV,
|
|
25
25
|
protected: false,
|
|
26
26
|
},
|
|
27
|
+
{
|
|
28
|
+
...BLOCKLET_TEST_STORE,
|
|
29
|
+
protected: false,
|
|
30
|
+
},
|
|
27
31
|
],
|
|
28
32
|
},
|
|
29
33
|
registerUrl: { getDefaultValue: () => BLOCKLET_LAUNCHER_URL },
|