@fugood/bricks-project 2.23.0 → 2.23.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/compile/action-name-map.ts +26 -0
  2. package/compile/index.ts +353 -130
  3. package/package.json +6 -4
  4. package/skills/bricks-project/rules/automations.md +74 -28
  5. package/tools/deploy.ts +39 -10
  6. package/tools/mcp-server.ts +21 -13
  7. package/tools/postinstall.ts +53 -6
  8. package/tools/preview-main.mjs +8 -7
  9. package/tools/preview.ts +1 -1
  10. package/tsconfig.json +16 -0
  11. package/types/bricks/Camera.ts +1 -1
  12. package/types/bricks/Chart.ts +1 -1
  13. package/types/bricks/GenerativeMedia.ts +1 -1
  14. package/types/bricks/Icon.ts +1 -1
  15. package/types/bricks/Image.ts +1 -1
  16. package/types/bricks/Items.ts +1 -1
  17. package/types/bricks/Lottie.ts +1 -1
  18. package/types/bricks/Maps.ts +1 -1
  19. package/types/bricks/QrCode.ts +1 -1
  20. package/types/bricks/Rect.ts +1 -1
  21. package/types/bricks/RichText.ts +1 -1
  22. package/types/bricks/Rive.ts +1 -1
  23. package/types/bricks/Slideshow.ts +1 -1
  24. package/types/bricks/Svg.ts +1 -1
  25. package/types/bricks/Text.ts +1 -1
  26. package/types/bricks/TextInput.ts +1 -1
  27. package/types/bricks/Video.ts +1 -1
  28. package/types/bricks/VideoStreaming.ts +1 -1
  29. package/types/bricks/WebRtcStream.ts +1 -1
  30. package/types/bricks/WebView.ts +1 -1
  31. package/types/canvas.ts +2 -2
  32. package/types/common.ts +4 -4
  33. package/types/generators/AlarmClock.ts +1 -1
  34. package/types/generators/Assistant.ts +1 -1
  35. package/types/generators/BleCentral.ts +1 -1
  36. package/types/generators/BlePeripheral.ts +1 -1
  37. package/types/generators/CanvasMap.ts +1 -1
  38. package/types/generators/CastlesPay.ts +1 -1
  39. package/types/generators/DataBank.ts +1 -1
  40. package/types/generators/File.ts +1 -1
  41. package/types/generators/GraphQl.ts +1 -1
  42. package/types/generators/Http.ts +1 -1
  43. package/types/generators/HttpServer.ts +1 -1
  44. package/types/generators/Information.ts +1 -1
  45. package/types/generators/Intent.ts +1 -1
  46. package/types/generators/Iterator.ts +1 -1
  47. package/types/generators/Keyboard.ts +1 -1
  48. package/types/generators/LlmAnthropicCompat.ts +1 -1
  49. package/types/generators/LlmAppleBuiltin.ts +1 -1
  50. package/types/generators/LlmGgml.ts +1 -1
  51. package/types/generators/LlmOnnx.ts +1 -1
  52. package/types/generators/LlmOpenAiCompat.ts +1 -1
  53. package/types/generators/LlmQualcommAiEngine.ts +1 -1
  54. package/types/generators/Mcp.ts +1 -1
  55. package/types/generators/McpServer.ts +1 -1
  56. package/types/generators/MediaFlow.ts +1 -1
  57. package/types/generators/MqttBroker.ts +1 -1
  58. package/types/generators/MqttClient.ts +1 -1
  59. package/types/generators/Question.ts +1 -1
  60. package/types/generators/RealtimeTranscription.ts +15 -7
  61. package/types/generators/RerankerGgml.ts +1 -1
  62. package/types/generators/SerialPort.ts +1 -1
  63. package/types/generators/SoundPlayer.ts +1 -1
  64. package/types/generators/SoundRecorder.ts +1 -1
  65. package/types/generators/SpeechToTextGgml.ts +6 -1
  66. package/types/generators/SpeechToTextOnnx.ts +1 -1
  67. package/types/generators/SpeechToTextPlatform.ts +1 -1
  68. package/types/generators/SqLite.ts +1 -1
  69. package/types/generators/Step.ts +1 -1
  70. package/types/generators/SttAppleBuiltin.ts +1 -1
  71. package/types/generators/Tcp.ts +1 -1
  72. package/types/generators/TcpServer.ts +1 -1
  73. package/types/generators/TextToSpeechAppleBuiltin.ts +1 -1
  74. package/types/generators/TextToSpeechGgml.ts +1 -1
  75. package/types/generators/TextToSpeechOnnx.ts +1 -1
  76. package/types/generators/TextToSpeechOpenAiLike.ts +1 -1
  77. package/types/generators/ThermalPrinter.ts +1 -1
  78. package/types/generators/Tick.ts +1 -1
  79. package/types/generators/Udp.ts +1 -1
  80. package/types/generators/VadGgml.ts +1 -1
  81. package/types/generators/VadOnnx.ts +201 -0
  82. package/types/generators/VadTraditional.ts +123 -0
  83. package/types/generators/VectorStore.ts +1 -1
  84. package/types/generators/Watchdog.ts +1 -1
  85. package/types/generators/WebCrawler.ts +1 -1
  86. package/types/generators/WebRtc.ts +1 -1
  87. package/types/generators/WebSocket.ts +1 -1
  88. package/types/generators/index.ts +2 -0
  89. package/utils/calc.ts +16 -8
  90. package/utils/event-props.ts +27 -0
  91. package/utils/id.ts +4 -0
  92. package/api/index.ts +0 -1
  93. package/api/instance.ts +0 -213
package/compile/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable no-underscore-dangle -- Uses __typename, __actionName, etc. for type system */
2
- import _ from 'lodash'
2
+ import snakeCase from 'lodash/snakeCase'
3
+ import omit from 'lodash/omit'
3
4
  import { parse as parseAST } from 'acorn'
4
5
  import type { ExportNamedDeclaration, FunctionDeclaration } from 'acorn'
5
6
  import escodegen from 'escodegen'
@@ -33,6 +34,40 @@ import type {
33
34
  TestVariable,
34
35
  } from '../types'
35
36
 
37
+ const uuidPattern = '[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}'
38
+
39
+ const entryIdPatterns = {
40
+ SUBSPACE: new RegExp(`^SUBSPACE_${uuidPattern}$`),
41
+ CANVAS: new RegExp(`^CANVAS_${uuidPattern}$`),
42
+ BRICK: new RegExp(`^BRICK_${uuidPattern}$`),
43
+ GENERATOR: new RegExp(`^(GENERATOR|AUTO_GENERATOR)_${uuidPattern}$`),
44
+ ANIMATION: new RegExp(`^ANIMATION_${uuidPattern}$`),
45
+ PROPERTY_BANK_DATA_NODE: new RegExp(`^PROPERTY_BANK_DATA_NODE_${uuidPattern}$`),
46
+ PROPERTY_BANK_COMMAND_NODE: new RegExp(`^PROPERTY_BANK_COMMAND_NODE_${uuidPattern}$`),
47
+ PROPERTY_BANK_COMMAND_MAP: new RegExp(`^PROPERTY_BANK_COMMAND_MAP_${uuidPattern}$`),
48
+ BRICK_STATE_GROUP: new RegExp(`^BRICK_STATE_GROUP_${uuidPattern}$`),
49
+ TEST: new RegExp(`^TEST_${uuidPattern}$`),
50
+ TEST_CASE: new RegExp(`^TEST_CASE_${uuidPattern}$`),
51
+ TEST_VAR: new RegExp(`^TEST_VAR_${uuidPattern}$`),
52
+ AUTOMATION_MAP: /^AUTOMATION_MAP_.*/,
53
+ } as const
54
+
55
+ type EntryIdPatternKey = keyof typeof entryIdPatterns
56
+
57
+ const assertEntryId = (
58
+ id: unknown,
59
+ patternKey: EntryIdPatternKey,
60
+ errorReference: string = '',
61
+ ): string => {
62
+ const pattern = entryIdPatterns[patternKey]
63
+ if (typeof id !== 'string' || !pattern.test(id)) {
64
+ throw new Error(
65
+ `Invalid ${patternKey} id${errorReference ? ` ${errorReference}` : ''}: ${String(id)}`,
66
+ )
67
+ }
68
+ return id
69
+ }
70
+
36
71
  const compileProperty = (property, errorReference: string, result = {}) => {
37
72
  if (Array.isArray(property)) {
38
73
  return property.map((p) => compileProperty(p, errorReference))
@@ -70,7 +105,7 @@ const compileEventActionValue = (templateKey, eventKey, value, errorReference) =
70
105
  }
71
106
 
72
107
  const convertOutletKey = (templateKey: string, key: string) =>
73
- `${templateKey}_${_.snakeCase(key).toUpperCase()}`
108
+ `${templateKey}_${snakeCase(key).toUpperCase()}`
74
109
 
75
110
  const compileOutlets = (
76
111
  templateKey: string,
@@ -78,13 +113,14 @@ const compileOutlets = (
78
113
  errorReference: string,
79
114
  ) =>
80
115
  Object.entries(outlets).reduce((acc, [key, data]) => {
81
- if (!data()?.id) throw new Error(`Invalid data reference ${errorReference}`)
82
- acc[convertOutletKey(templateKey, key)] = data().id
116
+ const dataInstance = data?.()
117
+ const dataId = assertEntryId(dataInstance?.id, 'PROPERTY_BANK_DATA_NODE', errorReference)
118
+ acc[convertOutletKey(templateKey, key)] = dataId
83
119
  return acc
84
120
  }, {})
85
121
 
86
122
  const convertEventKey = (templateKey: string, key: string) =>
87
- `${templateKey ? `${templateKey}_` : ''}${_.snakeCase(key).toUpperCase()}`
123
+ `${templateKey ? `${templateKey}_` : ''}${snakeCase(key).toUpperCase()}`
88
124
 
89
125
  const basicAnimationEvents = ['show', 'standby', 'breatheStart']
90
126
 
@@ -94,9 +130,9 @@ const compileAnimations = (
94
130
  errorReference: string,
95
131
  ) =>
96
132
  Object.entries(animations).reduce((acc, [key, animation]) => {
97
- if (!animation?.id) throw new Error(`Invalid animation reference ${errorReference}`)
133
+ const animationId = assertEntryId(animation?.id, 'ANIMATION', errorReference)
98
134
  acc[convertEventKey(basicAnimationEvents.includes(key) ? 'BRICK' : templateKey, key)] =
99
- `ANIMATION#${animation.id}`
135
+ `ANIMATION#${animationId}`
100
136
  return acc
101
137
  }, {})
102
138
 
@@ -380,59 +416,120 @@ const compileTestVariable = (variable: TestVariable) => ({
380
416
  */
381
417
  const arrayToIdMap = <T extends { id: string }, R>(
382
418
  items: T[],
383
- transform: (item: T) => R,
384
- ): Record<string, R> => Object.fromEntries(items.map((item) => [item.id, transform(item)]))
419
+ transform: (item: T, index: number) => R,
420
+ options: {
421
+ patternKey: EntryIdPatternKey
422
+ getErrorReference: (item: T, index: number) => string
423
+ },
424
+ ): Record<string, R> =>
425
+ Object.fromEntries(
426
+ items.map((item, index) => {
427
+ const itemId = assertEntryId(
428
+ item.id,
429
+ options.patternKey,
430
+ options.getErrorReference(item, index),
431
+ )
432
+ return [itemId, transform(item, index)]
433
+ }),
434
+ )
385
435
 
386
436
  /**
387
437
  * Compile typed AutomationTest to raw format
388
438
  */
389
- const compileAutomationTest = (test: AutomationTest) => ({
390
- id: test.id,
391
- title: test.title,
392
- timeout: test.timeout,
393
- trigger_type: test.trigger_type,
394
- cron: test.cron,
395
- skip_trigger_type_check: test.skip_trigger_type_check,
396
- local_sync: test.local_sync,
397
- meta: test.meta,
398
- case_map: arrayToIdMap(test.cases, compileTestCase),
399
- var_map: arrayToIdMap(test.variables, compileTestVariable),
400
- })
439
+ const compileAutomationTest = (
440
+ test: AutomationTest,
441
+ options: { mapId: string; testIndex: number },
442
+ ) => {
443
+ const testId = assertEntryId(
444
+ test.id,
445
+ 'TEST',
446
+ `(automation map: ${options.mapId}, test index: ${options.testIndex})`,
447
+ )
448
+
449
+ return {
450
+ id: testId,
451
+ title: test.title,
452
+ timeout: test.timeout,
453
+ trigger_type: test.trigger_type,
454
+ cron: test.cron,
455
+ skip_trigger_type_check: test.skip_trigger_type_check,
456
+ local_sync: test.local_sync,
457
+ meta: test.meta,
458
+ case_map: arrayToIdMap(test.cases, compileTestCase, {
459
+ patternKey: 'TEST_CASE',
460
+ getErrorReference: (_, index) =>
461
+ `(automation map: ${options.mapId}, test: ${testId}, case index: ${index})`,
462
+ }),
463
+ var_map: arrayToIdMap(test.variables, compileTestVariable, {
464
+ patternKey: 'TEST_VAR',
465
+ getErrorReference: (_, index) =>
466
+ `(automation map: ${options.mapId}, test: ${testId}, variable index: ${index})`,
467
+ }),
468
+ }
469
+ }
401
470
 
402
471
  /**
403
472
  * Compile typed AutomationTestMap to raw format
404
473
  */
405
- const compileAutomationTestMap = (testMap: AutomationTestMap) => ({
406
- title: testMap.title,
407
- createdAt: testMap.createdAt,
408
- map: arrayToIdMap(testMap.tests, compileAutomationTest),
409
- })
474
+ const compileAutomationTestMap = (testMap: AutomationTestMap, mapId: string) => {
475
+ assertEntryId(testMap.id, 'AUTOMATION_MAP', `(automation map id field: ${mapId})`)
476
+
477
+ return {
478
+ title: testMap.title,
479
+ createdAt: testMap.createdAt,
480
+ map: arrayToIdMap(
481
+ testMap.tests,
482
+ (test, index) => compileAutomationTest(test, { mapId, testIndex: index }),
483
+ {
484
+ patternKey: 'TEST',
485
+ getErrorReference: (_, index) => `(automation map: ${mapId}, test index: ${index})`,
486
+ },
487
+ ),
488
+ }
489
+ }
410
490
 
411
491
  /**
412
492
  * Compile typed AutomationMap to raw automation_map format
413
493
  */
414
494
  const compileAutomation = (automationMap: AutomationMap) =>
415
495
  Object.fromEntries(
416
- Object.entries(automationMap).map(([mapId, testMap]) => [
417
- mapId,
418
- compileAutomationTestMap(testMap),
419
- ]),
496
+ Object.entries(automationMap).map(([mapId, testMap]) => {
497
+ const automationMapId = assertEntryId(mapId, 'AUTOMATION_MAP', '(automation map key)')
498
+ return [automationMapId, compileAutomationTestMap(testMap, automationMapId)]
499
+ }),
420
500
  )
421
501
 
422
502
  export const compile = async (app: Application) => {
423
503
  await new Promise((resolve) => setImmediate(resolve, 0))
504
+ const timestamp = Date.now()
424
505
  const config = {
425
- title: app.name,
426
- subspace_map: app.subspaces.reduce((subspaceMap, subspace) => {
427
- subspaceMap[subspace.id] = {
506
+ title: `${app.name || 'Unknown'}(${timestamp})`,
507
+ subspace_map: app.subspaces.reduce((subspaceMap, subspace, subspaceIndex) => {
508
+ const subspaceId = assertEntryId(
509
+ subspace.id,
510
+ 'SUBSPACE',
511
+ `(subspace index: ${subspaceIndex})`,
512
+ )
513
+ const rootCanvasId = assertEntryId(
514
+ subspace.rootCanvas?.id,
515
+ 'CANVAS',
516
+ `(subspace: ${subspaceId}, root canvas)`,
517
+ )
518
+
519
+ subspaceMap[subspaceId] = {
428
520
  title: subspace.title,
429
521
  description: subspace.description,
430
522
  _expanded: subspace.unexpanded
431
523
  ? {
432
524
  brick: !subspace.unexpanded.brick,
433
525
  generator: !subspace.unexpanded.generator,
434
- canvas: subspace.unexpanded.canvas?.reduce((acc, canvas) => {
435
- acc[canvas.id] = !canvas?.id
526
+ canvas: subspace.unexpanded.canvas?.reduce((acc, canvas, canvasIndex) => {
527
+ const unexpandedCanvasId = assertEntryId(
528
+ canvas?.id,
529
+ 'CANVAS',
530
+ `(subspace: ${subspaceId}, unexpanded canvas index: ${canvasIndex})`,
531
+ )
532
+ acc[unexpandedCanvasId] = !canvas?.id
436
533
  return acc
437
534
  }, {}),
438
535
  property_bank: !subspace.unexpanded.data,
@@ -449,23 +546,29 @@ export const compile = async (app: Application) => {
449
546
  change_canvas: subspace.localSyncChangeCanvas,
450
547
  }
451
548
  : undefined,
452
- animation_map: subspace.animations.reduce((map, animation) => {
549
+ animation_map: subspace.animations.reduce((map, animation, animationIndex) => {
550
+ const animationId = assertEntryId(
551
+ animation?.id,
552
+ 'ANIMATION',
553
+ `(animation index: ${animationIndex}, subspace: ${subspaceId})`,
554
+ )
555
+
453
556
  if (animation.__typename === 'Animation') {
454
557
  const animationDef = animation as AnimationDef
455
- map[animationDef.id] = {
558
+ map[animationId] = {
456
559
  title: animationDef.title,
457
560
  description: animationDef.description,
458
561
  animationRunType: animationDef.runType,
459
562
  property: animationDef.property,
460
563
  type: animationTypeMap[animationDef.config.__type],
461
564
  config: compileProperty(
462
- _.omit(animationDef.config, '__type'),
463
- `(animation: ${animation.id}, subspace ${subspace.id})`,
565
+ omit(animationDef.config, '__type'),
566
+ `(animation: ${animationId}, subspace ${subspaceId})`,
464
567
  ),
465
568
  }
466
569
  } else if (animation.__typename === 'AnimationCompose') {
467
570
  const animationDef = animation as AnimationComposeDef
468
- map[animationDef.id] = {
571
+ map[animationId] = {
469
572
  title: animationDef.title,
470
573
  description: animationDef.description,
471
574
  animationRunType: animationDef.runType,
@@ -474,7 +577,7 @@ export const compile = async (app: Application) => {
474
577
  const innerAnimation = item()
475
578
  if (!innerAnimation?.id)
476
579
  throw new Error(
477
- `Invalid animation index: ${index} (animation: ${innerAnimation.id}, subspace ${subspace.id})`,
580
+ `Invalid animation index: ${index} (animation: ${innerAnimation.id}, subspace ${subspaceId})`,
478
581
  )
479
582
  return { animation_id: innerAnimation.id }
480
583
  }),
@@ -482,10 +585,15 @@ export const compile = async (app: Application) => {
482
585
  }
483
586
  return map
484
587
  }, {}),
485
- brick_map: subspace.bricks.reduce((map, brick) => {
588
+ brick_map: subspace.bricks.reduce((map, brick, brickIndex) => {
589
+ const brickId = assertEntryId(
590
+ brick.id,
591
+ 'BRICK',
592
+ `(brick index: ${brickIndex}, subspace: ${subspaceId})`,
593
+ )
486
594
  const property = compileProperty(
487
595
  brick.property || {},
488
- `(brick: ${brick.id}, subspace ${subspace.id})`,
596
+ `(brick: ${brickId}, subspace ${subspaceId})`,
489
597
  )
490
598
  if (brick.templateKey === 'BRICK_ITEMS') {
491
599
  const brickItems = brick as BrickItems
@@ -497,25 +605,31 @@ export const compile = async (app: Application) => {
497
605
  frame: itemBrick.frame,
498
606
  property: compileProperty(
499
607
  itemBrick.property,
500
- `(brick: ${brick.id}, ${key}: ${index}, subspace ${subspace.id})`,
608
+ `(brick: ${brickId}, ${key}: ${index}, subspace ${subspaceId})`,
501
609
  ),
502
610
  propertyMapping: itemBrick.propertyMapping,
503
611
  animation: compileAnimations(
504
612
  itemBrick.templateKey,
505
613
  itemBrick.animation || {},
506
- `(brick: ${brick.id}, ${key}: ${index}, subspace ${subspace.id})`,
614
+ `(brick: ${brickId}, ${key}: ${index}, subspace ${subspaceId})`,
507
615
  ),
508
616
  outlet: compileOutlets(
509
617
  itemBrick.templateKey,
510
618
  itemBrick.outlets || {},
511
- `(brick: ${brick.id}, ${key}: ${index}, subspace ${subspace.id})`,
619
+ `(brick: ${brickId}, ${key}: ${index}, subspace ${subspaceId})`,
512
620
  ),
513
621
  eventMap: compileEvents(itemBrick.templateKey, itemBrick.eventMap || {}, {
514
622
  camelCase: true,
515
- errorReference: `(brick: ${brick.id}, ${key}: ${index}, subspace ${subspace.id})`,
623
+ errorReference: `(brick: ${brickId}, ${key}: ${index}, subspace ${subspaceId})`,
516
624
  }),
517
- stateGroup: itemBrick.stateGroup.reduce((acc, stateGroup) => {
518
- acc[stateGroup.id] = {
625
+ stateGroup: itemBrick.stateGroup.reduce((acc, stateGroup, stateGroupIndex) => {
626
+ const stateGroupId = assertEntryId(
627
+ stateGroup.id,
628
+ 'BRICK_STATE_GROUP',
629
+ `(brick: ${brickId}, ${key}: ${index}, switch index: ${stateGroupIndex}, subspace ${subspaceId})`,
630
+ )
631
+
632
+ acc[stateGroupId] = {
519
633
  title: stateGroup.title,
520
634
  description: stateGroup.description,
521
635
  override: stateGroup.override,
@@ -524,29 +638,32 @@ export const compile = async (app: Application) => {
524
638
  conds: compileSwitchConds(
525
639
  itemBrick.templateKey,
526
640
  stateGroup.conds || [],
527
- `(brick: ${brick.id}, ${key}: ${index}, switch: ${stateGroup.id}, subspace ${subspace.id})`,
641
+ `(brick: ${brickId}, ${key}: ${index}, switch: ${stateGroupId}, subspace ${subspaceId})`,
528
642
  ),
529
643
  property: compileProperty(
530
644
  stateGroup.property,
531
- `(brick: ${brick.id}, ${key}: ${index}, switch: ${stateGroup.id}, subspace ${subspace.id})`,
645
+ `(brick: ${brickId}, ${key}: ${index}, switch: ${stateGroupId}, subspace ${subspaceId})`,
532
646
  ),
533
647
  animation: compileAnimations(
534
648
  itemBrick.templateKey,
535
649
  stateGroup.animation || {},
536
- `(brick: ${brick.id}, ${key}: ${index}, switch: ${stateGroup.id}, subspace ${subspace.id})`,
650
+ `(brick: ${brickId}, ${key}: ${index}, switch: ${stateGroupId}, subspace ${subspaceId})`,
537
651
  ),
538
652
  outlet: compileOutlets(
539
653
  itemBrick.templateKey,
540
654
  stateGroup.outlets || {},
541
- `(brick: ${brick.id}, ${key}: ${index}, switch: ${stateGroup.id}, subspace ${subspace.id})`,
655
+ `(brick: ${brickId}, ${key}: ${index}, switch: ${stateGroupId}, subspace ${subspaceId})`,
542
656
  ),
543
657
  eventMap: compileEvents(itemBrick.templateKey, stateGroup.eventMap || {}, {
544
658
  camelCase: true,
545
- errorReference: `(brick: ${brick.id}, ${key}: ${index}, switch: ${stateGroup.id}, subspace ${subspace.id})`,
659
+ errorReference: `(brick: ${brickId}, ${key}: ${index}, switch: ${stateGroupId}, subspace ${subspaceId})`,
546
660
  }),
547
661
  }
548
662
  return acc
549
663
  }, {}),
664
+ show: itemBrick.show,
665
+ pressToOpenDetail: itemBrick.pressToOpenDetail,
666
+ pressToBackList: itemBrick.pressToBackList,
550
667
  })
551
668
  if (Array.isArray(brickItems.brickList)) {
552
669
  const brickList = (brickItems.brickList || []).map((item, index) =>
@@ -567,7 +684,7 @@ export const compile = async (app: Application) => {
567
684
  throw new TypeError('Not supported Data for brickList directly')
568
685
  }
569
686
  }
570
- map[brick.id] = {
687
+ map[brickId] = {
571
688
  template_key: brick.templateKey,
572
689
  title: brick.title,
573
690
  description: brick.description,
@@ -575,19 +692,25 @@ export const compile = async (app: Application) => {
575
692
  animation: compileAnimations(
576
693
  brick.templateKey,
577
694
  brick.animation || {},
578
- `(brick: ${brick.id}, subspace ${subspace.id})`,
695
+ `(brick: ${brickId}, subspace ${subspaceId})`,
579
696
  ),
580
697
  event_map: compileEvents(brick.templateKey, brick.events || {}, {
581
698
  camelCase: false,
582
- errorReference: `(brick: ${brick.id}, subspace ${subspace.id})`,
699
+ errorReference: `(brick: ${brickId}, subspace ${subspaceId})`,
583
700
  }),
584
701
  outlet: compileOutlets(
585
702
  brick.templateKey,
586
703
  brick.outlets || {},
587
- `(brick: ${brick.id}, subspace ${subspace.id})`,
704
+ `(brick: ${brickId}, subspace ${subspaceId})`,
588
705
  ),
589
- state_group: brick.switches?.reduce((acc, switchCase) => {
590
- acc[switchCase.id] = {
706
+ state_group: brick.switches?.reduce((acc, switchCase, switchIndex) => {
707
+ const switchId = assertEntryId(
708
+ switchCase.id,
709
+ 'BRICK_STATE_GROUP',
710
+ `(brick: ${brickId}, switch index: ${switchIndex}, subspace ${subspaceId})`,
711
+ )
712
+
713
+ acc[switchId] = {
591
714
  title: switchCase.title,
592
715
  description: switchCase.description,
593
716
  break: switchCase.break,
@@ -596,25 +719,25 @@ export const compile = async (app: Application) => {
596
719
  conds: compileSwitchConds(
597
720
  brick.templateKey,
598
721
  switchCase.conds || [],
599
- `(brick: ${brick.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
722
+ `(brick: ${brickId}, switch: ${switchId}, subspace ${subspaceId})`,
600
723
  ),
601
724
  property: compileProperty(
602
725
  switchCase.property,
603
- `(brick: ${brick.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
726
+ `(brick: ${brickId}, switch: ${switchId}, subspace ${subspaceId})`,
604
727
  ),
605
728
  outlet: compileOutlets(
606
729
  brick.templateKey,
607
730
  switchCase.outlets || {},
608
- `(brick: ${brick.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
731
+ `(brick: ${brickId}, switch: ${switchId}, subspace ${subspaceId})`,
609
732
  ),
610
733
  event_map: compileEvents(brick.templateKey, switchCase.events || {}, {
611
734
  camelCase: false,
612
- errorReference: `(brick: ${brick.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
735
+ errorReference: `(brick: ${brickId}, switch: ${switchId}, subspace ${subspaceId})`,
613
736
  }),
614
737
  animation: compileAnimations(
615
738
  brick.templateKey,
616
739
  switchCase.animation || {},
617
- `(brick: ${brick.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
740
+ `(brick: ${brickId}, switch: ${switchId}, subspace ${subspaceId})`,
618
741
  ),
619
742
  }
620
743
  return acc
@@ -622,21 +745,33 @@ export const compile = async (app: Application) => {
622
745
  }
623
746
  return map
624
747
  }, {}),
625
- root_canvas_id: subspace.rootCanvas.id,
626
- canvas_map: subspace.canvases.reduce((map, canvas) => {
627
- map[canvas.id] = {
748
+ root_canvas_id: rootCanvasId,
749
+ canvas_map: subspace.canvases.reduce((map, canvas, canvasIndex) => {
750
+ const canvasId = assertEntryId(
751
+ canvas.id,
752
+ 'CANVAS',
753
+ `(canvas index: ${canvasIndex}, subspace: ${subspaceId})`,
754
+ )
755
+
756
+ map[canvasId] = {
628
757
  title: canvas.title,
629
758
  description: canvas.description,
630
759
  property: compileProperty(
631
760
  canvas.property,
632
- `(canvas: ${canvas.id}, subspace ${subspace.id})`,
761
+ `(canvas: ${canvasId}, subspace ${subspaceId})`,
633
762
  ),
634
763
  event_map: compileEvents('CANVAS', canvas.events || {}, {
635
764
  camelCase: false,
636
- errorReference: `(canvas: ${canvas.id}, subspace ${subspace.id})`,
765
+ errorReference: `(canvas: ${canvasId}, subspace ${subspaceId})`,
637
766
  }),
638
- state_group: canvas.switches?.reduce((acc, switchCase) => {
639
- acc[switchCase.id] = {
767
+ state_group: canvas.switches?.reduce((acc, switchCase, switchIndex) => {
768
+ const switchId = assertEntryId(
769
+ switchCase.id,
770
+ 'BRICK_STATE_GROUP',
771
+ `(canvas: ${canvasId}, switch index: ${switchIndex}, subspace ${subspaceId})`,
772
+ )
773
+
774
+ acc[switchId] = {
640
775
  title: switchCase.title,
641
776
  description: switchCase.description,
642
777
  break: switchCase.break,
@@ -645,20 +780,20 @@ export const compile = async (app: Application) => {
645
780
  conds: compileSwitchConds(
646
781
  'CANVAS',
647
782
  switchCase.conds || [],
648
- `(canvas: ${canvas.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
783
+ `(canvas: ${canvasId}, switch: ${switchId}, subspace ${subspaceId})`,
649
784
  ),
650
785
  property: compileProperty(
651
786
  switchCase.property,
652
- `(canvas: ${canvas.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
787
+ `(canvas: ${canvasId}, switch: ${switchId}, subspace ${subspaceId})`,
653
788
  ),
654
789
  event_map: compileEvents('CANVAS', switchCase.events || {}, {
655
790
  camelCase: false,
656
- errorReference: `(canvas: ${canvas.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
791
+ errorReference: `(canvas: ${canvasId}, switch: ${switchId}, subspace ${subspaceId})`,
657
792
  }),
658
793
  animation: compileAnimations(
659
794
  'CANVAS',
660
795
  switchCase.animation || {},
661
- `(canvas: ${canvas.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
796
+ `(canvas: ${canvasId}, switch: ${switchId}, subspace ${subspaceId})`,
662
797
  ),
663
798
  }
664
799
  return acc
@@ -669,16 +804,16 @@ export const compile = async (app: Application) => {
669
804
  const brick = (item.item as () => Brick)()
670
805
  if (!brick?.id)
671
806
  throw new Error(
672
- `Invalid canvas item index: ${index}, brick not found (canvas: ${canvas.id}, subspace ${subspace.id})`,
807
+ `Invalid canvas item index: ${index}, brick not found (canvas: ${canvasId}, subspace ${subspaceId})`,
673
808
  )
674
809
  itemPayload = { brick_id: brick.id }
675
810
  } else {
676
- const subspaceId = item.item
677
- if (!app.subspaces.some((s) => s.id === subspaceId))
811
+ const targetSubspaceId = item.item
812
+ if (!app.subspaces.some((s) => s.id === targetSubspaceId))
678
813
  throw new Error(
679
- `Invalid canvas item index: ${index}, subspace not found (canvas: ${canvas.id}, subspace ${subspace.id})`,
814
+ `Invalid canvas item index: ${index}, subspace not found (canvas: ${canvasId}, subspace ${subspaceId})`,
680
815
  )
681
- itemPayload = { subspace_id: subspaceId }
816
+ itemPayload = { subspace_id: targetSubspaceId }
682
817
  }
683
818
  return {
684
819
  type: typeof item.item === 'function' ? 'brick' : 'subspace',
@@ -690,8 +825,14 @@ export const compile = async (app: Application) => {
690
825
  }
691
826
  return map
692
827
  }, {}),
693
- generator_map: subspace.generators.reduce((map, generator) => {
694
- map[generator.id] = {
828
+ generator_map: subspace.generators.reduce((map, generator, generatorIndex) => {
829
+ const generatorId = assertEntryId(
830
+ generator.id,
831
+ 'GENERATOR',
832
+ `(generator index: ${generatorIndex}, subspace: ${subspaceId})`,
833
+ )
834
+
835
+ map[generatorId] = {
695
836
  template_key: generator.templateKey,
696
837
  title: generator.title,
697
838
  description: generator.description,
@@ -702,19 +843,25 @@ export const compile = async (app: Application) => {
702
843
  : undefined,
703
844
  property: compileProperty(
704
845
  generator.property || {},
705
- `(generator: ${generator.id}, subspace ${subspace.id})`,
846
+ `(generator: ${generatorId}, subspace ${subspaceId})`,
706
847
  ),
707
848
  event_map: compileEvents(generator.templateKey, generator.events || {}, {
708
849
  camelCase: false,
709
- errorReference: `(generator: ${generator.id}, subspace ${subspace.id})`,
850
+ errorReference: `(generator: ${generatorId}, subspace ${subspaceId})`,
710
851
  }),
711
852
  outlet: compileOutlets(
712
853
  generator.templateKey,
713
854
  generator.outlets || {},
714
- `(generator: ${generator.id}, subspace ${subspace.id})`,
855
+ `(generator: ${generatorId}, subspace ${subspaceId})`,
715
856
  ),
716
- state_group: generator.switches?.reduce((acc, switchCase) => {
717
- acc[switchCase.id] = {
857
+ state_group: generator.switches?.reduce((acc, switchCase, switchIndex) => {
858
+ const switchId = assertEntryId(
859
+ switchCase.id,
860
+ 'BRICK_STATE_GROUP',
861
+ `(generator: ${generatorId}, switch index: ${switchIndex}, subspace ${subspaceId})`,
862
+ )
863
+
864
+ acc[switchId] = {
718
865
  title: switchCase.title,
719
866
  description: switchCase.description,
720
867
  break: switchCase.break,
@@ -723,25 +870,25 @@ export const compile = async (app: Application) => {
723
870
  conds: compileSwitchConds(
724
871
  generator.templateKey,
725
872
  switchCase.conds || [],
726
- `(generator: ${generator.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
873
+ `(generator: ${generatorId}, switch: ${switchId}, subspace ${subspaceId})`,
727
874
  ),
728
875
  property: compileProperty(
729
876
  switchCase.property,
730
- `(generator: ${generator.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
877
+ `(generator: ${generatorId}, switch: ${switchId}, subspace ${subspaceId})`,
731
878
  ),
732
879
  outlet: compileOutlets(
733
880
  generator.templateKey,
734
881
  switchCase.outlets || {},
735
- `(generator: ${generator.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
882
+ `(generator: ${generatorId}, switch: ${switchId}, subspace ${subspaceId})`,
736
883
  ),
737
884
  event_map: compileEvents(generator.templateKey, switchCase.events || {}, {
738
885
  camelCase: false,
739
- errorReference: `(generator: ${generator.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
886
+ errorReference: `(generator: ${generatorId}, switch: ${switchId}, subspace ${subspaceId})`,
740
887
  }),
741
888
  animation: compileAnimations(
742
889
  generator.templateKey,
743
890
  switchCase.animation || {},
744
- `(generator: ${generator.id}, switch: ${switchCase.id}, subspace ${subspace.id})`,
891
+ `(generator: ${generatorId}, switch: ${switchId}, subspace ${subspaceId})`,
745
892
  ),
746
893
  }
747
894
  return acc
@@ -749,8 +896,14 @@ export const compile = async (app: Application) => {
749
896
  }
750
897
  return map
751
898
  }, {}),
752
- property_bank_map: subspace.data.reduce((map, data) => {
753
- map[data.id] = {
899
+ property_bank_map: subspace.data.reduce((map, data, dataIndex) => {
900
+ const dataId = assertEntryId(
901
+ data.id,
902
+ 'PROPERTY_BANK_DATA_NODE',
903
+ `(data index: ${dataIndex}, subspace: ${subspaceId})`,
904
+ )
905
+
906
+ map[dataId] = {
754
907
  title: data.title,
755
908
  description: data.description,
756
909
  linked: data.metadata?.linked,
@@ -766,34 +919,71 @@ export const compile = async (app: Application) => {
766
919
  schema: data.schema,
767
920
  type: data.type,
768
921
  ...compileKind(data.kind),
769
- value: compileProperty(data.value, `(data: ${data.id}, subspace ${subspace.id})`),
922
+ value: compileProperty(data.value, `(data: ${dataId}, subspace ${subspaceId})`),
770
923
  event_map: compileEvents('PROPERTY_BANK', data.events || {}, {
771
924
  camelCase: false,
772
- errorReference: `(data: ${data.id}, subspace ${subspace.id})`,
925
+ errorReference: `(data: ${dataId}, subspace ${subspaceId})`,
773
926
  }),
774
927
  hit_equal: data.hit_equal,
775
928
  hit_regex: data.hit_regex,
776
929
  }
777
930
  return map
778
931
  }, {}),
779
- property_bank_calc_map: subspace.dataCalculation.reduce((map, dataCalc) => {
932
+ property_bank_calc_map: subspace.dataCalculation.reduce((map, dataCalc, dataCalcIndex) => {
933
+ const dataCalcId = assertEntryId(
934
+ dataCalc.id,
935
+ 'PROPERTY_BANK_COMMAND_MAP',
936
+ `(data calc index: ${dataCalcIndex}, subspace: ${subspaceId})`,
937
+ )
938
+
780
939
  const calc: any = {
781
940
  title: dataCalc.title,
782
941
  description: dataCalc.description,
783
942
  }
943
+ if (dataCalc.triggerMode) calc.trigger_type = dataCalc.triggerMode
784
944
  if (dataCalc.__typename === 'DataCalculationMap') {
785
945
  calc.type = 'general'
786
946
  const mapCalc = dataCalc as DataCalculationMap
787
947
 
948
+ const getNodeId = (
949
+ node: DataCalculationData | DataCommand,
950
+ reference = '',
951
+ nodeIndex?: number,
952
+ ) => {
953
+ const nodeReference = [
954
+ `data calc: ${dataCalcId}`,
955
+ `subspace: ${subspaceId}`,
956
+ typeof nodeIndex === 'number' ? `node index: ${nodeIndex}` : undefined,
957
+ reference || undefined,
958
+ ]
959
+ .filter(Boolean)
960
+ .join(', ')
961
+
962
+ if (node.__typename === 'DataCalculationData') {
963
+ return assertEntryId(
964
+ node.data()?.id,
965
+ 'PROPERTY_BANK_DATA_NODE',
966
+ `(${nodeReference})`,
967
+ )
968
+ }
969
+ if (node.__typename === 'DataCommand') {
970
+ return assertEntryId(node.id, 'PROPERTY_BANK_COMMAND_NODE', `(${nodeReference})`)
971
+ }
972
+ throw new Error(`Invalid node: ${JSON.stringify(node)}`)
973
+ }
974
+
788
975
  const generateInputPorts = (inputs) =>
789
- inputs.reduce((acc, port) => {
976
+ inputs.reduce((acc, port, portIndex) => {
790
977
  if (!acc[port.key]) acc[port.key] = null
791
978
 
792
979
  let sourceId
793
980
  const sourceNode = port.source()
794
- if (sourceNode?.__typename === 'DataCalculationData')
795
- sourceId = (sourceNode as DataCalculationData).data().id
796
- if (sourceNode?.__typename === 'DataCommand') sourceId = sourceNode.id
981
+ if (
982
+ sourceNode?.__typename === 'DataCalculationData' ||
983
+ sourceNode?.__typename === 'DataCommand'
984
+ ) {
985
+ sourceId = getNodeId(sourceNode, `input port index: ${portIndex}`)
986
+ }
797
987
 
798
988
  if (!sourceId) return acc
799
989
  if (!acc[port.key]) acc[port.key] = []
@@ -807,14 +997,17 @@ export const compile = async (app: Application) => {
807
997
  }, {})
808
998
 
809
999
  const generateOutputPorts = (outputs) =>
810
- outputs.reduce((acc, port) => {
1000
+ outputs.reduce((acc, port, portIndex) => {
811
1001
  if (!acc[port.key]) acc[port.key] = null
812
1002
 
813
1003
  let targetId
814
1004
  const targetNode = port.target()
815
- if (targetNode?.__typename === 'DataCalculationData')
816
- targetId = (targetNode as DataCalculationData).data().id
817
- if (targetNode?.__typename === 'DataCommand') targetId = targetNode.id
1005
+ if (
1006
+ targetNode?.__typename === 'DataCalculationData' ||
1007
+ targetNode?.__typename === 'DataCommand'
1008
+ ) {
1009
+ targetId = getNodeId(targetNode, `output port index: ${portIndex}`)
1010
+ }
818
1011
 
819
1012
  if (!targetId) return acc
820
1013
  if (!acc[port.key]) acc[port.key] = []
@@ -826,16 +1019,10 @@ export const compile = async (app: Application) => {
826
1019
  return acc
827
1020
  }, {})
828
1021
 
829
- const getNodeId = (node) => {
830
- if (node.__typename === 'DataCalculationData') return node.data().id
831
- if (node.__typename === 'DataCommand') return node.id
832
- throw new Error(`Invalid node: ${JSON.stringify(node)}`)
833
- }
834
-
835
- calc.map = mapCalc.nodes.reduce((acc, node) => {
1022
+ calc.map = mapCalc.nodes.reduce((acc, node, nodeIndex) => {
836
1023
  if (node.__typename === 'DataCalculationData') {
837
1024
  const dataNode = node as DataCalculationData
838
- acc[getNodeId(dataNode)] = {
1025
+ acc[getNodeId(dataNode, 'data node', nodeIndex)] = {
839
1026
  title: dataNode.title,
840
1027
  description: dataNode.description,
841
1028
  type: 'data-node',
@@ -860,7 +1047,7 @@ export const compile = async (app: Application) => {
860
1047
  (input.source()?.__typename === 'DataCalculationData' ||
861
1048
  input.source()?.__typename === 'DataCommand'),
862
1049
  )
863
- acc[getNodeId(commandNode)] = {
1050
+ acc[getNodeId(commandNode, 'command node', nodeIndex)] = {
864
1051
  title: commandNode.title,
865
1052
  description: commandNode.description,
866
1053
  type: `command-node-${type}`,
@@ -878,11 +1065,11 @@ export const compile = async (app: Application) => {
878
1065
  return acc
879
1066
  }, {})
880
1067
  calc.editor_info = mapCalc.editorInfo.reduce((acc, editorInfo) => {
881
- acc[getNodeId(editorInfo.node)] = {
1068
+ acc[getNodeId(editorInfo.node, 'editor info node')] = {
882
1069
  position: editorInfo.position,
883
1070
  points: editorInfo.points.reduce((pointsAcc, point) => {
884
- const sourceId = getNodeId(point.source)
885
- const targetId = getNodeId(point.target)
1071
+ const sourceId = getNodeId(point.source, 'editor info point source')
1072
+ const targetId = getNodeId(point.target, 'editor info point target')
886
1073
  const key = `${sourceId}-${point.sourceOutputKey}-${targetId}-${point.targetInputKey}`
887
1074
  pointsAcc[key] = point.positions
888
1075
  return pointsAcc
@@ -908,28 +1095,56 @@ export const compile = async (app: Application) => {
908
1095
  },
909
1096
  comment: true,
910
1097
  })
911
- } catch (e) {
1098
+ } catch {
912
1099
  code = scriptCalc.code || ''
913
1100
  }
914
1101
  calc.script_config = {
915
1102
  note: scriptCalc.note,
916
1103
  code,
917
1104
  enable_async: scriptCalc.enableAsync,
1105
+ trigger_mode: scriptCalc.triggerMode,
918
1106
  inputs: scriptCalc.inputs.reduce((acc, input) => {
919
- acc[input.data().id] = input.key
1107
+ const inputId = assertEntryId(
1108
+ input.data()?.id,
1109
+ 'PROPERTY_BANK_DATA_NODE',
1110
+ `(data calc: ${dataCalcId}, script input: ${input.key}, subspace: ${subspaceId})`,
1111
+ )
1112
+ acc[inputId] = input.key
920
1113
  return acc
921
1114
  }, {}),
922
1115
  disabled_triggers: scriptCalc.inputs.reduce((acc, input) => {
923
- acc[input.data().id] = !input.trigger
1116
+ const inputId = assertEntryId(
1117
+ input.data()?.id,
1118
+ 'PROPERTY_BANK_DATA_NODE',
1119
+ `(data calc: ${dataCalcId}, script trigger input: ${input.key}, subspace: ${subspaceId})`,
1120
+ )
1121
+ acc[inputId] = !input.trigger
924
1122
  return acc
925
1123
  }, {}),
926
- output: scriptCalc.output?.().id,
1124
+ output: scriptCalc.output
1125
+ ? assertEntryId(
1126
+ scriptCalc.output()?.id,
1127
+ 'PROPERTY_BANK_DATA_NODE',
1128
+ `(data calc: ${dataCalcId}, script output, subspace: ${subspaceId})`,
1129
+ )
1130
+ : undefined,
927
1131
  outputs: scriptCalc.outputs.reduce((acc, output) => {
928
1132
  if (!acc[output.key]) acc[output.key] = []
929
- acc[output.key].push(output.data().id)
1133
+ const outputId = assertEntryId(
1134
+ output.data()?.id,
1135
+ 'PROPERTY_BANK_DATA_NODE',
1136
+ `(data calc: ${dataCalcId}, script outputs key: ${output.key}, subspace: ${subspaceId})`,
1137
+ )
1138
+ acc[output.key].push(outputId)
930
1139
  return acc
931
1140
  }, {}),
932
- error: scriptCalc.error?.().id,
1141
+ error: scriptCalc.error
1142
+ ? assertEntryId(
1143
+ scriptCalc.error()?.id,
1144
+ 'PROPERTY_BANK_DATA_NODE',
1145
+ `(data calc: ${dataCalcId}, script error output, subspace: ${subspaceId})`,
1146
+ )
1147
+ : undefined,
933
1148
  }
934
1149
 
935
1150
  Object.assign(
@@ -939,25 +1154,32 @@ export const compile = async (app: Application) => {
939
1154
  }),
940
1155
  )
941
1156
  }
942
- map[dataCalc.id] = calc
1157
+ map[dataCalcId] = calc
943
1158
  return map
944
1159
  }, {}),
945
1160
  action_map: subspace.actions || undefined,
946
1161
  event_map: compileEvents('', subspace.events || {}, {
947
1162
  camelCase: false,
948
- errorReference: `(subspace ${subspace.id})`,
1163
+ errorReference: `(subspace ${subspaceId})`,
949
1164
  }),
950
1165
  routing: subspace.dataRouting.reduce((acc, data, index) => {
951
- if (!data?.id)
952
- throw new Error(`Invalid data routing index: ${index} (subspace ${subspace.id})`)
953
- acc[data.id] = { enabled_routing: true }
1166
+ const dataId = assertEntryId(
1167
+ data?.id,
1168
+ 'PROPERTY_BANK_DATA_NODE',
1169
+ `(data routing index: ${index}, subspace ${subspaceId})`,
1170
+ )
1171
+ acc[dataId] = { enabled_routing: true }
954
1172
  return acc
955
1173
  }, {}),
956
1174
  ...compileModule(subspace),
957
1175
  }
958
1176
  return subspaceMap
959
1177
  }, {}),
960
- root_subspace_id: app.rootSubspace.id,
1178
+ root_subspace_id: assertEntryId(
1179
+ app.rootSubspace?.id,
1180
+ 'SUBSPACE',
1181
+ '(application root subspace)',
1182
+ ),
961
1183
  fonts: app.fonts,
962
1184
  ...compileApplicationSettings(app.settings),
963
1185
  // Use typed automationMap if available, otherwise fall back to TEMP metadata
@@ -967,6 +1189,7 @@ export const compile = async (app: Application) => {
967
1189
  automation_map: app.automationMap
968
1190
  ? compileAutomation(app.automationMap)
969
1191
  : app.metadata?.TEMP_automation_map || {},
1192
+ update_timestamp: timestamp,
970
1193
  }
971
1194
  return config
972
1195
  }