@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.
@@ -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
- return doc ? formatBlocklet(doc, 'onRead', decryptSk ? this.config.dek : null) : null;
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
- return docs.filter(Boolean).map((doc) => formatBlocklet(doc, 'onRead', this.config.dek));
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
- children: blocklet.children,
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, children: 1, ports: 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, children: 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, children: 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();
@@ -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 blockletState = new BlockletState(models.Blocklet, config);
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,
@@ -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
- component.env = {
1974
- id,
1975
- name: getComponentName(component, ancestors),
1976
- processId: getComponentProcessId(component, ancestors),
1977
- ...getComponentDirs(component, {
1978
- dataDirs,
1979
- ensure: ensureIntegrity,
1980
- ancestors,
1981
- e2eMode: level === 0 ? e2eMode : false,
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
- fillBlockletConfigs(component, configs);
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 = ({ mode, launcher }) => {
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 }) && !!launcher;
2132
+ return isInServerlessMode({ mode });
2065
2133
  };
2066
2134
 
2067
2135
  const getBlockletURLForLauncher = ({ blocklet, nodeInfo }) => {
2068
- const enableSlpDomain = shouldEnableSlpDomain({ mode: nodeInfo.mode, launcher: nodeInfo.launcher });
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, launcher, did: serverDid } = nodeInfo;
2740
+ const { mode, did: serverDid } = nodeInfo;
2676
2741
 
2677
2742
  let slpDid = null;
2678
- const enableSlpDomain = shouldEnableSlpDomain({ mode, launcher });
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 },