@ductape/sdk 0.1.19 → 0.1.21

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 (116) hide show
  1. package/dist/agents/agents.service.d.ts +2 -0
  2. package/dist/agents/agents.service.js +26 -3
  3. package/dist/agents/agents.service.js.map +1 -1
  4. package/dist/api/services/appApi.service.d.ts +6 -0
  5. package/dist/api/services/appApi.service.js +25 -0
  6. package/dist/api/services/appApi.service.js.map +1 -1
  7. package/dist/api/services/cloudApi.service.js +8 -4
  8. package/dist/api/services/cloudApi.service.js.map +1 -1
  9. package/dist/api/services/logsApi.service.js +5 -1
  10. package/dist/api/services/logsApi.service.js.map +1 -1
  11. package/dist/api/services/productsApi.service.d.ts +113 -0
  12. package/dist/api/services/productsApi.service.js +104 -0
  13. package/dist/api/services/productsApi.service.js.map +1 -1
  14. package/dist/api/urls.d.ts +7 -0
  15. package/dist/api/urls.js +14 -7
  16. package/dist/api/urls.js.map +1 -1
  17. package/dist/api/utils/cache.utils.d.ts +1 -0
  18. package/dist/api/utils/cache.utils.js +5 -1
  19. package/dist/api/utils/cache.utils.js.map +1 -1
  20. package/dist/apps/services/app.service.js +27 -8
  21. package/dist/apps/services/app.service.js.map +1 -1
  22. package/dist/brokers/brokers.service.js +20 -12
  23. package/dist/brokers/brokers.service.js.map +1 -1
  24. package/dist/cloud/cloud-broker-link.util.d.ts +2 -6
  25. package/dist/cloud/cloud-broker-link.util.js +21 -35
  26. package/dist/cloud/cloud-broker-link.util.js.map +1 -1
  27. package/dist/cloud/cloud-database-link.util.d.ts +2 -6
  28. package/dist/cloud/cloud-database-link.util.js +17 -12
  29. package/dist/cloud/cloud-database-link.util.js.map +1 -1
  30. package/dist/cloud/cloud-graph-link.util.d.ts +2 -6
  31. package/dist/cloud/cloud-graph-link.util.js +18 -21
  32. package/dist/cloud/cloud-graph-link.util.js.map +1 -1
  33. package/dist/cloud/cloud-materialize.util.d.ts +22 -0
  34. package/dist/cloud/cloud-materialize.util.js +82 -0
  35. package/dist/cloud/cloud-materialize.util.js.map +1 -0
  36. package/dist/cloud/cloud-resource-body.util.d.ts +6 -0
  37. package/dist/cloud/cloud-resource-body.util.js +58 -0
  38. package/dist/cloud/cloud-resource-body.util.js.map +1 -0
  39. package/dist/cloud/cloud-runtime.util.js +1 -1
  40. package/dist/cloud/cloud-runtime.util.js.map +1 -1
  41. package/dist/cloud/cloud-vector-link.util.d.ts +2 -6
  42. package/dist/cloud/cloud-vector-link.util.js +22 -20
  43. package/dist/cloud/cloud-vector-link.util.js.map +1 -1
  44. package/dist/cloud/cloud.service.js +4 -4
  45. package/dist/cloud/cloud.service.js.map +1 -1
  46. package/dist/cloud/types/cloud.types.d.ts +13 -13
  47. package/dist/database/adapters/mysql.adapter.js +8 -3
  48. package/dist/database/adapters/mysql.adapter.js.map +1 -1
  49. package/dist/database/adapters/postgresql.adapter.js +6 -2
  50. package/dist/database/adapters/postgresql.adapter.js.map +1 -1
  51. package/dist/database/databases.service.d.ts +10 -1
  52. package/dist/database/databases.service.js +84 -27
  53. package/dist/database/databases.service.js.map +1 -1
  54. package/dist/graph/graphs.service.d.ts +7 -3
  55. package/dist/graph/graphs.service.js +67 -31
  56. package/dist/graph/graphs.service.js.map +1 -1
  57. package/dist/index.d.ts +27 -6
  58. package/dist/index.js +94 -102
  59. package/dist/index.js.map +1 -1
  60. package/dist/logs/logs.service.d.ts +3 -1
  61. package/dist/logs/logs.service.js +12 -2
  62. package/dist/logs/logs.service.js.map +1 -1
  63. package/dist/logs/logs.types.d.ts +4 -0
  64. package/dist/logs/logs.types.js.map +1 -1
  65. package/dist/notifications/notifications.service.d.ts +6 -0
  66. package/dist/notifications/notifications.service.js +54 -17
  67. package/dist/notifications/notifications.service.js.map +1 -1
  68. package/dist/processor/services/processor.service.d.ts +0 -14
  69. package/dist/processor/services/processor.service.js +6 -72
  70. package/dist/processor/services/processor.service.js.map +1 -1
  71. package/dist/products/bootstrap-cache.d.ts +22 -0
  72. package/dist/products/bootstrap-cache.js +78 -0
  73. package/dist/products/bootstrap-cache.js.map +1 -0
  74. package/dist/products/services/products.service.d.ts +48 -5
  75. package/dist/products/services/products.service.js +314 -171
  76. package/dist/products/services/products.service.js.map +1 -1
  77. package/dist/products/validators/joi-validators/create.productFallback.validator.js +1 -1
  78. package/dist/products/validators/joi-validators/create.productGraph.validator.js +7 -0
  79. package/dist/products/validators/joi-validators/create.productGraph.validator.js.map +1 -1
  80. package/dist/products/validators/joi-validators/create.productMessageBrokers.validator.js +1 -1
  81. package/dist/products/validators/joi-validators/create.productMessageBrokers.validator.js.map +1 -1
  82. package/dist/products/validators/joi-validators/create.productQuota.validator.js +1 -1
  83. package/dist/products/validators/joi-validators/create.productVector.validator.js +6 -0
  84. package/dist/products/validators/joi-validators/create.productVector.validator.js.map +1 -1
  85. package/dist/products/validators/joi-validators/update.productFallback.validator.js +1 -1
  86. package/dist/products/validators/joi-validators/update.productGraph.validator.js +9 -0
  87. package/dist/products/validators/joi-validators/update.productGraph.validator.js.map +1 -1
  88. package/dist/products/validators/joi-validators/update.productQuota.validator.js +1 -1
  89. package/dist/resilience/fallback.service.d.ts +3 -0
  90. package/dist/resilience/fallback.service.js +49 -14
  91. package/dist/resilience/fallback.service.js.map +1 -1
  92. package/dist/resilience/healthcheck.service.d.ts +3 -0
  93. package/dist/resilience/healthcheck.service.js +57 -7
  94. package/dist/resilience/healthcheck.service.js.map +1 -1
  95. package/dist/resilience/quota.service.d.ts +3 -0
  96. package/dist/resilience/quota.service.js +49 -14
  97. package/dist/resilience/quota.service.js.map +1 -1
  98. package/dist/resilience/resilience-execution.utils.d.ts +22 -0
  99. package/dist/resilience/resilience-execution.utils.js +81 -0
  100. package/dist/resilience/resilience-execution.utils.js.map +1 -0
  101. package/dist/sessions/sessions.service.d.ts +9 -1
  102. package/dist/sessions/sessions.service.js +125 -49
  103. package/dist/sessions/sessions.service.js.map +1 -1
  104. package/dist/storage/storage-cloud-link.util.d.ts +2 -6
  105. package/dist/storage/storage-cloud-link.util.js +23 -21
  106. package/dist/storage/storage-cloud-link.util.js.map +1 -1
  107. package/dist/types/appBuilder.types.d.ts +2 -0
  108. package/dist/types/index.types.d.ts +8 -0
  109. package/dist/types/index.types.js.map +1 -1
  110. package/dist/types/processor.types.d.ts +3 -0
  111. package/dist/types/processor.types.js.map +1 -1
  112. package/dist/types/requests.types.d.ts +4 -0
  113. package/dist/vector/vector-database.service.d.ts +6 -0
  114. package/dist/vector/vector-database.service.js +66 -8
  115. package/dist/vector/vector-database.service.js.map +1 -1
  116. package/package.json +3 -1
@@ -27,10 +27,12 @@ const cloud_broker_link_util_1 = require("../../cloud/cloud-broker-link.util");
27
27
  const cloud_database_link_util_1 = require("../../cloud/cloud-database-link.util");
28
28
  const cloud_graph_link_util_1 = require("../../cloud/cloud-graph-link.util");
29
29
  const cloud_vector_link_util_1 = require("../../cloud/cloud-vector-link.util");
30
+ const cloud_materialize_util_1 = require("../../cloud/cloud-materialize.util");
30
31
  const productsBuilder_types_1 = require("../../types/productsBuilder.types");
31
32
  const validators_1 = require("../validators");
32
33
  const objects_utils_1 = require("../utils/objects.utils");
33
34
  const processor_utils_1 = require("../../processor/utils/processor.utils");
35
+ const bootstrap_cache_1 = require("../bootstrap-cache");
34
36
  const create_productDatabaseAction_validator_1 = require("../validators/joi-validators/create.productDatabaseAction.validator");
35
37
  const update_productDatabaseAction_validator_1 = require("../validators/joi-validators/update.productDatabaseAction.validator");
36
38
  const create_productStorage_validator_1 = require("../validators/joi-validators/create.productStorage.validator");
@@ -81,6 +83,34 @@ class ProductsBuilderService {
81
83
  if (queues) {
82
84
  this.queues = queues;
83
85
  }
86
+ this.bootstrapCache = new bootstrap_cache_1.BootstrapCache(this.workspace_id, this.redisClient, this.workspace_private_key);
87
+ }
88
+ applyBootstrapProductContext(productTag, boot) {
89
+ var _a, _b;
90
+ if (boot.product_id) {
91
+ this.product_id = boot.product_id;
92
+ }
93
+ const hasPrivateKey = boot.private_key != null && String(boot.private_key).trim() !== '';
94
+ if (hasPrivateKey) {
95
+ this.product = {
96
+ _id: boot.product_id,
97
+ workspace_id: boot.workspace_id,
98
+ private_key: boot.private_key,
99
+ tag: productTag !== null && productTag !== void 0 ? productTag : ((_b = (_a = this.product) === null || _a === void 0 ? void 0 : _a.tag) !== null && _b !== void 0 ? _b : ''),
100
+ };
101
+ }
102
+ }
103
+ async cachedBootstrap(domain, keyParts, fetch, apply) {
104
+ const key = (0, bootstrap_cache_1.buildBootstrapCacheKey)(domain, this.workspace_id, keyParts);
105
+ const cached = await this.bootstrapCache.get(key);
106
+ if (cached) {
107
+ apply === null || apply === void 0 ? void 0 : apply(cached);
108
+ return cached;
109
+ }
110
+ const result = await fetch();
111
+ apply === null || apply === void 0 ? void 0 : apply(result);
112
+ this.bootstrapCache.set(key, result);
113
+ return result;
84
114
  }
85
115
  fetchPrivateKey() {
86
116
  var _a;
@@ -235,6 +265,32 @@ class ProductsBuilderService {
235
265
  option.check_interval = 10000;
236
266
  }
237
267
  }
268
+ /** Validate a quota/fallback action provider (app action or product workflow). */
269
+ async validateQuotaFallbackProvider(option) {
270
+ var _a;
271
+ if (option.type !== productsBuilder_types_1.FeatureEventTypes.ACTION)
272
+ return;
273
+ if ((_a = option.app) === null || _a === void 0 ? void 0 : _a.trim()) {
274
+ const app = await this.fetchThirdPartyAppByAccessTag(option.app);
275
+ if (!app) {
276
+ throw new Error(`App with access tag ${option.app} not found`);
277
+ }
278
+ const version = app.versions.find((v) => v.tag === app.version);
279
+ const action = version === null || version === void 0 ? void 0 : version.actions.find((a) => a.tag === option.event);
280
+ if (!action) {
281
+ throw new Error(`Cannot find action ${option.event} on app ${app.tag} version ${app.version}`);
282
+ }
283
+ }
284
+ else {
285
+ const workflow = await this.fetchWorkflow(option.event);
286
+ if (!workflow) {
287
+ throw new Error(`Workflow ${option.event} not found on product`);
288
+ }
289
+ }
290
+ if (option.healthcheck) {
291
+ await this.validateProviderHealthcheckTag(option);
292
+ }
293
+ }
238
294
  /** Keep in-memory product component arrays in sync after component CRUD (components API can lag). */
239
295
  mergeProductComponent(kind, item) {
240
296
  if (!this.product || !(item === null || item === void 0 ? void 0 : item.tag))
@@ -277,6 +333,27 @@ class ProductsBuilderService {
277
333
  event,
278
334
  envs, action: enums_1.RequestAction.CREATE, component: enums_1.ProductComponents.HEALTHCHECK }), this.getUserAccess());
279
335
  }
336
+ async updateHealthcheckFromSchema(schema) {
337
+ var _a, _b, _c;
338
+ const probe = schema.probe;
339
+ const probeInput = (probe === null || probe === void 0 ? void 0 : probe.input) != null ? probe.input : undefined;
340
+ const app = (_a = probe === null || probe === void 0 ? void 0 : probe.app) !== null && _a !== void 0 ? _a : schema.app;
341
+ const event = (_b = probe === null || probe === void 0 ? void 0 : probe.event) !== null && _b !== void 0 ? _b : schema.event;
342
+ if (probeInput != null && !((_c = this.product) === null || _c === void 0 ? void 0 : _c.private_key)) {
343
+ throw new Error('Healthcheck inputs must be encrypted with the product private key; product not initialized or missing private_key');
344
+ }
345
+ const envs = await Promise.all((schema.envs || []).map(async (env) => {
346
+ var _a;
347
+ const input = env.input != null ? env.input : probeInput;
348
+ const encrypted = input != null && ((_a = this.product) === null || _a === void 0 ? void 0 : _a.private_key)
349
+ ? (0, processor_utils_1.encrypt)(JSON.stringify(input), this.product.private_key)
350
+ : input;
351
+ return Object.assign(Object.assign({}, env), { input: encrypted });
352
+ }));
353
+ await this.productApi.updateProduct(this.product_id, Object.assign(Object.assign({}, schema), { app,
354
+ event,
355
+ envs, action: enums_1.RequestAction.UPDATE, component: enums_1.ProductComponents.HEALTHCHECK }), this.getUserAccess());
356
+ }
280
357
  async updateDataValidation(selector, update) {
281
358
  if (!selector.startsWith('$Data{') && !selector.startsWith('$Filter')) {
282
359
  throw new Error(`selector ${selector} is expected to start with $Data or $Filter`);
@@ -352,12 +429,9 @@ class ProductsBuilderService {
352
429
  await validators_1.CreateProductBuilderSchema.validateAsync(data);
353
430
  const exists = await this.checkIfProductExists(data.name);
354
431
  if (exists && (exists === null || exists === void 0 ? void 0 : exists._id)) {
355
- // await this.initializeProduct(exists?._id);
356
- }
357
- else {
358
- const product = await this.createNewProduct(data);
359
- // await this.initializeProduct(product._id);
432
+ return exists;
360
433
  }
434
+ return await this.createNewProduct(data);
361
435
  }
362
436
  catch (e) {
363
437
  throw e;
@@ -418,22 +492,9 @@ class ProductsBuilderService {
418
492
  * Returns only the minimal action data needed to execute
419
493
  */
420
494
  async bootstrapAction(params) {
495
+ var _a;
421
496
  try {
422
- const result = await this.productApi.bootstrapAction(params, this.getUserAccess());
423
- // Initialize minimal product data so fetchPrivateKey/fetchProductId/fetchWorkspaceId work
424
- if (result.product_id) {
425
- this.product_id = result.product_id;
426
- }
427
- const hasPrivateKey = result.private_key != null && String(result.private_key).trim() !== '';
428
- if (hasPrivateKey) {
429
- this.product = {
430
- _id: result.product_id,
431
- workspace_id: result.workspace_id,
432
- private_key: result.private_key,
433
- tag: params.product_tag,
434
- };
435
- }
436
- return result;
497
+ return await this.cachedBootstrap('action', [(_a = params.product_tag) !== null && _a !== void 0 ? _a : '', params.access_tag, params.env_slug, params.action_tag], () => this.productApi.bootstrapAction(params, this.getUserAccess()), (result) => this.applyBootstrapProductContext(params.product_tag, result));
437
498
  }
438
499
  catch (e) {
439
500
  throw e;
@@ -460,14 +521,17 @@ class ProductsBuilderService {
460
521
  }
461
522
  async bootstrapNotification(params) {
462
523
  try {
463
- const result = await this.productApi.bootstrapNotification(params, this.getUserAccess());
464
- if (result.product_id) {
465
- this.product_id = result.product_id;
466
- }
467
- if (result.notification && result.private_key) {
468
- result.notification = this.decryptNotificationChannelConfigs(result.notification, result.private_key);
469
- }
470
- return result;
524
+ return await this.cachedBootstrap('notification', [params.product_tag, params.env_slug, params.notification_tag, params.message_tag], async () => {
525
+ const result = await this.productApi.bootstrapNotification(params, this.getUserAccess());
526
+ if (result.notification && result.private_key) {
527
+ result.notification = this.decryptNotificationChannelConfigs(result.notification, result.private_key);
528
+ }
529
+ return result;
530
+ }, (result) => {
531
+ if (result.product_id) {
532
+ this.product_id = result.product_id;
533
+ }
534
+ });
471
535
  }
472
536
  catch (e) {
473
537
  throw e;
@@ -475,11 +539,68 @@ class ProductsBuilderService {
475
539
  }
476
540
  async bootstrapStorage(params) {
477
541
  try {
478
- const result = await this.productApi.bootstrapStorage(params, this.getUserAccess());
479
- if (result.product_id) {
480
- this.product_id = result.product_id;
481
- }
482
- return result;
542
+ return await this.cachedBootstrap('storage', [params.product_tag, params.env_slug, params.storage_tag], () => this.productApi.bootstrapStorage(params, this.getUserAccess()), (result) => {
543
+ if (result.product_id) {
544
+ this.product_id = result.product_id;
545
+ }
546
+ });
547
+ }
548
+ catch (e) {
549
+ throw e;
550
+ }
551
+ }
552
+ async bootstrapSession(params) {
553
+ try {
554
+ return await this.cachedBootstrap('session', [params.product_tag, params.env_slug, params.session_tag], () => this.productApi.bootstrapSession(params, this.getUserAccess()), (result) => this.applyBootstrapProductContext(params.product_tag, result));
555
+ }
556
+ catch (e) {
557
+ throw e;
558
+ }
559
+ }
560
+ async bootstrapDatabase(params) {
561
+ try {
562
+ return await this.cachedBootstrap('database', [params.product_tag, params.env_slug, params.database_tag], () => this.productApi.bootstrapDatabase(params, this.getUserAccess()), (result) => this.applyBootstrapProductContext(params.product_tag, result));
563
+ }
564
+ catch (e) {
565
+ throw e;
566
+ }
567
+ }
568
+ async bootstrapBroker(params) {
569
+ var _a;
570
+ try {
571
+ return await this.cachedBootstrap('broker', [params.product_tag, params.env_slug, params.broker_tag, (_a = params.topic_tag) !== null && _a !== void 0 ? _a : ''], () => this.productApi.bootstrapBroker(params, this.getUserAccess()), (result) => this.applyBootstrapProductContext(params.product_tag, result));
572
+ }
573
+ catch (e) {
574
+ throw e;
575
+ }
576
+ }
577
+ async bootstrapGraph(params) {
578
+ try {
579
+ return await this.cachedBootstrap('graph', [params.product_tag, params.env_slug, params.graph_tag], () => this.productApi.bootstrapGraph(params, this.getUserAccess()), (result) => this.applyBootstrapProductContext(params.product_tag, result));
580
+ }
581
+ catch (e) {
582
+ throw e;
583
+ }
584
+ }
585
+ async bootstrapVector(params) {
586
+ try {
587
+ return await this.cachedBootstrap('vector', [params.product_tag, params.env_slug, params.vector_tag], () => this.productApi.bootstrapVector(params, this.getUserAccess()), (result) => this.applyBootstrapProductContext(params.product_tag, result));
588
+ }
589
+ catch (e) {
590
+ throw e;
591
+ }
592
+ }
593
+ async bootstrapResilience(params) {
594
+ try {
595
+ return await this.cachedBootstrap('resilience', [params.product_tag, params.env_slug, params.component_type, params.component_tag], () => this.productApi.bootstrapResilience(params, this.getUserAccess()), (result) => this.applyBootstrapProductContext(params.product_tag, result));
596
+ }
597
+ catch (e) {
598
+ throw e;
599
+ }
600
+ }
601
+ async bootstrapIntelligence(params) {
602
+ try {
603
+ return await this.cachedBootstrap('intelligence', [params.product_tag, params.env_slug, params.agent_tag], () => this.productApi.bootstrapIntelligence(params, this.getUserAccess()), (result) => this.applyBootstrapProductContext(params.product_tag, result));
483
604
  }
484
605
  catch (e) {
485
606
  throw e;
@@ -491,19 +612,21 @@ class ProductsBuilderService {
491
612
  async bootstrapWorkflow(params) {
492
613
  try {
493
614
  const auth = this.getUserAccess();
494
- const result = await this.productApi.bootstrapWorkflow(Object.assign(Object.assign({}, params), { workspace_id: auth.workspace_id }), auth);
495
- if (result && typeof result === 'object') {
496
- for (const stepTag of Object.keys(result)) {
497
- const data = result[stepTag];
498
- if (data === null || data === void 0 ? void 0 : data.product_id) {
499
- this.product_id = data.product_id;
500
- }
501
- if ((data === null || data === void 0 ? void 0 : data.notification) && (data === null || data === void 0 ? void 0 : data.private_key)) {
502
- result[stepTag] = Object.assign(Object.assign({}, data), { notification: this.decryptNotificationChannelConfigs(data.notification, data.private_key) });
615
+ return await this.cachedBootstrap('workflow', [params.product_tag, params.env_slug, (0, bootstrap_cache_1.hashWorkflowSteps)(params.steps)], async () => {
616
+ const result = await this.productApi.bootstrapWorkflow(Object.assign(Object.assign({}, params), { workspace_id: auth.workspace_id }), auth);
617
+ if (result && typeof result === 'object') {
618
+ for (const stepTag of Object.keys(result)) {
619
+ const data = result[stepTag];
620
+ if (data === null || data === void 0 ? void 0 : data.product_id) {
621
+ this.product_id = data.product_id;
622
+ }
623
+ if ((data === null || data === void 0 ? void 0 : data.notification) && (data === null || data === void 0 ? void 0 : data.private_key)) {
624
+ result[stepTag] = Object.assign(Object.assign({}, data), { notification: this.decryptNotificationChannelConfigs(data.notification, data.private_key) });
625
+ }
503
626
  }
504
627
  }
505
- }
506
- return result !== null && result !== void 0 ? result : {};
628
+ return result !== null && result !== void 0 ? result : {};
629
+ });
507
630
  }
508
631
  catch (e) {
509
632
  throw e;
@@ -519,7 +642,7 @@ class ProductsBuilderService {
519
642
  }
520
643
  async updateProduct(data) {
521
644
  try {
522
- if (!this.app_id)
645
+ if (!this.product_id)
523
646
  throw new Error('Product not initialized');
524
647
  await validators_1.CreateProductBuilderSchema.validateAsync(data);
525
648
  await this.productApi.updateProduct(this.product_id, Object.assign({}, data), this.getUserAccess());
@@ -1072,20 +1195,7 @@ class ProductsBuilderService {
1072
1195
  data.total_init = 0;
1073
1196
  await Promise.all(data.options.map(async (d) => {
1074
1197
  data.total_quota += d.quota;
1075
- if (d.type === productsBuilder_types_1.FeatureEventTypes.ACTION) {
1076
- const app = await this.fetchThirdPartyAppByAccessTag(d.app);
1077
- if (!app) {
1078
- throw new Error(`App with access tag ${d.app} not found`);
1079
- }
1080
- const version = app.versions.find((version) => version.tag === app.version);
1081
- const action = version.actions.find((action) => action.tag === d.event);
1082
- if (!action) {
1083
- throw new Error(`Cannot find action ${d.event} on app ${app.tag} version ${app.version}`);
1084
- }
1085
- if (d.healthcheck) {
1086
- await this.validateProviderHealthcheckTag(d);
1087
- }
1088
- }
1198
+ await this.validateQuotaFallbackProvider(d);
1089
1199
  d.last_checked = new Date();
1090
1200
  d.provider_status = productsBuilder_types_1.ProviderStatus.AVAILABLE;
1091
1201
  d.last_available = true;
@@ -1110,20 +1220,7 @@ class ProductsBuilderService {
1110
1220
  data.tag = tag;
1111
1221
  await Promise.all(data.options.map(async (d) => {
1112
1222
  data.total_quota += d.quota;
1113
- if (d.type === productsBuilder_types_1.FeatureEventTypes.ACTION) {
1114
- const app = await this.fetchThirdPartyAppByAccessTag(d.app);
1115
- if (!app) {
1116
- throw new Error(`App with access tag ${d.app} not found`);
1117
- }
1118
- const version = app.versions.find((version) => version.tag === app.version);
1119
- const action = version.actions.find((action) => action.tag === d.event);
1120
- if (!action) {
1121
- throw new Error(`Cannot find action ${d.event} on app ${app.tag} version ${app.version}`);
1122
- }
1123
- if (d.healthcheck) {
1124
- await this.validateProviderHealthcheckTag(d);
1125
- }
1126
- }
1223
+ await this.validateQuotaFallbackProvider(d);
1127
1224
  d.last_checked = new Date();
1128
1225
  d.provider_status = productsBuilder_types_1.ProviderStatus.AVAILABLE;
1129
1226
  d.last_available = true;
@@ -1179,20 +1276,7 @@ class ProductsBuilderService {
1179
1276
  await validators_1.CreateProductFallbackSchema.validateAsync(data);
1180
1277
  await this.validateQuotaFallbackInputAndOutput(data, 'fallback');
1181
1278
  await Promise.all(data.options.map(async (d) => {
1182
- if (d.type === productsBuilder_types_1.FeatureEventTypes.ACTION) {
1183
- const app = await this.fetchThirdPartyAppByAccessTag(d.app);
1184
- if (!app) {
1185
- throw new Error(`App with access tag ${d.app} not found`);
1186
- }
1187
- const version = app.versions.find((version) => version.tag === app.version);
1188
- const action = version.actions.find((action) => action.tag === d.event);
1189
- if (!action) {
1190
- throw new Error(`Cannot find action ${d.event} on app ${app.tag} version ${app.version}`);
1191
- }
1192
- if (d.healthcheck) {
1193
- await this.validateProviderHealthcheckTag(d);
1194
- }
1195
- }
1279
+ await this.validateQuotaFallbackProvider(d);
1196
1280
  d.last_checked = new Date();
1197
1281
  d.provider_status = productsBuilder_types_1.ProviderStatus.AVAILABLE;
1198
1282
  d.last_available = true;
@@ -1214,20 +1298,7 @@ class ProductsBuilderService {
1214
1298
  await this.validateQuotaFallbackInputAndOutput(data, 'fallback');
1215
1299
  data.tag = tag;
1216
1300
  await Promise.all(data.options.map(async (d) => {
1217
- if (d.type === productsBuilder_types_1.FeatureEventTypes.ACTION) {
1218
- const app = await this.fetchThirdPartyAppByAccessTag(d.app);
1219
- if (!app) {
1220
- throw new Error(`App with access tag ${d.app} not found`);
1221
- }
1222
- const version = app.versions.find((version) => version.tag === app.version);
1223
- const action = version.actions.find((action) => action.tag === d.event);
1224
- if (!action) {
1225
- throw new Error(`Cannot find action ${d.event} on app ${app.tag} version ${app.version}`);
1226
- }
1227
- if (d.healthcheck) {
1228
- await this.validateProviderHealthcheckTag(d);
1229
- }
1230
- }
1301
+ await this.validateQuotaFallbackProvider(d);
1231
1302
  d.last_checked = new Date();
1232
1303
  d.provider_status = productsBuilder_types_1.ProviderStatus.AVAILABLE;
1233
1304
  d.last_available = true;
@@ -1353,12 +1424,7 @@ class ProductsBuilderService {
1353
1424
  const auth = this.getUserAccess();
1354
1425
  const cloudApi = new cloudApi_service_1.CloudApiService(this.env_type);
1355
1426
  const productTag = this.product.tag;
1356
- const materializedEnvs = await Promise.all((data.envs || []).map((env) => (0, cloud_broker_link_util_1.materializeCloudLinkedBrokerEnv)(env, {
1357
- cloudApi,
1358
- auth,
1359
- productTag,
1360
- brokerTag: data.tag,
1361
- })));
1427
+ const materializedEnvs = await (0, cloud_materialize_util_1.materializeCloudEnvsSequential)(data.envs || [], { cloudApi, auth, productTag }, (env, batchCtx) => (0, cloud_broker_link_util_1.materializeCloudLinkedBrokerEnv)(env, Object.assign(Object.assign({}, batchCtx), { brokerTag: data.tag })));
1362
1428
  data.envs = materializedEnvs;
1363
1429
  console.log(`${logPrefix} Validating schema...`);
1364
1430
  await validators_1.CreateMessageBrokerSchema.validateAsync(data);
@@ -1603,16 +1669,7 @@ class ProductsBuilderService {
1603
1669
  const auth = this.getUserAccess();
1604
1670
  const cloudApi = new cloudApi_service_1.CloudApiService(this.env_type);
1605
1671
  const productTag = this.product.tag;
1606
- const materializedEnvs = [];
1607
- for (const env of data.envs || []) {
1608
- materializedEnvs.push(await (0, storage_cloud_link_util_1.materializeCloudLinkedStorageEnv)(env, {
1609
- cloudApi,
1610
- auth,
1611
- productTag,
1612
- storageTag: data.tag,
1613
- }));
1614
- }
1615
- data.envs = materializedEnvs;
1672
+ data.envs = await (0, cloud_materialize_util_1.materializeCloudEnvsSequential)(data.envs || [], { cloudApi, auth, productTag }, (env, batchCtx) => (0, storage_cloud_link_util_1.materializeCloudLinkedStorageEnv)(env, Object.assign(Object.assign({}, batchCtx), { storageTag: data.tag })));
1616
1673
  await create_productStorage_validator_1.CreateProductStorageSchema.validateAsync(data);
1617
1674
  const processedEnvs = [];
1618
1675
  for (const env of data.envs) {
@@ -1782,12 +1839,7 @@ class ProductsBuilderService {
1782
1839
  const auth = this.getUserAccess();
1783
1840
  const cloudApi = new cloudApi_service_1.CloudApiService(this.env_type);
1784
1841
  const productTag = this.product.tag;
1785
- const materializedEnvs = await Promise.all((data.envs || []).map((env) => (0, cloud_vector_link_util_1.materializeCloudLinkedVectorEnv)(env, {
1786
- cloudApi,
1787
- auth,
1788
- productTag,
1789
- vectorTag: data.tag,
1790
- })));
1842
+ const materializedEnvs = await (0, cloud_materialize_util_1.materializeCloudEnvsSequential)(data.envs || [], { cloudApi, auth, productTag }, (env, batchCtx) => (0, cloud_vector_link_util_1.materializeCloudLinkedVectorEnv)(env, Object.assign(Object.assign({}, batchCtx), { vectorTag: data.tag })));
1791
1843
  data.envs = materializedEnvs;
1792
1844
  await validators_1.CreateProductVectorSchema.validateAsync(data);
1793
1845
  const processedEnvs = [];
@@ -2424,9 +2476,13 @@ class ProductsBuilderService {
2424
2476
  }
2425
2477
  async validateAppData(appData, app) {
2426
2478
  // TODO:
2479
+ var _a;
2427
2480
  const { envs } = app;
2428
2481
  // const { envs: appEnvs, auths: appAuths } = appData
2429
- const version = appData.versions.find((data) => (data.latest = true));
2482
+ const version = (_a = appData.versions.find((data) => data.latest === true)) !== null && _a !== void 0 ? _a : appData.versions[0];
2483
+ if (!version) {
2484
+ throw new Error(`App ${appData.tag} has no versions`);
2485
+ }
2430
2486
  app.envs = this.validateAppEnvs(envs, version);
2431
2487
  // await this.validateAppAuth(auth, appData);
2432
2488
  return app;
@@ -2559,31 +2615,114 @@ class ProductsBuilderService {
2559
2615
  }
2560
2616
  return { data: updateData, values: updateValues };
2561
2617
  }
2562
- async createAppAccessTag(app_tag) {
2618
+ async createAppAccessTag(app_tag, known_app_id) {
2563
2619
  await this.initializeWorkspace();
2564
2620
  const { name: workspace_name } = this.workspace;
2565
- const app = await this.appApi.fetchAppByTag(app_tag, this.getUserAccess());
2566
- if (!app) {
2567
- throw new Error(`App ${app_tag} not found`);
2621
+ let app_id = known_app_id === null || known_app_id === void 0 ? void 0 : known_app_id.trim();
2622
+ if (!app_id) {
2623
+ const app = await this.appApi.fetchAppByTag(app_tag, this.getUserAccess());
2624
+ if (!app) {
2625
+ throw new Error(`App ${app_tag} not found`);
2626
+ }
2627
+ app_id = String(app._id);
2568
2628
  }
2569
- const { _id: app_id } = app;
2570
2629
  const accessTag = `${app_tag}:${(0, string_utils_2.tagify)(workspace_name)}`;
2571
- const { access, access_tag } = await this.appApi.createAppAccess(app_id, this.product_id, accessTag, this.getUserAccess());
2572
- return {
2573
- access_tag,
2574
- access,
2575
- };
2630
+ try {
2631
+ const existing = await this.appApi.fetchAccessByTag(accessTag, this.getUserAccess());
2632
+ if ((existing === null || existing === void 0 ? void 0 : existing.access_tag) && (await this.accessAppIsLive(existing))) {
2633
+ return {
2634
+ access_tag: existing.access_tag,
2635
+ access: existing.access,
2636
+ };
2637
+ }
2638
+ }
2639
+ catch (_a) {
2640
+ // no existing access row — create below
2641
+ }
2642
+ try {
2643
+ const { access, access_tag } = await this.appApi.createAppAccess(app_id, this.product_id, accessTag, this.getUserAccess());
2644
+ return {
2645
+ access_tag,
2646
+ access,
2647
+ };
2648
+ }
2649
+ catch (e) {
2650
+ try {
2651
+ const existing = await this.appApi.fetchAccessByTag(accessTag, this.getUserAccess());
2652
+ if ((existing === null || existing === void 0 ? void 0 : existing.access_tag) && (await this.accessAppIsLive(existing))) {
2653
+ return {
2654
+ access_tag: existing.access_tag,
2655
+ access: existing.access,
2656
+ };
2657
+ }
2658
+ }
2659
+ catch (_b) {
2660
+ // fall through to original error
2661
+ }
2662
+ throw e;
2663
+ }
2664
+ }
2665
+ async accessAppIsLive(access) {
2666
+ const appId = (access === null || access === void 0 ? void 0 : access.app_id) == null ? '' : String(access.app_id).trim();
2667
+ if (!appId)
2668
+ return false;
2669
+ try {
2670
+ const appData = await this.appApi.fetchApp(appId, this.getUserAccess());
2671
+ return appData != null;
2672
+ }
2673
+ catch (_a) {
2674
+ return false;
2675
+ }
2576
2676
  }
2577
2677
  async addApp(app, throwErrorIfExists = false) {
2678
+ var _a, _b, _c, _d, _e, _f;
2578
2679
  try {
2579
2680
  await validators_1.CreateProductAppSchema.validateAsync(app);
2580
2681
  // TODO: figure out a way to check if this has run before, halt if it has
2581
2682
  if (!await this.fetchApp(app.access_tag, throwErrorIfExists)) {
2582
- const _a = await this.appApi.fetchAccessByTag(app.access_tag, this.getUserAccess()), { version } = _a, access = __rest(_a, ["version"]);
2583
- if (!access) {
2584
- throw new Error(`Access to app ${app.access_tag} not found`);
2683
+ let access = null;
2684
+ try {
2685
+ const fetched = await this.appApi.fetchAccessByTag(app.access_tag, this.getUserAccess());
2686
+ access = fetched ? Object.assign({}, fetched) : null;
2687
+ }
2688
+ catch (_g) {
2689
+ access = null;
2690
+ }
2691
+ if (access === null || access === void 0 ? void 0 : access.app_id) {
2692
+ const liveApp = await this.appApi.fetchApp(access.app_id, this.getUserAccess());
2693
+ if (!liveApp) {
2694
+ access = null;
2695
+ }
2585
2696
  }
2586
- const appData = await this.appApi.fetchApp(access.app_id, this.getUserAccess());
2697
+ if (!(access === null || access === void 0 ? void 0 : access.app_id)) {
2698
+ const wsSuffix = `:${(0, string_utils_2.tagify)(this.workspace.name)}`;
2699
+ const appTag = app.access_tag.endsWith(wsSuffix)
2700
+ ? app.access_tag.slice(0, -wsSuffix.length)
2701
+ : '';
2702
+ if (!appTag) {
2703
+ throw new Error(`Access to app ${app.access_tag} not found`);
2704
+ }
2705
+ const appRow = await this.appApi.fetchAppByTag(appTag, this.getUserAccess());
2706
+ if (!(appRow === null || appRow === void 0 ? void 0 : appRow._id)) {
2707
+ throw new Error(`App not found for tag ${appTag}`);
2708
+ }
2709
+ const created = await this.appApi.createAppAccess(String(appRow._id), this.product_id, app.access_tag, this.getUserAccess());
2710
+ const auth = this.getUserAccess();
2711
+ const latestVersion = (_f = (_c = (_b = (_a = appRow.versions) === null || _a === void 0 ? void 0 : _a.find((v) => v.latest)) === null || _b === void 0 ? void 0 : _b.tag) !== null && _c !== void 0 ? _c : (_e = (_d = appRow.versions) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.tag) !== null && _f !== void 0 ? _f : '';
2712
+ access = {
2713
+ workspace_id: auth.workspace_id,
2714
+ user_id: auth.user_id,
2715
+ public_key: auth.public_key,
2716
+ token: auth.token,
2717
+ product_id: this.product_id,
2718
+ app_id: String(appRow._id),
2719
+ access_tag: created.access_tag,
2720
+ access: created.access,
2721
+ version: latestVersion,
2722
+ };
2723
+ }
2724
+ const _h = access, { version } = _h, accessFields = __rest(_h, ["version"]);
2725
+ const appData = await this.appApi.fetchApp(accessFields.app_id, this.getUserAccess());
2587
2726
  if (!appData) {
2588
2727
  throw new Error(`App ${app.access_tag} not found`);
2589
2728
  }
@@ -4243,12 +4382,7 @@ class ProductsBuilderService {
4243
4382
  const auth = this.getUserAccess();
4244
4383
  const cloudApi = new cloudApi_service_1.CloudApiService(this.env_type);
4245
4384
  const productTag = this.product.tag;
4246
- data.envs = (await Promise.all((data.envs || []).map(async (env) => (0, cloud_database_link_util_1.materializeCloudLinkedDatabaseEnv)(env, {
4247
- cloudApi,
4248
- auth,
4249
- productTag,
4250
- databaseTag: data.tag,
4251
- })))).map((env) => {
4385
+ data.envs = (await (0, cloud_materialize_util_1.materializeCloudEnvsSequential)(data.envs || [], { cloudApi, auth, productTag }, (env, batchCtx) => (0, cloud_database_link_util_1.materializeCloudLinkedDatabaseEnv)(env, Object.assign(Object.assign({}, batchCtx), { databaseTag: data.tag })))).map((env) => {
4252
4386
  const _a = env, { masterPassword: _mp, importExisting: _ie } = _a, rest = __rest(_a, ["masterPassword", "importExisting"]);
4253
4387
  return rest;
4254
4388
  });
@@ -4301,12 +4435,7 @@ class ProductsBuilderService {
4301
4435
  const auth = this.getUserAccess();
4302
4436
  const cloudApi = new cloudApi_service_1.CloudApiService(this.env_type);
4303
4437
  const productTag = this.product.tag;
4304
- data.envs = await Promise.all(data.envs.map(async (env) => (0, cloud_database_link_util_1.materializeCloudLinkedDatabaseEnv)(env, {
4305
- cloudApi,
4306
- auth,
4307
- productTag,
4308
- databaseTag: data.tag || tag,
4309
- })));
4438
+ data.envs = await (0, cloud_materialize_util_1.materializeCloudEnvsSequential)(data.envs, { cloudApi, auth, productTag }, (env, batchCtx) => (0, cloud_database_link_util_1.materializeCloudLinkedDatabaseEnv)(env, Object.assign(Object.assign({}, batchCtx), { databaseTag: data.tag || tag })));
4310
4439
  }
4311
4440
  await validators_1.UpdateProductDatabaseSchema.validateAsync(data);
4312
4441
  if (data.envs && data.envs.length > 0) {
@@ -4378,6 +4507,24 @@ class ProductsBuilderService {
4378
4507
  }
4379
4508
  return component;
4380
4509
  }
4510
+ /** Resolve database config from in-memory product cache, falling back to API fetch. */
4511
+ async resolveDatabaseConfig(databaseTag) {
4512
+ var _a;
4513
+ const cached = ((_a = this.product.databases) !== null && _a !== void 0 ? _a : []).find((data) => data.tag === databaseTag);
4514
+ if (cached)
4515
+ return cached;
4516
+ return this.fetchDatabase(databaseTag);
4517
+ }
4518
+ normalizeDatabaseTriggers(database) {
4519
+ const raw = database.triggers;
4520
+ if (!raw)
4521
+ return [];
4522
+ if (Array.isArray(raw))
4523
+ return raw;
4524
+ if (typeof raw === 'object')
4525
+ return Object.values(raw);
4526
+ return [];
4527
+ }
4381
4528
  async deleteDatabase(tag) {
4382
4529
  try {
4383
4530
  const database = await this.fetchDatabase(tag);
@@ -4409,12 +4556,7 @@ class ProductsBuilderService {
4409
4556
  const auth = this.getUserAccess();
4410
4557
  const cloudApi = new cloudApi_service_1.CloudApiService(this.env_type);
4411
4558
  const productTag = this.product.tag;
4412
- const materializedEnvs = await Promise.all((data.envs || []).map((env) => (0, cloud_graph_link_util_1.materializeCloudLinkedGraphEnv)(env, {
4413
- cloudApi,
4414
- auth,
4415
- productTag,
4416
- graphTag: data.tag,
4417
- })));
4559
+ const materializedEnvs = await (0, cloud_materialize_util_1.materializeCloudEnvsSequential)(data.envs || [], { cloudApi, auth, productTag }, (env, batchCtx) => (0, cloud_graph_link_util_1.materializeCloudLinkedGraphEnv)(env, Object.assign(Object.assign({}, batchCtx), { graphTag: data.tag })));
4418
4560
  data.envs = materializedEnvs;
4419
4561
  await validators_1.CreateProductGraphSchema.validateAsync(data);
4420
4562
  const processedEnvs = [];
@@ -4766,14 +4908,15 @@ class ProductsBuilderService {
4766
4908
  }
4767
4909
  }
4768
4910
  async fetchDatabaseAction(tag, throwErrorIfExists = false) {
4911
+ var _a;
4769
4912
  const [databaseTag, actionTag] = tag.split(':');
4770
4913
  if (!databaseTag || !actionTag) {
4771
4914
  throw new Error(`tag is expected to be defined as "database_tag:action_tag"`);
4772
4915
  }
4773
- const database = this.product.databases.find((data) => data.tag === databaseTag);
4916
+ const database = await this.resolveDatabaseConfig(databaseTag);
4774
4917
  if (!database)
4775
4918
  throw new Error(`Database ${databaseTag} not found`);
4776
- const action = database.actions.find((data) => data.tag === actionTag);
4919
+ const action = ((_a = database.actions) !== null && _a !== void 0 ? _a : []).find((data) => data.tag === actionTag);
4777
4920
  if (!action && throwErrorIfExists)
4778
4921
  throw new Error(`Database action ${tag} not found`);
4779
4922
  if (database.type === productsBuilder_types_1.DatabaseTypes.MONGODB && action) {
@@ -4826,10 +4969,11 @@ class ProductsBuilderService {
4826
4969
  }
4827
4970
  }
4828
4971
  async fetchDatabaseActions(databaseTag) {
4829
- const database = this.product.databases.find((data) => data.tag === databaseTag);
4972
+ var _a;
4973
+ const database = await this.resolveDatabaseConfig(databaseTag);
4830
4974
  if (!database)
4831
4975
  throw new Error(`Database ${databaseTag} not found`);
4832
- const actions = database.actions;
4976
+ const actions = (_a = database.actions) !== null && _a !== void 0 ? _a : [];
4833
4977
  if (database.type === productsBuilder_types_1.DatabaseTypes.MONGODB && actions.length) {
4834
4978
  /*return actions.map((data)=>{
4835
4979
  return{ ...data,template: JSON.parse(String(data.template))}
@@ -4933,24 +5077,25 @@ class ProductsBuilderService {
4933
5077
  await this.productApi.updateProduct(this.product_id, Object.assign(Object.assign(Object.assign({}, existing), data), { value: processedValue || existing.value, databaseTag, component: enums_1.ProductComponents.DATABASE_MIGRATION }), this.getUserAccess());
4934
5078
  }
4935
5079
  async fetchDatabaseMigration(tag, throwError = false) {
5080
+ var _a;
4936
5081
  const [databaseTag, migrationTag] = tag.split(':');
4937
5082
  if (!databaseTag || !migrationTag) {
4938
5083
  throw new Error(`tag is expected to be defined as "database_tag:action_tag"`);
4939
5084
  }
4940
- const database = this.product.databases.find((data) => data.tag === databaseTag);
5085
+ const database = await this.resolveDatabaseConfig(databaseTag);
4941
5086
  if (!database)
4942
5087
  throw new Error(`Database ${databaseTag} not found`);
4943
- const migration = database.migrations.find((data) => data.tag === migrationTag);
5088
+ const migration = ((_a = database.migrations) !== null && _a !== void 0 ? _a : []).find((data) => data.tag === migrationTag);
4944
5089
  if (!migration && throwError)
4945
5090
  throw new Error(`Database migration ${tag} not found`);
4946
5091
  return migration;
4947
5092
  }
4948
5093
  async fetchDatabaseMigrations(databaseTag) {
4949
- const database = this.product.databases.find((data) => data.tag === databaseTag);
5094
+ var _a;
5095
+ const database = await this.resolveDatabaseConfig(databaseTag);
4950
5096
  if (!database)
4951
5097
  throw new Error(`Database ${databaseTag} not found`);
4952
- const migrations = database.migrations;
4953
- return migrations;
5098
+ return (_a = database.migrations) !== null && _a !== void 0 ? _a : [];
4954
5099
  }
4955
5100
  async deleteDatabaseMigration(tag) {
4956
5101
  try {
@@ -5028,21 +5173,19 @@ class ProductsBuilderService {
5028
5173
  if (!databaseTag || !triggerTag) {
5029
5174
  throw new Error(`tag is expected to be defined as "database_tag:trigger_tag"`);
5030
5175
  }
5031
- const database = this.product.databases.find((data) => data.tag === databaseTag);
5176
+ const database = await this.resolveDatabaseConfig(databaseTag);
5032
5177
  if (!database)
5033
5178
  throw new Error(`Database ${databaseTag} not found`);
5034
- const triggers = database.triggers || [];
5035
- const trigger = triggers.find((data) => data.tag === triggerTag);
5179
+ const trigger = this.normalizeDatabaseTriggers(database).find((data) => data.tag === triggerTag);
5036
5180
  if (!trigger && throwError)
5037
5181
  throw new Error(`Database trigger ${tag} not found`);
5038
5182
  return trigger || null;
5039
5183
  }
5040
5184
  async fetchDatabaseTriggers(databaseTag) {
5041
- const database = this.product.databases.find((data) => data.tag === databaseTag);
5185
+ const database = await this.resolveDatabaseConfig(databaseTag);
5042
5186
  if (!database)
5043
5187
  throw new Error(`Database ${databaseTag} not found`);
5044
- const triggers = database.triggers || [];
5045
- return triggers;
5188
+ return this.normalizeDatabaseTriggers(database);
5046
5189
  }
5047
5190
  async deleteDatabaseTrigger(tag) {
5048
5191
  try {