@things-factory/integration-base 10.1.233 → 10.1.236

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 (28) hide show
  1. package/dist-server/controllers/scenario-controller.js +6 -4
  2. package/dist-server/controllers/scenario-controller.js.map +1 -1
  3. package/dist-server/engine/scenario-engine.d.ts +5 -1
  4. package/dist-server/engine/scenario-engine.js +4 -0
  5. package/dist-server/engine/scenario-engine.js.map +1 -1
  6. package/dist-server/engine/task/local-graphql-mutate.js +6 -1
  7. package/dist-server/engine/task/local-graphql-mutate.js.map +1 -1
  8. package/dist-server/engine/task/local-graphql-query.js +6 -1
  9. package/dist-server/engine/task/local-graphql-query.js.map +1 -1
  10. package/dist-server/index.js +4 -0
  11. package/dist-server/index.js.map +1 -1
  12. package/dist-server/role-tasks.d.ts +2 -0
  13. package/dist-server/role-tasks.js +16 -0
  14. package/dist-server/role-tasks.js.map +1 -0
  15. package/dist-server/service/connection/connection-mutation.js +18 -0
  16. package/dist-server/service/connection/connection-mutation.js.map +1 -1
  17. package/dist-server/service/scenario/scenario-mutation.js +11 -1
  18. package/dist-server/service/scenario/scenario-mutation.js.map +1 -1
  19. package/dist-server/service/scenario-instance/scenario-instance-mutation.js +2 -1
  20. package/dist-server/service/scenario-instance/scenario-instance-mutation.js.map +1 -1
  21. package/dist-server/tsconfig.tsbuildinfo +1 -1
  22. package/package.json +10 -10
  23. package/translations/en.json +9 -1
  24. package/translations/es.json +9 -1
  25. package/translations/ja.json +9 -1
  26. package/translations/ko.json +9 -1
  27. package/translations/ms.json +9 -1
  28. package/translations/zh.json +9 -1
@@ -62,14 +62,16 @@ async function runScenario(instanceName, scenarioName, variables, context, mode
62
62
  }
63
63
  /* 시나리오 인스턴스를 생성한다. */
64
64
  instanceName = instanceName || scenarioName + '-' + String(Date.now());
65
+ /*
66
+ * The one who ran it is told why it failed - the step's own error - not a null result nor 「관리자에게 문의」
67
+ * (the user, 2026-10-31).
68
+ */
65
69
  try {
66
- return await scenario_engine_1.ScenarioEngine.run(instanceName, scenario, { domain, user, lng, variables });
70
+ return await scenario_engine_1.ScenarioEngine.runInstance(instanceName, scenario, { domain, user, lng, variables });
67
71
  }
68
72
  catch (err) {
69
73
  console.error(err);
70
- throw new Error(context.t('error.scenario run error', {
71
- scenario: scenarioName
72
- }));
74
+ throw new shell_1.Refusal('scenario-run-failed', { scenario: scenarioName, reason: err?.message || String(err) }, `The scenario '${scenarioName}' failed: ${err?.message || err}`);
73
75
  }
74
76
  }
75
77
  async function startScenario(instanceName, scenarioName, variables, context, mode = 'released') {
@@ -1 +1 @@
1
- {"version":3,"file":"scenario-controller.js","sourceRoot":"","sources":["../../server/controllers/scenario-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { getRepository, Domain, GraphqlLocalClient, getDomainIdsWithAncestors } from '@things-factory/shell'\nimport { checkUserHasRole } from '@things-factory/auth-base'\nimport { cacheService } from '@things-factory/cache-service'\n\nimport { ScenarioEngine } from '../engine/scenario-engine'\nimport { Scenario } from '../service/scenario/scenario'\nimport { resolveRunnableSteps } from '../service/scenario/resolve-steps'\nimport {\n ScenarioInstance,\n ScenarioInstanceRunResult,\n ScenarioInstanceStartResult\n} from '../service/scenario-instance/scenario-instance-type'\nimport { Step } from '../service/step/step-type'\n\nconst debug = require('debug')('things-factory:integration-base:controller:run-scenario')\n\n/**\n * 실행할 시나리오를 찾아 실행 대상 steps 를 주입한다.\n *\n * [버전관리] 기본 mode='released' — 운영 실행은 최신 릴리즈 스냅샷을 사용한다.\n * 릴리즈된 버전이 없으면 draft 로 폴백(resolveRunnableSteps 내부 처리).\n * mode='draft' 는 디버깅 실행(편집 중 draft 를 그대로 실행) 용.\n */\nasync function findScenario(\n scenarioName: string,\n domain: Domain,\n mode: 'released' | 'draft' = 'released'\n): Promise<{\n id: string\n ttl: number\n name: string\n steps: Step[]\n domain: Domain\n}> {\n var repository = getRepository(Scenario)\n\n // ancestor 도메인을 closest-first 로 순회하여 first hit 사용\n const domainIds = await getDomainIdsWithAncestors(domain)\n var scenario: Scenario | null = null\n for (const did of domainIds) {\n scenario = await repository.findOne({\n where: { domain: { id: did }, name: scenarioName },\n relations: ['domain', 'role', 'creator', 'updater']\n })\n if (scenario) break\n }\n\n if (scenario) {\n scenario.steps = await resolveRunnableSteps(scenario, { mode })\n }\n\n return scenario as any\n}\n\nexport async function checkHasRole(scenario: Partial<Scenario>, context: ResolverContext): Promise<void> {\n const { domain, user } = context.state\n if (!(await checkUserHasRole(scenario.roleId, domain, user))) {\n throw new Error(\n context.t('error.scenario run unauthorized', {\n scenario: scenario.name\n })\n )\n }\n}\n\nexport async function runScenario(\n instanceName: string,\n scenarioName: string,\n variables: any,\n context: ResolverContext,\n mode: 'released' | 'draft' = 'released'\n): Promise<ScenarioInstanceRunResult> {\n const { domain, user, lng } = context.state\n\n debug('runScenario', scenarioName, instanceName, variables, mode)\n\n var scenario = await findScenario(scenarioName, domain, mode)\n\n if (!scenario) {\n throw new Error(\n context.t('error.scenario not found', {\n scenario: scenarioName\n })\n )\n }\n\n await checkHasRole(scenario, context)\n\n if (scenario.ttl > 0) {\n const cachedValue = await cacheService.getFromCache(scenario.id, { domain: domain.id, variables: variables || {} })\n if (cachedValue) {\n return cachedValue.value\n }\n }\n\n /* 시나리오 인스턴스를 생성한다. */\n instanceName = instanceName || scenarioName + '-' + String(Date.now())\n\n try {\n return await ScenarioEngine.run(instanceName, scenario, { domain, user, lng, variables })\n } catch (err) {\n console.error(err)\n\n throw new Error(\n context.t('error.scenario run error', {\n scenario: scenarioName\n })\n )\n }\n}\n\nexport async function startScenario(\n instanceName: string,\n scenarioName: string,\n variables: any,\n context: ResolverContext,\n mode: 'released' | 'draft' = 'released'\n): Promise<ScenarioInstanceStartResult> {\n const { domain, user, lng } = context.state\n\n debug('startScenario', instanceName, scenarioName, variables, mode)\n\n var scenario = await findScenario(scenarioName, domain, mode)\n\n if (!scenario) {\n throw new Error(\n context.t('error.scenario not found', {\n scenario: scenarioName\n })\n )\n }\n\n await checkHasRole(scenario, context)\n\n instanceName = instanceName || scenarioName\n return await ScenarioEngine.loadIteration(instanceName, scenario, { domain, user, lng, variables })\n}\n\nexport async function stopScenario(\n instanceName: string,\n context: ResolverContext\n): Promise<ScenarioInstance | undefined> {\n const { domain, user, unsafeIP, prohibitedPrivileges } = context.state\n\n debug('stopScenario', instanceName)\n\n var scenarioInstance = ScenarioEngine.getScenarioInstance(domain, instanceName)\n\n if (!scenarioInstance) {\n debug('stopScenario', `ScenarioInstance(${instanceName}) Not Found.`)\n throw new Error(\n context.t('error.scenario instance not found', {\n instance: instanceName\n })\n )\n }\n\n var scenario = await findScenario(scenarioInstance.scenarioName, domain)\n\n await checkHasRole(scenario, context)\n\n await ScenarioEngine.unload(domain, instanceName)\n\n return scenarioInstance\n}\n"]}
1
+ {"version":3,"file":"scenario-controller.js","sourceRoot":"","sources":["../../server/controllers/scenario-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { getRepository, Domain, GraphqlLocalClient, getDomainIdsWithAncestors, Refusal } from '@things-factory/shell'\nimport { checkUserHasRole } from '@things-factory/auth-base'\nimport { cacheService } from '@things-factory/cache-service'\n\nimport { ScenarioEngine } from '../engine/scenario-engine'\nimport { Scenario } from '../service/scenario/scenario'\nimport { resolveRunnableSteps } from '../service/scenario/resolve-steps'\nimport {\n ScenarioInstance,\n ScenarioInstanceRunResult,\n ScenarioInstanceStartResult\n} from '../service/scenario-instance/scenario-instance-type'\nimport { Step } from '../service/step/step-type'\n\nconst debug = require('debug')('things-factory:integration-base:controller:run-scenario')\n\n/**\n * 실행할 시나리오를 찾아 실행 대상 steps 를 주입한다.\n *\n * [버전관리] 기본 mode='released' — 운영 실행은 최신 릴리즈 스냅샷을 사용한다.\n * 릴리즈된 버전이 없으면 draft 로 폴백(resolveRunnableSteps 내부 처리).\n * mode='draft' 는 디버깅 실행(편집 중 draft 를 그대로 실행) 용.\n */\nasync function findScenario(\n scenarioName: string,\n domain: Domain,\n mode: 'released' | 'draft' = 'released'\n): Promise<{\n id: string\n ttl: number\n name: string\n steps: Step[]\n domain: Domain\n}> {\n var repository = getRepository(Scenario)\n\n // ancestor 도메인을 closest-first 로 순회하여 first hit 사용\n const domainIds = await getDomainIdsWithAncestors(domain)\n var scenario: Scenario | null = null\n for (const did of domainIds) {\n scenario = await repository.findOne({\n where: { domain: { id: did }, name: scenarioName },\n relations: ['domain', 'role', 'creator', 'updater']\n })\n if (scenario) break\n }\n\n if (scenario) {\n scenario.steps = await resolveRunnableSteps(scenario, { mode })\n }\n\n return scenario as any\n}\n\nexport async function checkHasRole(scenario: Partial<Scenario>, context: ResolverContext): Promise<void> {\n const { domain, user } = context.state\n if (!(await checkUserHasRole(scenario.roleId, domain, user))) {\n throw new Error(\n context.t('error.scenario run unauthorized', {\n scenario: scenario.name\n })\n )\n }\n}\n\nexport async function runScenario(\n instanceName: string,\n scenarioName: string,\n variables: any,\n context: ResolverContext,\n mode: 'released' | 'draft' = 'released'\n): Promise<ScenarioInstanceRunResult> {\n const { domain, user, lng } = context.state\n\n debug('runScenario', scenarioName, instanceName, variables, mode)\n\n var scenario = await findScenario(scenarioName, domain, mode)\n\n if (!scenario) {\n throw new Error(\n context.t('error.scenario not found', {\n scenario: scenarioName\n })\n )\n }\n\n await checkHasRole(scenario, context)\n\n if (scenario.ttl > 0) {\n const cachedValue = await cacheService.getFromCache(scenario.id, { domain: domain.id, variables: variables || {} })\n if (cachedValue) {\n return cachedValue.value\n }\n }\n\n /* 시나리오 인스턴스를 생성한다. */\n instanceName = instanceName || scenarioName + '-' + String(Date.now())\n\n /*\n * The one who ran it is told why it failed - the step's own error - not a null result nor 「관리자에게 문의」\n * (the user, 2026-10-31).\n */\n try {\n return await ScenarioEngine.runInstance(instanceName, scenario, { domain, user, lng, variables })\n } catch (err) {\n console.error(err)\n\n throw new Refusal(\n 'scenario-run-failed',\n { scenario: scenarioName, reason: (err as Error)?.message || String(err) },\n `The scenario '${scenarioName}' failed: ${(err as Error)?.message || err}`\n )\n }\n}\n\nexport async function startScenario(\n instanceName: string,\n scenarioName: string,\n variables: any,\n context: ResolverContext,\n mode: 'released' | 'draft' = 'released'\n): Promise<ScenarioInstanceStartResult> {\n const { domain, user, lng } = context.state\n\n debug('startScenario', instanceName, scenarioName, variables, mode)\n\n var scenario = await findScenario(scenarioName, domain, mode)\n\n if (!scenario) {\n throw new Error(\n context.t('error.scenario not found', {\n scenario: scenarioName\n })\n )\n }\n\n await checkHasRole(scenario, context)\n\n instanceName = instanceName || scenarioName\n return await ScenarioEngine.loadIteration(instanceName, scenario, { domain, user, lng, variables })\n}\n\nexport async function stopScenario(\n instanceName: string,\n context: ResolverContext\n): Promise<ScenarioInstance | undefined> {\n const { domain, user, unsafeIP, prohibitedPrivileges } = context.state\n\n debug('stopScenario', instanceName)\n\n var scenarioInstance = ScenarioEngine.getScenarioInstance(domain, instanceName)\n\n if (!scenarioInstance) {\n debug('stopScenario', `ScenarioInstance(${instanceName}) Not Found.`)\n throw new Error(\n context.t('error.scenario instance not found', {\n instance: instanceName\n })\n )\n }\n\n var scenario = await findScenario(scenarioInstance.scenarioName, domain)\n\n await checkHasRole(scenario, context)\n\n await ScenarioEngine.unload(domain, instanceName)\n\n return scenarioInstance\n}\n"]}
@@ -26,7 +26,11 @@ export declare class ScenarioEngine {
26
26
  alreadyRunning: string[];
27
27
  }>;
28
28
  /** Create and run one instance. Throws what the run throws. */
29
- private static runInstance;
29
+ /**
30
+ * Run one instance and wait - a failure is thrown, not swallowed as `run` does. A caller who asked for the run
31
+ * (`runScenario`) says why it failed.
32
+ */
33
+ static runInstance(instanceName: any, scenarioConfig: any, context?: any): Promise<ScenarioInstanceRunResult>;
30
34
  /**
31
35
  * Loads and executes a scenario across multiple domains based on iteration
32
36
  * @param instanceName - The name for the scenario instance
@@ -109,6 +109,10 @@ class ScenarioEngine {
109
109
  return { domains: targetDomains.length, failed, alreadyRunning };
110
110
  }
111
111
  /** Create and run one instance. Throws what the run throws. */
112
+ /**
113
+ * Run one instance and wait - a failure is thrown, not swallowed as `run` does. A caller who asked for the run
114
+ * (`runScenario`) says why it failed.
115
+ */
112
116
  static async runInstance(instanceName, scenarioConfig, context) {
113
117
  const { domain: scenarioDomain } = scenarioConfig;
114
118
  const domain = context?.domain || scenarioDomain;
@@ -1 +1 @@
1
- {"version":3,"file":"scenario-engine.js","sourceRoot":"","sources":["../../server/engine/scenario-engine.ts"],"names":[],"mappings":"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","sourcesContent":["import { getRepository, Domain, GraphqlLocalClient, pubsub } from '@things-factory/shell'\n\nimport { Scenario } from '../service/scenario/scenario'\nimport {\n ScenarioInstance,\n ScenarioInstanceRunResult,\n ScenarioInstanceStartResult,\n ScenarioInstanceStatus\n} from '../service/scenario-instance/scenario-instance-type'\n\nimport { PendingQueue } from './pending-queue'\nimport { IntegrationRuntime } from './integration-runtime'\nimport { User } from '@things-factory/auth-base'\nimport { resolveRunnableSteps } from '../service/scenario/resolve-steps'\n\nconst debug = require('debug')('things-factory:integration-base:scenario-engine')\n\nexport class ScenarioEngine {\n private static scenarioInstances = {} // TODO impl. by WeakMap\n private static pendingQueues = {}\n\n public static getPendingQueue(domain) {\n if (!ScenarioEngine.pendingQueues[domain.id]) {\n ScenarioEngine.pendingQueues[domain.id] = new PendingQueue(queue => {\n pubsub.publish('scenario-queue-state', {\n scenarioQueueState: {\n domain,\n queue\n }\n })\n })\n }\n\n return ScenarioEngine.pendingQueues[domain.id]\n }\n\n public static getScenarioInstance(domain, instanceName): ScenarioInstance {\n return ScenarioEngine.scenarioInstances[domain.id]?.[instanceName]\n }\n\n public static getScenarioInstances(domain, scenarioName?): ScenarioInstance[] {\n const instances: ScenarioInstance[] = Object.values(ScenarioEngine.scenarioInstances[domain.id] || {}) || []\n return instances.filter(instance => !scenarioName || instance.scenarioName == scenarioName)\n }\n\n public static async load(instanceName, scenarioConfig, context?) {\n IntegrationRuntime.assertEnabled(`scenario \"${instanceName}\"`)\n const { domain: scenarioDomain } = scenarioConfig\n const domain = context?.domain || scenarioDomain\n\n debug('load', domain.subdomain, instanceName)\n\n var scenarioInstances = ScenarioEngine.scenarioInstances[domain.id]\n if (!scenarioInstances) {\n scenarioInstances = ScenarioEngine.scenarioInstances[domain.id] = {}\n }\n\n var scenarioInstance = scenarioInstances[instanceName]\n if (scenarioInstance) {\n debug('load - duplicated', instanceName)\n return scenarioInstance\n }\n\n var instance = new ScenarioInstance(instanceName, scenarioConfig, {\n ...context,\n user:\n context?.user ||\n (await getRepository(User).findOne({\n where: {\n id: scenarioConfig.creatorId\n }\n })),\n client: GraphqlLocalClient.client,\n disposer: () => {\n this.unload(domain, instanceName)\n }\n })\n\n instance.start().catch(err => {\n /* IMPORTANT. if you didn't catch exception here, system will be exit */\n console.error(\n `An exception occurred while executing the scenario instance named \"${instanceName}\" on the domain \"${domain.name}\"`,\n err\n )\n })\n\n scenarioInstances[instanceName] = instance\n\n return instance\n }\n\n public static async run(instanceName, scenarioConfig, context?): Promise<ScenarioInstanceRunResult> {\n try {\n return await ScenarioEngine.runInstance(instanceName, scenarioConfig, context)\n } catch (err) {\n const domain = context?.domain || scenarioConfig?.domain\n console.error(\n `An exception occurred while executing the scenario instance named \"${instanceName}\" on the domain \"${domain?.name}\"`,\n err\n )\n }\n }\n\n /** Whether an instance by this name is loaded on this domain in this process. */\n public static isRunning(domainId: string, instanceName: string): boolean {\n return !!ScenarioEngine.scenarioInstances[domainId]?.[instanceName]\n }\n\n /**\n * Run a scenario across its iteration's domains **and wait**, saying what happened (ADR-0110 adoption 2, step 5).\n *\n * `loadIteration` returns at once and `run` swallows a failure, so a scheduled run could never tell the\n * scheduler's discipline that it failed. This one awaits every domain and returns the failures by domain.\n * A domain where an instance by that name is already loaded in this process is not run again and is named in\n * `alreadyRunning` — `run` would hand back the running instance and report nothing.\n */\n public static async runIteration(\n instanceName,\n scenarioConfig,\n context?\n ): Promise<{ domains: number; failed: { subdomain: string; error: string }[]; alreadyRunning: string[] }> {\n IntegrationRuntime.assertEnabled(`scenario \"${instanceName}\"`)\n const { domain: scenarioDomain, iteration = 'SELF' } = scenarioConfig\n const domain = context?.domain || scenarioDomain\n const targetDomains = await ScenarioEngine.getTargetDomains(domain, iteration)\n\n const failed: { subdomain: string; error: string }[] = []\n const alreadyRunning: string[] = []\n\n for (const target of targetDomains) {\n if (ScenarioEngine.isRunning(target.id, instanceName)) {\n alreadyRunning.push(target.subdomain)\n continue\n }\n try {\n await ScenarioEngine.runInstance(instanceName, { ...scenarioConfig, domain: target }, { ...context, domain: target })\n } catch (error) {\n failed.push({ subdomain: target.subdomain, error: String((error as any)?.message ?? error).slice(0, 300) })\n }\n }\n\n return { domains: targetDomains.length, failed, alreadyRunning }\n }\n\n /** Create and run one instance. Throws what the run throws. */\n private static async runInstance(instanceName, scenarioConfig, context?): Promise<ScenarioInstanceRunResult> {\n const { domain: scenarioDomain } = scenarioConfig\n const domain = context?.domain || scenarioDomain\n\n debug('run', domain.subdomain, instanceName)\n\n var scenarioInstances = ScenarioEngine.scenarioInstances[domain.id]\n if (!scenarioInstances) {\n scenarioInstances = ScenarioEngine.scenarioInstances[domain.id] = {}\n }\n\n var scenarioInstance = scenarioInstances[instanceName]\n if (scenarioInstance) {\n debug('load - duplicated', instanceName)\n return scenarioInstance\n }\n\n var instance = new ScenarioInstance(instanceName, scenarioConfig, {\n ...context,\n user:\n context?.user ||\n (await getRepository(User).findOne({\n where: {\n id: scenarioConfig.creatorId\n }\n })),\n client: GraphqlLocalClient.client,\n disposer: () => {\n this.unload(domain, instanceName)\n }\n })\n\n scenarioInstances[instanceName] = instance\n\n return await instance.run()\n }\n\n /**\n * Loads and executes a scenario across multiple domains based on iteration\n * @param instanceName - The name for the scenario instance\n * @param scenarioConfig - The scenario configuration\n * @param context - The execution context\n * @returns Promise that resolves immediately, but scenarios execute sequentially\n */\n public static async loadIteration(instanceName, scenarioConfig, context?): Promise<ScenarioInstanceStartResult> {\n IntegrationRuntime.assertEnabled(`scenario \"${instanceName}\"`)\n const { domain: scenarioDomain, iteration = 'SELF' } = scenarioConfig\n const domain = context?.domain || scenarioDomain\n\n debug('load-iteration', domain.subdomain, instanceName, iteration)\n\n // Get target domains based on iteration\n const targetDomains = await ScenarioEngine.getTargetDomains(domain, iteration)\n\n // Start sequential execution in background\n ScenarioEngine.executeSequentially(instanceName, scenarioConfig, context, targetDomains)\n\n // Return immediately with execution info\n return {\n state: ScenarioInstanceStatus.STARTED,\n message: `Scenario iteration started for ${targetDomains.length} domains`,\n timestamp: new Date()\n }\n }\n\n /**\n * Executes scenarios sequentially across domains\n * @param instanceName - The name for the scenario instance\n * @param scenarioConfig - The scenario configuration\n * @param context - The execution context\n * @param targetDomains - Array of target domains\n */\n private static async executeSequentially(instanceName, scenarioConfig, context, targetDomains) {\n const results = []\n\n for (let i = 0; i < targetDomains.length; i++) {\n const targetDomain = targetDomains[i]\n\n try {\n console.log(`Executing scenario on domain ${targetDomain.subdomain} (${i + 1}/${targetDomains.length})`)\n\n const result = await ScenarioEngine.run(\n instanceName,\n {\n ...scenarioConfig,\n domain: targetDomain\n },\n {\n ...context,\n domain: targetDomain\n }\n )\n\n results.push(result)\n\n console.log(`Completed scenario on domain ${targetDomain.subdomain}`)\n } catch (error) {\n console.error(`Failed to execute scenario on domain ${targetDomain.subdomain}:`, error)\n }\n }\n\n return results[0]\n }\n\n /**\n * Gets target domains based on iteration\n * @param domain - The source domain\n * @param iteration - The iteration (SELF, CHILDREN, SELF & CHILDREN)\n * @returns Array of target domains\n */\n private static async getTargetDomains(domain: any, iteration: string): Promise<any[]> {\n switch (iteration) {\n case 'SELF':\n return [domain]\n\n case 'CHILDREN':\n const childDomains = await getRepository(Domain).find({\n where: { parent: { id: domain.id } }\n })\n return childDomains\n\n case 'SELF & CHILDREN':\n const allDomains = await getRepository(Domain).find({\n where: [{ id: domain.id }, { parent: { id: domain.id } }]\n })\n return allDomains\n\n default:\n return [domain]\n }\n }\n\n public static async unload(domain, instanceName) {\n var scenarioInstances = ScenarioEngine.scenarioInstances[domain.id]\n if (!scenarioInstances) {\n return\n }\n\n var instance = scenarioInstances[instanceName]\n if (!instance) {\n return\n }\n\n delete scenarioInstances[instanceName]\n\n instance.unload()\n }\n\n // will be deprecated soon\n public static async loadAll() {\n const SCENARIOS = await getRepository(Scenario).find({\n where: { active: true },\n relations: ['domain']\n })\n\n debug(\n 'load-all',\n SCENARIOS.map(scenario => `${scenario.domain.subdomain}: ${scenario.name}`)\n )\n\n // [버전관리] 부팅 시 자동 실행은 운영 실행이므로 released 스냅샷을 사용(없으면 draft 폴백).\n for (const scenario of SCENARIOS) {\n scenario.steps = await resolveRunnableSteps(scenario, { mode: 'released' })\n ScenarioEngine.loadIteration(scenario.name, scenario)\n }\n }\n}\n"]}
1
+ {"version":3,"file":"scenario-engine.js","sourceRoot":"","sources":["../../server/engine/scenario-engine.ts"],"names":[],"mappings":"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","sourcesContent":["import { getRepository, Domain, GraphqlLocalClient, pubsub } from '@things-factory/shell'\n\nimport { Scenario } from '../service/scenario/scenario'\nimport {\n ScenarioInstance,\n ScenarioInstanceRunResult,\n ScenarioInstanceStartResult,\n ScenarioInstanceStatus\n} from '../service/scenario-instance/scenario-instance-type'\n\nimport { PendingQueue } from './pending-queue'\nimport { IntegrationRuntime } from './integration-runtime'\nimport { User } from '@things-factory/auth-base'\nimport { resolveRunnableSteps } from '../service/scenario/resolve-steps'\n\nconst debug = require('debug')('things-factory:integration-base:scenario-engine')\n\nexport class ScenarioEngine {\n private static scenarioInstances = {} // TODO impl. by WeakMap\n private static pendingQueues = {}\n\n public static getPendingQueue(domain) {\n if (!ScenarioEngine.pendingQueues[domain.id]) {\n ScenarioEngine.pendingQueues[domain.id] = new PendingQueue(queue => {\n pubsub.publish('scenario-queue-state', {\n scenarioQueueState: {\n domain,\n queue\n }\n })\n })\n }\n\n return ScenarioEngine.pendingQueues[domain.id]\n }\n\n public static getScenarioInstance(domain, instanceName): ScenarioInstance {\n return ScenarioEngine.scenarioInstances[domain.id]?.[instanceName]\n }\n\n public static getScenarioInstances(domain, scenarioName?): ScenarioInstance[] {\n const instances: ScenarioInstance[] = Object.values(ScenarioEngine.scenarioInstances[domain.id] || {}) || []\n return instances.filter(instance => !scenarioName || instance.scenarioName == scenarioName)\n }\n\n public static async load(instanceName, scenarioConfig, context?) {\n IntegrationRuntime.assertEnabled(`scenario \"${instanceName}\"`)\n const { domain: scenarioDomain } = scenarioConfig\n const domain = context?.domain || scenarioDomain\n\n debug('load', domain.subdomain, instanceName)\n\n var scenarioInstances = ScenarioEngine.scenarioInstances[domain.id]\n if (!scenarioInstances) {\n scenarioInstances = ScenarioEngine.scenarioInstances[domain.id] = {}\n }\n\n var scenarioInstance = scenarioInstances[instanceName]\n if (scenarioInstance) {\n debug('load - duplicated', instanceName)\n return scenarioInstance\n }\n\n var instance = new ScenarioInstance(instanceName, scenarioConfig, {\n ...context,\n user:\n context?.user ||\n (await getRepository(User).findOne({\n where: {\n id: scenarioConfig.creatorId\n }\n })),\n client: GraphqlLocalClient.client,\n disposer: () => {\n this.unload(domain, instanceName)\n }\n })\n\n instance.start().catch(err => {\n /* IMPORTANT. if you didn't catch exception here, system will be exit */\n console.error(\n `An exception occurred while executing the scenario instance named \"${instanceName}\" on the domain \"${domain.name}\"`,\n err\n )\n })\n\n scenarioInstances[instanceName] = instance\n\n return instance\n }\n\n public static async run(instanceName, scenarioConfig, context?): Promise<ScenarioInstanceRunResult> {\n try {\n return await ScenarioEngine.runInstance(instanceName, scenarioConfig, context)\n } catch (err) {\n const domain = context?.domain || scenarioConfig?.domain\n console.error(\n `An exception occurred while executing the scenario instance named \"${instanceName}\" on the domain \"${domain?.name}\"`,\n err\n )\n }\n }\n\n /** Whether an instance by this name is loaded on this domain in this process. */\n public static isRunning(domainId: string, instanceName: string): boolean {\n return !!ScenarioEngine.scenarioInstances[domainId]?.[instanceName]\n }\n\n /**\n * Run a scenario across its iteration's domains **and wait**, saying what happened (ADR-0110 adoption 2, step 5).\n *\n * `loadIteration` returns at once and `run` swallows a failure, so a scheduled run could never tell the\n * scheduler's discipline that it failed. This one awaits every domain and returns the failures by domain.\n * A domain where an instance by that name is already loaded in this process is not run again and is named in\n * `alreadyRunning` — `run` would hand back the running instance and report nothing.\n */\n public static async runIteration(\n instanceName,\n scenarioConfig,\n context?\n ): Promise<{ domains: number; failed: { subdomain: string; error: string }[]; alreadyRunning: string[] }> {\n IntegrationRuntime.assertEnabled(`scenario \"${instanceName}\"`)\n const { domain: scenarioDomain, iteration = 'SELF' } = scenarioConfig\n const domain = context?.domain || scenarioDomain\n const targetDomains = await ScenarioEngine.getTargetDomains(domain, iteration)\n\n const failed: { subdomain: string; error: string }[] = []\n const alreadyRunning: string[] = []\n\n for (const target of targetDomains) {\n if (ScenarioEngine.isRunning(target.id, instanceName)) {\n alreadyRunning.push(target.subdomain)\n continue\n }\n try {\n await ScenarioEngine.runInstance(instanceName, { ...scenarioConfig, domain: target }, { ...context, domain: target })\n } catch (error) {\n failed.push({ subdomain: target.subdomain, error: String((error as any)?.message ?? error).slice(0, 300) })\n }\n }\n\n return { domains: targetDomains.length, failed, alreadyRunning }\n }\n\n /** Create and run one instance. Throws what the run throws. */\n /**\n * Run one instance and wait - a failure is thrown, not swallowed as `run` does. A caller who asked for the run\n * (`runScenario`) says why it failed.\n */\n public static async runInstance(instanceName, scenarioConfig, context?): Promise<ScenarioInstanceRunResult> {\n const { domain: scenarioDomain } = scenarioConfig\n const domain = context?.domain || scenarioDomain\n\n debug('run', domain.subdomain, instanceName)\n\n var scenarioInstances = ScenarioEngine.scenarioInstances[domain.id]\n if (!scenarioInstances) {\n scenarioInstances = ScenarioEngine.scenarioInstances[domain.id] = {}\n }\n\n var scenarioInstance = scenarioInstances[instanceName]\n if (scenarioInstance) {\n debug('load - duplicated', instanceName)\n return scenarioInstance\n }\n\n var instance = new ScenarioInstance(instanceName, scenarioConfig, {\n ...context,\n user:\n context?.user ||\n (await getRepository(User).findOne({\n where: {\n id: scenarioConfig.creatorId\n }\n })),\n client: GraphqlLocalClient.client,\n disposer: () => {\n this.unload(domain, instanceName)\n }\n })\n\n scenarioInstances[instanceName] = instance\n\n return await instance.run()\n }\n\n /**\n * Loads and executes a scenario across multiple domains based on iteration\n * @param instanceName - The name for the scenario instance\n * @param scenarioConfig - The scenario configuration\n * @param context - The execution context\n * @returns Promise that resolves immediately, but scenarios execute sequentially\n */\n public static async loadIteration(instanceName, scenarioConfig, context?): Promise<ScenarioInstanceStartResult> {\n IntegrationRuntime.assertEnabled(`scenario \"${instanceName}\"`)\n const { domain: scenarioDomain, iteration = 'SELF' } = scenarioConfig\n const domain = context?.domain || scenarioDomain\n\n debug('load-iteration', domain.subdomain, instanceName, iteration)\n\n // Get target domains based on iteration\n const targetDomains = await ScenarioEngine.getTargetDomains(domain, iteration)\n\n // Start sequential execution in background\n ScenarioEngine.executeSequentially(instanceName, scenarioConfig, context, targetDomains)\n\n // Return immediately with execution info\n return {\n state: ScenarioInstanceStatus.STARTED,\n message: `Scenario iteration started for ${targetDomains.length} domains`,\n timestamp: new Date()\n }\n }\n\n /**\n * Executes scenarios sequentially across domains\n * @param instanceName - The name for the scenario instance\n * @param scenarioConfig - The scenario configuration\n * @param context - The execution context\n * @param targetDomains - Array of target domains\n */\n private static async executeSequentially(instanceName, scenarioConfig, context, targetDomains) {\n const results = []\n\n for (let i = 0; i < targetDomains.length; i++) {\n const targetDomain = targetDomains[i]\n\n try {\n console.log(`Executing scenario on domain ${targetDomain.subdomain} (${i + 1}/${targetDomains.length})`)\n\n const result = await ScenarioEngine.run(\n instanceName,\n {\n ...scenarioConfig,\n domain: targetDomain\n },\n {\n ...context,\n domain: targetDomain\n }\n )\n\n results.push(result)\n\n console.log(`Completed scenario on domain ${targetDomain.subdomain}`)\n } catch (error) {\n console.error(`Failed to execute scenario on domain ${targetDomain.subdomain}:`, error)\n }\n }\n\n return results[0]\n }\n\n /**\n * Gets target domains based on iteration\n * @param domain - The source domain\n * @param iteration - The iteration (SELF, CHILDREN, SELF & CHILDREN)\n * @returns Array of target domains\n */\n private static async getTargetDomains(domain: any, iteration: string): Promise<any[]> {\n switch (iteration) {\n case 'SELF':\n return [domain]\n\n case 'CHILDREN':\n const childDomains = await getRepository(Domain).find({\n where: { parent: { id: domain.id } }\n })\n return childDomains\n\n case 'SELF & CHILDREN':\n const allDomains = await getRepository(Domain).find({\n where: [{ id: domain.id }, { parent: { id: domain.id } }]\n })\n return allDomains\n\n default:\n return [domain]\n }\n }\n\n public static async unload(domain, instanceName) {\n var scenarioInstances = ScenarioEngine.scenarioInstances[domain.id]\n if (!scenarioInstances) {\n return\n }\n\n var instance = scenarioInstances[instanceName]\n if (!instance) {\n return\n }\n\n delete scenarioInstances[instanceName]\n\n instance.unload()\n }\n\n // will be deprecated soon\n public static async loadAll() {\n const SCENARIOS = await getRepository(Scenario).find({\n where: { active: true },\n relations: ['domain']\n })\n\n debug(\n 'load-all',\n SCENARIOS.map(scenario => `${scenario.domain.subdomain}: ${scenario.name}`)\n )\n\n // [버전관리] 부팅 시 자동 실행은 운영 실행이므로 released 스냅샷을 사용(없으면 draft 폴백).\n for (const scenario of SCENARIOS) {\n scenario.steps = await resolveRunnableSteps(scenario, { mode: 'released' })\n ScenarioEngine.loadIteration(scenario.name, scenario)\n }\n }\n}\n"]}
@@ -43,10 +43,15 @@ async function LocalGraphqlMutate(step, context) {
43
43
  }
44
44
  }
45
45
  });
46
- if (errors) {
46
+ /*
47
+ * A refused or failed call fails the step - logged and passed on as a success, the next step ran on nothing and the
48
+ * scenario ended STOPPED with no word of why (the user, 2026-10-31).
49
+ */
50
+ if (errors?.length) {
47
51
  errors.forEach(error => {
48
52
  logger.error('GraphQL Error: %s', error);
49
53
  });
54
+ throw new Error(errors.map(error => error.message).join('; '));
50
55
  }
51
56
  return {
52
57
  data: mutateResult
@@ -1 +1 @@
1
- {"version":3,"file":"local-graphql-mutate.js","sourceRoot":"","sources":["../../../server/engine/task/local-graphql-mutate.ts"],"names":[],"mappings":";;;AAAA,sEAA6B;AAE7B,yDAAgD;AAChD,iDAAqD;AACrD,iDAA8C;AAE9C,4DAAuD;AACvD,oDAA+C;AAI/C,KAAK,UAAU,kBAAkB,CAAC,IAAe,EAAE,OAAgB;IACjE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;IAChC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,oBAAoB,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,EAAE,CAAA;IACzE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,OAAO,CAAA;IAEpE,IAAI;QACF,IAAI;YACJ,CAAC,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,OAAO,CAAC;gBACjC,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE;gBACxB,SAAS,EAAE,CAAC,SAAS,CAAC;aACvB,CAAC,CAAC,CAAA;IAEL,IAAI,YAAY,CAAA;IAChB,IAAI,CAAC;QACH,YAAY,GAAG,IAAA,oCAAgB,EAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAA;IAC5F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;IAChE,CAAC;IAED,QAAQ,GAAG,YAAY,CAAA;IAEvB,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE;QACvF,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAA;QAC1C,SAAS,CAAC,GAAG,CAAC,GAAG,IAAA,cAAM,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QACvC,OAAO,SAAS,CAAA;IAClB,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;QACvD,QAAQ,EAAE,IAAA,qBAAG,EAAA;QACT,QAAQ;KACX;QACD,SAAS,EAAE,cAAc;QACzB,OAAO;QACP,OAAO,EAAE;YACP,KAAK,EAAE;gBACL,MAAM;gBACN,IAAI;aACL;SACF;KACF,CAAC,CAAA;IAEF,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACrB,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAA;QAC1C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,YAAY;KACnB,CAAA;AACH,CAAC;AAED,kBAAkB,CAAC,aAAa,GAAG;IACjC;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE;YACR,eAAe,EAAE,IAAI;SACtB;QACD,MAAM,EAAE;YACN,IAAI,EAAE,CAAC;SACR;KACF;IACD;QACE,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,WAAW;KACnB;IACD;QACE,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;KACjB;CACF,CAAA;AAED,kBAAkB,CAAC,aAAa,GAAG,IAAI,CAAA;AACvC,kBAAkB,CAAC,IAAI,GAAG,uCAAuC,CAAA;AAEjE,4BAAY,CAAC,mBAAmB,CAAC,sBAAsB,EAAE,kBAAkB,CAAC,CAAA","sourcesContent":["import gql from 'graphql-tag'\n\nimport { User } from '@things-factory/auth-base'\nimport { getRepository } from '@things-factory/shell'\nimport { access } from '@things-factory/utils'\n\nimport { evaluateTemplate } from '../evaluate-template'\nimport { TaskRegistry } from '../task-registry'\nimport { InputStep } from '../../service/step/step-type'\nimport { Context } from '../types'\n\nasync function LocalGraphqlMutate(step: InputStep, context: Context) {\n var { params, updaterId } = step\n var { mutation, variables: variablesAccessorMap, headers } = params || {}\n var { logger, client, domain, user, data, variables, lng } = context\n\n user =\n user ||\n (await getRepository(User).findOne({\n where: { id: updaterId },\n relations: ['domains']\n }))\n\n let evalMutation\n try {\n evalMutation = evaluateTemplate(mutation, { domain, user, lng, data, variables, console })\n } catch (err) {\n throw new Error(`Failed to evaluate mutation: ${err.message}`)\n }\n\n mutation = evalMutation\n\n const queryVariables = Object.keys(variablesAccessorMap || {}).reduce((variables, key) => {\n const accessor = variablesAccessorMap[key]\n variables[key] = access(accessor, data)\n return variables\n }, {})\n\n var { data: mutateResult, errors } = await client.mutate({\n mutation: gql`\n ${mutation}\n `,\n variables: queryVariables,\n headers,\n context: {\n state: {\n domain,\n user\n }\n }\n })\n\n if (errors) {\n errors.forEach(error => {\n logger.error('GraphQL Error: %s', error)\n })\n }\n\n return {\n data: mutateResult\n }\n}\n\nLocalGraphqlMutate.parameterSpec = [\n {\n type: 'graphql',\n name: 'mutation',\n label: 'mutation',\n property: {\n showLineNumbers: true\n },\n styles: {\n flex: 1\n }\n },\n {\n type: 'key-values',\n name: 'variables',\n label: 'variables'\n },\n {\n type: 'key-values',\n name: 'headers',\n label: 'headers'\n }\n]\n\nLocalGraphqlMutate.connectorFree = true\nLocalGraphqlMutate.help = 'integration/task/local-graphql-mutate'\n\nTaskRegistry.registerTaskHandler('local-graphql-mutate', LocalGraphqlMutate)\n"]}
1
+ {"version":3,"file":"local-graphql-mutate.js","sourceRoot":"","sources":["../../../server/engine/task/local-graphql-mutate.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\n\nimport { User } from '@things-factory/auth-base'\nimport { getRepository } from '@things-factory/shell'\nimport { access } from '@things-factory/utils'\n\nimport { evaluateTemplate } from '../evaluate-template'\nimport { TaskRegistry } from '../task-registry'\nimport { InputStep } from '../../service/step/step-type'\nimport { Context } from '../types'\n\nasync function LocalGraphqlMutate(step: InputStep, context: Context) {\n var { params, updaterId } = step\n var { mutation, variables: variablesAccessorMap, headers } = params || {}\n var { logger, client, domain, user, data, variables, lng } = context\n\n user =\n user ||\n (await getRepository(User).findOne({\n where: { id: updaterId },\n relations: ['domains']\n }))\n\n let evalMutation\n try {\n evalMutation = evaluateTemplate(mutation, { domain, user, lng, data, variables, console })\n } catch (err) {\n throw new Error(`Failed to evaluate mutation: ${err.message}`)\n }\n\n mutation = evalMutation\n\n const queryVariables = Object.keys(variablesAccessorMap || {}).reduce((variables, key) => {\n const accessor = variablesAccessorMap[key]\n variables[key] = access(accessor, data)\n return variables\n }, {})\n\n var { data: mutateResult, errors } = await client.mutate({\n mutation: gql`\n ${mutation}\n `,\n variables: queryVariables,\n headers,\n context: {\n state: {\n domain,\n user\n }\n }\n })\n\n /*\n * A refused or failed call fails the step - logged and passed on as a success, the next step ran on nothing and the\n * scenario ended STOPPED with no word of why (the user, 2026-10-31).\n */\n if (errors?.length) {\n errors.forEach(error => {\n logger.error('GraphQL Error: %s', error)\n })\n throw new Error(errors.map(error => error.message).join('; '))\n }\n\n return {\n data: mutateResult\n }\n}\n\nLocalGraphqlMutate.parameterSpec = [\n {\n type: 'graphql',\n name: 'mutation',\n label: 'mutation',\n property: {\n showLineNumbers: true\n },\n styles: {\n flex: 1\n }\n },\n {\n type: 'key-values',\n name: 'variables',\n label: 'variables'\n },\n {\n type: 'key-values',\n name: 'headers',\n label: 'headers'\n }\n]\n\nLocalGraphqlMutate.connectorFree = true\nLocalGraphqlMutate.help = 'integration/task/local-graphql-mutate'\n\nTaskRegistry.registerTaskHandler('local-graphql-mutate', LocalGraphqlMutate)\n"]}
@@ -43,10 +43,15 @@ async function LocalGraphqlQuery(step, context) {
43
43
  }
44
44
  }
45
45
  });
46
- if (errors) {
46
+ /*
47
+ * A refused or failed call fails the step - logged and passed on as a success, the next step ran on nothing and the
48
+ * scenario ended STOPPED with no word of why (the user, 2026-10-31).
49
+ */
50
+ if (errors?.length) {
47
51
  errors.forEach(error => {
48
52
  logger.error('GraphQL Error: %s', error);
49
53
  });
54
+ throw new Error(errors.map(error => error.message).join('; '));
50
55
  }
51
56
  return {
52
57
  data: queryResult
@@ -1 +1 @@
1
- {"version":3,"file":"local-graphql-query.js","sourceRoot":"","sources":["../../../server/engine/task/local-graphql-query.ts"],"names":[],"mappings":";;;AAAA,sEAA6B;AAE7B,yDAAgD;AAChD,iDAAqD;AACrD,iDAA8C;AAE9C,4DAAuD;AACvD,oDAA+C;AAI/C,KAAK,UAAU,iBAAiB,CAAC,IAAe,EAAE,OAAgB;IAChE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;IAChC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,EAAE,CAAA;IACtE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,OAAO,CAAA;IAEpE,IAAI;QACF,IAAI;YACJ,CAAC,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,OAAO,CAAC;gBACjC,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE;gBACxB,SAAS,EAAE,CAAC,SAAS,CAAC;aACvB,CAAC,CAAC,CAAA;IAEL,IAAI,SAAS,CAAA;IACb,IAAI,CAAC;QACH,SAAS,GAAG,IAAA,oCAAgB,EAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAA;IACtF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;IAC7D,CAAC;IAED,KAAK,GAAG,SAAS,CAAA;IAEjB,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE;QACvF,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAA;QAC1C,SAAS,CAAC,GAAG,CAAC,GAAG,IAAA,cAAM,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QACvC,OAAO,SAAS,CAAA;IAClB,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;QACrD,KAAK,EAAE,IAAA,qBAAG,EAAA;QACN,KAAK;KACR;QACD,SAAS,EAAE,cAAc;QACzB,OAAO;QACP,OAAO,EAAE;YACP,KAAK,EAAE;gBACL,MAAM;gBACN,IAAI;aACL;SACF;KACF,CAAC,CAAA;IAEF,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACrB,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAA;QAC1C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,WAAW;KAClB,CAAA;AACH,CAAC;AAED,iBAAiB,CAAC,aAAa,GAAG;IAChC;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE;YACR,eAAe,EAAE,IAAI;SACtB;QACD,MAAM,EAAE;YACN,IAAI,EAAE,CAAC;SACR;KACF;IACD;QACE,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,WAAW;KACnB;IACD;QACE,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;KACjB;CACF,CAAA;AAED,iBAAiB,CAAC,aAAa,GAAG,IAAI,CAAA;AACtC,iBAAiB,CAAC,IAAI,GAAG,sCAAsC,CAAA;AAE/D,4BAAY,CAAC,mBAAmB,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,CAAA","sourcesContent":["import gql from 'graphql-tag'\n\nimport { User } from '@things-factory/auth-base'\nimport { getRepository } from '@things-factory/shell'\nimport { access } from '@things-factory/utils'\n\nimport { evaluateTemplate } from '../evaluate-template'\nimport { TaskRegistry } from '../task-registry'\nimport { InputStep } from '../../service/step/step-type'\nimport { Context } from '../types'\n\nasync function LocalGraphqlQuery(step: InputStep, context: Context) {\n var { params, updaterId } = step\n var { query, variables: variablesAccessorMap, headers } = params || {}\n var { logger, client, domain, user, data, variables, lng } = context\n\n user =\n user ||\n (await getRepository(User).findOne({\n where: { id: updaterId },\n relations: ['domains']\n }))\n\n let evalQuery\n try {\n evalQuery = evaluateTemplate(query, { domain, user, lng, data, variables, console })\n } catch (err) {\n throw new Error(`Failed to evaluate query: ${err.message}`)\n }\n\n query = evalQuery\n\n const queryVariables = Object.keys(variablesAccessorMap || {}).reduce((variables, key) => {\n const accessor = variablesAccessorMap[key]\n variables[key] = access(accessor, data)\n return variables\n }, {})\n\n var { data: queryResult, errors } = await client.query({\n query: gql`\n ${query}\n `,\n variables: queryVariables,\n headers,\n context: {\n state: {\n domain,\n user\n }\n }\n })\n\n if (errors) {\n errors.forEach(error => {\n logger.error('GraphQL Error: %s', error)\n })\n }\n\n return {\n data: queryResult\n }\n}\n\nLocalGraphqlQuery.parameterSpec = [\n {\n type: 'graphql',\n name: 'query',\n label: 'query',\n property: {\n showLineNumbers: true\n },\n styles: {\n flex: 1\n }\n },\n {\n type: 'key-values',\n name: 'variables',\n label: 'variables'\n },\n {\n type: 'key-values',\n name: 'headers',\n label: 'headers'\n }\n]\n\nLocalGraphqlQuery.connectorFree = true\nLocalGraphqlQuery.help = 'integration/task/local-graphql-query'\n\nTaskRegistry.registerTaskHandler('local-graphql-query', LocalGraphqlQuery)\n"]}
1
+ {"version":3,"file":"local-graphql-query.js","sourceRoot":"","sources":["../../../server/engine/task/local-graphql-query.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\n\nimport { User } from '@things-factory/auth-base'\nimport { getRepository } from '@things-factory/shell'\nimport { access } from '@things-factory/utils'\n\nimport { evaluateTemplate } from '../evaluate-template'\nimport { TaskRegistry } from '../task-registry'\nimport { InputStep } from '../../service/step/step-type'\nimport { Context } from '../types'\n\nasync function LocalGraphqlQuery(step: InputStep, context: Context) {\n var { params, updaterId } = step\n var { query, variables: variablesAccessorMap, headers } = params || {}\n var { logger, client, domain, user, data, variables, lng } = context\n\n user =\n user ||\n (await getRepository(User).findOne({\n where: { id: updaterId },\n relations: ['domains']\n }))\n\n let evalQuery\n try {\n evalQuery = evaluateTemplate(query, { domain, user, lng, data, variables, console })\n } catch (err) {\n throw new Error(`Failed to evaluate query: ${err.message}`)\n }\n\n query = evalQuery\n\n const queryVariables = Object.keys(variablesAccessorMap || {}).reduce((variables, key) => {\n const accessor = variablesAccessorMap[key]\n variables[key] = access(accessor, data)\n return variables\n }, {})\n\n var { data: queryResult, errors } = await client.query({\n query: gql`\n ${query}\n `,\n variables: queryVariables,\n headers,\n context: {\n state: {\n domain,\n user\n }\n }\n })\n\n /*\n * A refused or failed call fails the step - logged and passed on as a success, the next step ran on nothing and the\n * scenario ended STOPPED with no word of why (the user, 2026-10-31).\n */\n if (errors?.length) {\n errors.forEach(error => {\n logger.error('GraphQL Error: %s', error)\n })\n throw new Error(errors.map(error => error.message).join('; '))\n }\n\n return {\n data: queryResult\n }\n}\n\nLocalGraphqlQuery.parameterSpec = [\n {\n type: 'graphql',\n name: 'query',\n label: 'query',\n property: {\n showLineNumbers: true\n },\n styles: {\n flex: 1\n }\n },\n {\n type: 'key-values',\n name: 'variables',\n label: 'variables'\n },\n {\n type: 'key-values',\n name: 'headers',\n label: 'headers'\n }\n]\n\nLocalGraphqlQuery.connectorFree = true\nLocalGraphqlQuery.help = 'integration/task/local-graphql-query'\n\nTaskRegistry.registerTaskHandler('local-graphql-query', LocalGraphqlQuery)\n"]}
@@ -10,6 +10,10 @@ require("./restful/index.js"); /* APIs */
10
10
  const index_js_1 = require("./engine/index.js");
11
11
  const integration_runtime_js_1 = require("./engine/integration-runtime.js");
12
12
  tslib_1.__exportStar(require("./engine/integration-runtime.js"), exports);
13
+ const auth_base_1 = require("@things-factory/auth-base");
14
+ const role_tasks_js_1 = require("./role-tasks.js");
15
+ for (const task of role_tasks_js_1.ROLE_TASKS)
16
+ (0, auth_base_1.registerRoleTask)(task);
13
17
  process.on('bootstrap-module-start', async ({ app, config, client }) => {
14
18
  integration_runtime_js_1.IntegrationRuntime.markBooted();
15
19
  if (!integration_runtime_js_1.IntegrationRuntime.enabled) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,gEAAqC;AACrC,4DAAiC;AACjC,iEAAsC;AACtC,6DAAkC;AAElC,uBAAoB;AACpB,8BAA2B,CAAC,UAAU;AAEtC,gDAAqE;AACrE,4EAAoE;AAEpE,0EAA+C;AAE/C,OAAO,CAAC,EAAE,CAAC,wBAA+B,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAO,EAAE,EAAE;IACjF,2CAAkB,CAAC,UAAU,EAAE,CAAA;IAC/B,IAAI,CAAC,2CAAkB,CAAC,OAAO,EAAE,CAAC;QAChC,4FAA4F;QAC5F,OAAO,CAAC,GAAG,CAAC,4CAA4C,2CAAkB,CAAC,MAAM,EAAE,CAAC,CAAA;QACpF,OAAM;IACR,CAAC;IACD,IAAI,CAAC;QACH,MAAM,4BAAiB,CAAC,KAAK,EAAE,CAAA;QAC/B,MAAM,yBAAc,CAAC,OAAO,EAAE,CAAA;QAE9B,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAA;IAClD,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;QACZ,4BAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,EAAE,EAAE,CAAC,CAAA;IACjF,CAAC;AACH,CAAC,CAAC,CAAA","sourcesContent":["export * from './migrations/index.js'\nexport * from './engine/index.js'\nexport * from './controllers/index.js'\nexport * from './service/index.js'\n\nimport './routes.js'\nimport './restful/index.js' /* APIs */\n\nimport { ConnectionManager, ScenarioEngine } from './engine/index.js'\nimport { IntegrationRuntime } from './engine/integration-runtime.js'\n\nexport * from './engine/integration-runtime.js'\n\nprocess.on('bootstrap-module-start' as any, async ({ app, config, client }: any) => {\n IntegrationRuntime.markBooted()\n if (!IntegrationRuntime.enabled) {\n /* Integration runs in another process; this one connects nothing and starts no scenario. */\n console.log(`Scenario Engine is off in this process — ${IntegrationRuntime.reason}`)\n return\n }\n try {\n await ConnectionManager.ready()\n await ScenarioEngine.loadAll()\n\n console.log('Scenario Engine has just started.')\n } catch (ex) {\n ConnectionManager.logger.error('Just has failed to start Scenario Engine.', ex)\n }\n})\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,gEAAqC;AACrC,4DAAiC;AACjC,iEAAsC;AACtC,6DAAkC;AAElC,uBAAoB;AACpB,8BAA2B,CAAC,UAAU;AAEtC,gDAAqE;AACrE,4EAAoE;AAEpE,0EAA+C;AAE/C,yDAA4D;AAC5D,mDAA4C;AAE5C,KAAK,MAAM,IAAI,IAAI,0BAAU;IAAE,IAAA,4BAAgB,EAAC,IAAI,CAAC,CAAA;AAErD,OAAO,CAAC,EAAE,CAAC,wBAA+B,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAO,EAAE,EAAE;IACjF,2CAAkB,CAAC,UAAU,EAAE,CAAA;IAC/B,IAAI,CAAC,2CAAkB,CAAC,OAAO,EAAE,CAAC;QAChC,4FAA4F;QAC5F,OAAO,CAAC,GAAG,CAAC,4CAA4C,2CAAkB,CAAC,MAAM,EAAE,CAAC,CAAA;QACpF,OAAM;IACR,CAAC;IACD,IAAI,CAAC;QACH,MAAM,4BAAiB,CAAC,KAAK,EAAE,CAAA;QAC/B,MAAM,yBAAc,CAAC,OAAO,EAAE,CAAA;QAE9B,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAA;IAClD,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;QACZ,4BAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,EAAE,EAAE,CAAC,CAAA;IACjF,CAAC;AACH,CAAC,CAAC,CAAA","sourcesContent":["export * from './migrations/index.js'\nexport * from './engine/index.js'\nexport * from './controllers/index.js'\nexport * from './service/index.js'\n\nimport './routes.js'\nimport './restful/index.js' /* APIs */\n\nimport { ConnectionManager, ScenarioEngine } from './engine/index.js'\nimport { IntegrationRuntime } from './engine/integration-runtime.js'\n\nexport * from './engine/integration-runtime.js'\n\nimport { registerRoleTask } from '@things-factory/auth-base'\nimport { ROLE_TASKS } from './role-tasks.js'\n\nfor (const task of ROLE_TASKS) registerRoleTask(task)\n\nprocess.on('bootstrap-module-start' as any, async ({ app, config, client }: any) => {\n IntegrationRuntime.markBooted()\n if (!IntegrationRuntime.enabled) {\n /* Integration runs in another process; this one connects nothing and starts no scenario. */\n console.log(`Scenario Engine is off in this process — ${IntegrationRuntime.reason}`)\n return\n }\n try {\n await ConnectionManager.ready()\n await ScenarioEngine.loadAll()\n\n console.log('Scenario Engine has just started.')\n } catch (ex) {\n ConnectionManager.logger.error('Just has failed to start Scenario Engine.', ex)\n }\n})\n"]}
@@ -0,0 +1,2 @@
1
+ import type { RoleTask } from '@things-factory/auth-base';
2
+ export declare const ROLE_TASKS: RoleTask[];
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ /*
3
+ * The work this module names, for the seats applications build (ADR-0139 decision 11).
4
+ *
5
+ * A task holds whole privileges: each opens everything its doors open, and the words under `task.<id>` in this
6
+ * module's translations say what that is. Seats are put together by applications (`RoleTemplate.tasks`).
7
+ *
8
+ * Data only - `server/index.ts` registers it - so an application's tests read it without starting the framework.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.ROLE_TASKS = void 0;
12
+ exports.ROLE_TASKS = [
13
+ { id: 'integration-base.connections', grants: [{ category: 'connection', axes: ['query', 'mutation'] }] },
14
+ { id: 'integration-base.scenarios', grants: [{ category: 'scenario', axes: ['query', 'mutation'] }] }
15
+ ];
16
+ //# sourceMappingURL=role-tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role-tasks.js","sourceRoot":"","sources":["../server/role-tasks.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAIU,QAAA,UAAU,GAAe;IACpC,EAAE,EAAE,EAAE,8BAA8B,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE;IACzG,EAAE,EAAE,EAAE,4BAA4B,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE;CACtG,CAAA","sourcesContent":["/*\n * The work this module names, for the seats applications build (ADR-0139 decision 11).\n *\n * A task holds whole privileges: each opens everything its doors open, and the words under `task.<id>` in this\n * module's translations say what that is. Seats are put together by applications (`RoleTemplate.tasks`).\n *\n * Data only - `server/index.ts` registers it - so an application's tests read it without starting the framework.\n */\n\nimport type { RoleTask } from '@things-factory/auth-base'\n\nexport const ROLE_TASKS: RoleTask[] = [\n { id: 'integration-base.connections', grants: [{ category: 'connection', axes: ['query', 'mutation'] }] },\n { id: 'integration-base.scenarios', grants: [{ category: 'scenario', axes: ['query', 'mutation'] }] }\n]\n"]}
@@ -37,9 +37,24 @@ function paramsToStore(written, stored) {
37
37
  function notInThisDomain(connection) {
38
38
  return new shell_1.Refusal('connection-not-in-domain', { connection }, `There is no connection "${connection}" in this domain.`);
39
39
  }
40
+ /**
41
+ * A connection is nothing without its name and its type - the type says which connector it is. A row saved without
42
+ * either is refused naming the field, before the database refuses it in its own words. A patch that leaves a field
43
+ * out keeps the stored value; one that empties it is refused alike.
44
+ */
45
+ function refuseMissingFields(written, stored) {
46
+ const connection = written.name || stored?.name || '';
47
+ for (const field of ['name', 'type']) {
48
+ const value = field in written ? written[field] : stored ? stored[field] : undefined;
49
+ if (value === undefined || value === null || String(value).trim() === '') {
50
+ throw new shell_1.Refusal(`connection-${field}-required`, { connection }, `A connection needs a ${field}.`);
51
+ }
52
+ }
53
+ }
40
54
  let ConnectionMutation = class ConnectionMutation {
41
55
  async createConnection(connection, context) {
42
56
  const { domain, user, tx } = context.state;
57
+ refuseMissingFields(connection);
43
58
  return await tx.getRepository(connection_1.Connection).save({
44
59
  ...connection,
45
60
  ...paramsToStore(connection),
@@ -57,6 +72,7 @@ let ConnectionMutation = class ConnectionMutation {
57
72
  if (!connection) {
58
73
  throw notInThisDomain(name);
59
74
  }
75
+ refuseMissingFields(patch, connection);
60
76
  if (patch.name && patch.name !== connection.name) {
61
77
  await (0, connection_env_vars_1.carryConnectionEnvVars)(tx, domain, connection.name, patch.name);
62
78
  }
@@ -78,6 +94,7 @@ let ConnectionMutation = class ConnectionMutation {
78
94
  for (let i = 0; i < _createRecords.length; i++) {
79
95
  /* A new row: an id it carries would make `save` overwrite the row of that id, wherever it is. */
80
96
  const { id, ...newRecord } = _createRecords[i];
97
+ refuseMissingFields(newRecord);
81
98
  const result = await connectionRepo.save({
82
99
  ...newRecord,
83
100
  ...paramsToStore(newRecord),
@@ -95,6 +112,7 @@ let ConnectionMutation = class ConnectionMutation {
95
112
  if (!connection) {
96
113
  throw notInThisDomain(newRecord.name || newRecord.id);
97
114
  }
115
+ refuseMissingFields(newRecord, connection);
98
116
  if (newRecord.name && newRecord.name !== connection.name) {
99
117
  await (0, connection_env_vars_1.carryConnectionEnvVars)(tx, domain, connection.name, newRecord.name);
100
118
  }
@@ -1 +1 @@
1
- {"version":3,"file":"connection-mutation.js","sourceRoot":"","sources":["../../../server/service/connection/connection-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver, UseMiddleware } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { getRepository, Refusal, SpeakRefusals, getDomainIdsWithAncestors } from '@things-factory/shell'\n\nimport { ConnectionManager } from '../../engine/connection-manager'\nimport { Connection, ConnectionStatus } from './connection'\nimport { ConnectionPatch, NewConnection } from './connection-type'\nimport { keepStoredSecrets, refuseSecretParams, withoutSecretsOf } from './connection-secrets'\nimport { carryConnectionEnvVars } from './connection-env-vars'\n\n/**\n * The params a write stores (ADR-0112): a secret the caller sends is refused, a secret the caller\n * leaves out is kept from the stored row.\n *\n * A write that changes the connector type keeps none of the old type's secrets. They were secrets\n * under the old type's spec; the new type may not declare them, and then reading would show them.\n * When the old type is not registered here nobody can say which were secret, so none of its params\n * are carried over.\n */\nfunction paramsToStore(written: Partial<Connection>, stored?: Connection) {\n const type = written.type ?? stored?.type\n const name = written.name ?? stored?.name\n const typeChanged = Boolean(stored && written.type && written.type !== stored.type)\n\n if (written.params === undefined) {\n return typeChanged ? { params: withoutSecretsOf(stored.type, stored.params) } : {}\n }\n\n refuseSecretParams(type, name, written.params)\n return { params: typeChanged ? written.params : keepStoredSecrets(type, written.params, stored?.params) }\n}\n\n/**\n * A write names an existing row only through this: the row of that id or name **in the request's\n * domain**. `save` writes by primary key, so an id from another domain left in the object would\n * overwrite that domain's row - the lookup alone does not stop it.\n */\nfunction notInThisDomain(connection: string) {\n return new Refusal(\n 'connection-not-in-domain',\n { connection },\n `There is no connection \"${connection}\" in this domain.`\n )\n}\n\n@Resolver(Connection)\n@UseMiddleware(SpeakRefusals)\nexport class ConnectionMutation {\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Creates a new connection.' })\n async createConnection(\n @Arg('connection') connection: NewConnection,\n @Ctx() context: ResolverContext\n ): Promise<Connection> {\n const { domain, user, tx } = context.state\n\n return await tx.getRepository(Connection).save({\n ...connection,\n ...paramsToStore(connection),\n domain,\n creator: user,\n updater: user\n })\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Updates an existing connection.' })\n async updateConnection(\n @Arg('name') name: string,\n @Arg('patch') patch: ConnectionPatch,\n @Ctx() context: ResolverContext\n ): Promise<Connection> {\n const { domain, user, tx } = context.state\n\n const repository = tx.getRepository(Connection)\n const connection = await repository.findOne({\n where: { domain: { id: domain.id }, name }\n })\n\n if (!connection) {\n throw notInThisDomain(name)\n }\n\n if (patch.name && patch.name !== connection.name) {\n await carryConnectionEnvVars(tx, domain, connection.name, patch.name)\n }\n\n return await repository.save({\n ...connection,\n ...patch,\n ...paramsToStore(patch, connection),\n id: connection.id,\n updater: user\n })\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => [Connection], { description: 'Updates multiple connections at once.' })\n async updateMultipleConnection(\n @Arg('patches', type => [ConnectionPatch]) patches: ConnectionPatch[],\n @Ctx() context: ResolverContext\n ): Promise<Connection[]> {\n const { domain, user, tx } = context.state\n\n let results = []\n const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')\n const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')\n const connectionRepo = tx.getRepository(Connection)\n\n if (_createRecords.length > 0) {\n for (let i = 0; i < _createRecords.length; i++) {\n /* A new row: an id it carries would make `save` overwrite the row of that id, wherever it is. */\n const { id, ...newRecord } = _createRecords[i]\n\n const result = await connectionRepo.save({\n ...newRecord,\n ...paramsToStore(newRecord),\n domain,\n creator: user,\n updater: user\n })\n\n results.push({ ...result, cuFlag: '+' })\n }\n }\n\n if (_updateRecords.length > 0) {\n for (let i = 0; i < _updateRecords.length; i++) {\n const newRecord = _updateRecords[i]\n const connection = await connectionRepo.findOneBy({ id: newRecord.id, domain: { id: domain.id } })\n\n if (!connection) {\n throw notInThisDomain(newRecord.name || newRecord.id)\n }\n\n if (newRecord.name && newRecord.name !== connection.name) {\n await carryConnectionEnvVars(tx, domain, connection.name, newRecord.name)\n }\n\n const result = await connectionRepo.save({\n ...connection,\n ...newRecord,\n ...paramsToStore(newRecord, connection),\n id: connection.id,\n updater: user\n })\n\n results.push({ ...result, cuFlag: 'M' })\n }\n }\n\n return results\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, { description: 'Deletes a single connection by its name.' })\n async deleteConnection(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, tx } = context.state\n\n await tx.getRepository(Connection).delete({ domain: { id: domain.id }, name })\n return true\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, { description: 'Deletes multiple connections by their names.' })\n async deleteConnections(\n @Arg('names', type => [String]) names: string[],\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, tx } = context.state\n\n await tx.getRepository(Connection).delete({\n domain: { id: domain.id },\n name: In(names)\n })\n\n return true\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Establishes a live connection to a configured endpoint.' })\n async connectConnection(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<Connection> {\n const { domain } = context.state\n var repository = getRepository(Connection)\n\n // ancestor 도메인을 closest-first 로 순회하여 first hit 사용\n const domainIds = await getDomainIdsWithAncestors(domain)\n var connection: Connection | null = null\n for (const did of domainIds) {\n connection = await repository.findOne({\n where: { domain: { id: did }, name },\n relations: ['domain', 'edge']\n })\n if (connection) break\n }\n\n if (!connection) {\n throw new Error(`Connection with name '${name}' not found`)\n }\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n if (connection.domain.id !== domain.id) {\n connection.domain = domain\n await connection.connect()\n /* on-demand 연결인 경우에 connection을 저장하지 말아야 한다. */\n } else {\n await connection.connect()\n await repository.save(connection)\n }\n\n return {\n ...connection,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n } as Connection\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Terminates a live connection.' })\n async disconnectConnection(@Arg('name') name: string, @Ctx() context: ResolverContext) {\n const { domain } = context.state\n\n var repository = getRepository(Connection)\n\n // ancestor 도메인을 closest-first 로 순회하여 first hit 사용\n const domainIds = await getDomainIdsWithAncestors(domain)\n var connection: Connection | null = null\n for (const did of domainIds) {\n connection = await repository.findOne({\n where: { domain: { id: did }, name },\n relations: ['domain', 'edge']\n })\n if (connection) break\n }\n\n if (!connection) {\n throw new Error(`Connection with name '${name}' not found`)\n }\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n if (connection.domain.id !== domain.id) {\n connection.domain = domain\n await connection.disconnect()\n\n /* on-demand 연결인 경우에 connection을 저장하지 말아야 한다. */\n } else {\n await connection.disconnect()\n await repository.save(connection)\n }\n\n return {\n ...connection,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n }\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, {\n description: 'Imports multiple connections. Can overwrite existing connections if IDs or names match.'\n })\n async importConnections(\n @Arg('connections', type => [ConnectionPatch]) connections: Connection[],\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain, user } = context.state\n\n const repository = tx.getRepository(Connection)\n\n await Promise.all(\n connections.map(async (connection: Connection) => {\n const { id, name } = connection\n\n if (id) {\n const sameId = await repository.findOneBy({ id })\n\n if (sameId) {\n if (sameId.domainId != domain.id) {\n throw `Connection with id '${id}:${name}' is already taken by another domain`\n }\n\n const sameName = await repository.findOneBy({ domain: { id: domain.id }, name })\n if (sameName && sameName.id != id) {\n throw `Connection with name '${name}' is already taken by another connection`\n }\n\n await repository.save({\n ...sameId,\n ...connection,\n ...paramsToStore(connection, sameId),\n domain,\n updater: user\n })\n\n return\n }\n }\n\n await repository.save({\n ...connection,\n ...paramsToStore(connection),\n domain,\n updater: user,\n creator: user\n })\n })\n )\n\n return true\n }\n}\n"]}
1
+ {"version":3,"file":"connection-mutation.js","sourceRoot":"","sources":["../../../server/service/connection/connection-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver, UseMiddleware } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { getRepository, Refusal, SpeakRefusals, getDomainIdsWithAncestors } from '@things-factory/shell'\n\nimport { ConnectionManager } from '../../engine/connection-manager'\nimport { Connection, ConnectionStatus } from './connection'\nimport { ConnectionPatch, NewConnection } from './connection-type'\nimport { keepStoredSecrets, refuseSecretParams, withoutSecretsOf } from './connection-secrets'\nimport { carryConnectionEnvVars } from './connection-env-vars'\n\n/**\n * The params a write stores (ADR-0112): a secret the caller sends is refused, a secret the caller\n * leaves out is kept from the stored row.\n *\n * A write that changes the connector type keeps none of the old type's secrets. They were secrets\n * under the old type's spec; the new type may not declare them, and then reading would show them.\n * When the old type is not registered here nobody can say which were secret, so none of its params\n * are carried over.\n */\nfunction paramsToStore(written: Partial<Connection>, stored?: Connection) {\n const type = written.type ?? stored?.type\n const name = written.name ?? stored?.name\n const typeChanged = Boolean(stored && written.type && written.type !== stored.type)\n\n if (written.params === undefined) {\n return typeChanged ? { params: withoutSecretsOf(stored.type, stored.params) } : {}\n }\n\n refuseSecretParams(type, name, written.params)\n return { params: typeChanged ? written.params : keepStoredSecrets(type, written.params, stored?.params) }\n}\n\n/**\n * A write names an existing row only through this: the row of that id or name **in the request's\n * domain**. `save` writes by primary key, so an id from another domain left in the object would\n * overwrite that domain's row - the lookup alone does not stop it.\n */\nfunction notInThisDomain(connection: string) {\n return new Refusal(\n 'connection-not-in-domain',\n { connection },\n `There is no connection \"${connection}\" in this domain.`\n )\n}\n\n/**\n * A connection is nothing without its name and its type - the type says which connector it is. A row saved without\n * either is refused naming the field, before the database refuses it in its own words. A patch that leaves a field\n * out keeps the stored value; one that empties it is refused alike.\n */\nfunction refuseMissingFields(written: Partial<Connection>, stored?: Connection) {\n const connection = written.name || stored?.name || ''\n for (const field of ['name', 'type'] as const) {\n const value = field in written ? written[field] : stored ? stored[field] : undefined\n if (value === undefined || value === null || String(value).trim() === '') {\n throw new Refusal(`connection-${field}-required`, { connection }, `A connection needs a ${field}.`)\n }\n }\n}\n\n@Resolver(Connection)\n@UseMiddleware(SpeakRefusals)\nexport class ConnectionMutation {\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Creates a new connection.' })\n async createConnection(\n @Arg('connection') connection: NewConnection,\n @Ctx() context: ResolverContext\n ): Promise<Connection> {\n const { domain, user, tx } = context.state\n\n refuseMissingFields(connection)\n\n return await tx.getRepository(Connection).save({\n ...connection,\n ...paramsToStore(connection),\n domain,\n creator: user,\n updater: user\n })\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Updates an existing connection.' })\n async updateConnection(\n @Arg('name') name: string,\n @Arg('patch') patch: ConnectionPatch,\n @Ctx() context: ResolverContext\n ): Promise<Connection> {\n const { domain, user, tx } = context.state\n\n const repository = tx.getRepository(Connection)\n const connection = await repository.findOne({\n where: { domain: { id: domain.id }, name }\n })\n\n if (!connection) {\n throw notInThisDomain(name)\n }\n\n refuseMissingFields(patch, connection)\n\n if (patch.name && patch.name !== connection.name) {\n await carryConnectionEnvVars(tx, domain, connection.name, patch.name)\n }\n\n return await repository.save({\n ...connection,\n ...patch,\n ...paramsToStore(patch, connection),\n id: connection.id,\n updater: user\n })\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => [Connection], { description: 'Updates multiple connections at once.' })\n async updateMultipleConnection(\n @Arg('patches', type => [ConnectionPatch]) patches: ConnectionPatch[],\n @Ctx() context: ResolverContext\n ): Promise<Connection[]> {\n const { domain, user, tx } = context.state\n\n let results = []\n const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')\n const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')\n const connectionRepo = tx.getRepository(Connection)\n\n if (_createRecords.length > 0) {\n for (let i = 0; i < _createRecords.length; i++) {\n /* A new row: an id it carries would make `save` overwrite the row of that id, wherever it is. */\n const { id, ...newRecord } = _createRecords[i]\n refuseMissingFields(newRecord)\n\n const result = await connectionRepo.save({\n ...newRecord,\n ...paramsToStore(newRecord),\n domain,\n creator: user,\n updater: user\n })\n\n results.push({ ...result, cuFlag: '+' })\n }\n }\n\n if (_updateRecords.length > 0) {\n for (let i = 0; i < _updateRecords.length; i++) {\n const newRecord = _updateRecords[i]\n const connection = await connectionRepo.findOneBy({ id: newRecord.id, domain: { id: domain.id } })\n\n if (!connection) {\n throw notInThisDomain(newRecord.name || newRecord.id)\n }\n\n refuseMissingFields(newRecord, connection)\n\n if (newRecord.name && newRecord.name !== connection.name) {\n await carryConnectionEnvVars(tx, domain, connection.name, newRecord.name)\n }\n\n const result = await connectionRepo.save({\n ...connection,\n ...newRecord,\n ...paramsToStore(newRecord, connection),\n id: connection.id,\n updater: user\n })\n\n results.push({ ...result, cuFlag: 'M' })\n }\n }\n\n return results\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, { description: 'Deletes a single connection by its name.' })\n async deleteConnection(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, tx } = context.state\n\n await tx.getRepository(Connection).delete({ domain: { id: domain.id }, name })\n return true\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, { description: 'Deletes multiple connections by their names.' })\n async deleteConnections(\n @Arg('names', type => [String]) names: string[],\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, tx } = context.state\n\n await tx.getRepository(Connection).delete({\n domain: { id: domain.id },\n name: In(names)\n })\n\n return true\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Establishes a live connection to a configured endpoint.' })\n async connectConnection(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<Connection> {\n const { domain } = context.state\n var repository = getRepository(Connection)\n\n // ancestor 도메인을 closest-first 로 순회하여 first hit 사용\n const domainIds = await getDomainIdsWithAncestors(domain)\n var connection: Connection | null = null\n for (const did of domainIds) {\n connection = await repository.findOne({\n where: { domain: { id: did }, name },\n relations: ['domain', 'edge']\n })\n if (connection) break\n }\n\n if (!connection) {\n throw new Error(`Connection with name '${name}' not found`)\n }\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n if (connection.domain.id !== domain.id) {\n connection.domain = domain\n await connection.connect()\n /* on-demand 연결인 경우에 connection을 저장하지 말아야 한다. */\n } else {\n await connection.connect()\n await repository.save(connection)\n }\n\n return {\n ...connection,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n } as Connection\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Terminates a live connection.' })\n async disconnectConnection(@Arg('name') name: string, @Ctx() context: ResolverContext) {\n const { domain } = context.state\n\n var repository = getRepository(Connection)\n\n // ancestor 도메인을 closest-first 로 순회하여 first hit 사용\n const domainIds = await getDomainIdsWithAncestors(domain)\n var connection: Connection | null = null\n for (const did of domainIds) {\n connection = await repository.findOne({\n where: { domain: { id: did }, name },\n relations: ['domain', 'edge']\n })\n if (connection) break\n }\n\n if (!connection) {\n throw new Error(`Connection with name '${name}' not found`)\n }\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n if (connection.domain.id !== domain.id) {\n connection.domain = domain\n await connection.disconnect()\n\n /* on-demand 연결인 경우에 connection을 저장하지 말아야 한다. */\n } else {\n await connection.disconnect()\n await repository.save(connection)\n }\n\n return {\n ...connection,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n }\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, {\n description: 'Imports multiple connections. Can overwrite existing connections if IDs or names match.'\n })\n async importConnections(\n @Arg('connections', type => [ConnectionPatch]) connections: Connection[],\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain, user } = context.state\n\n const repository = tx.getRepository(Connection)\n\n await Promise.all(\n connections.map(async (connection: Connection) => {\n const { id, name } = connection\n\n if (id) {\n const sameId = await repository.findOneBy({ id })\n\n if (sameId) {\n if (sameId.domainId != domain.id) {\n throw `Connection with id '${id}:${name}' is already taken by another domain`\n }\n\n const sameName = await repository.findOneBy({ domain: { id: domain.id }, name })\n if (sameName && sameName.id != id) {\n throw `Connection with name '${name}' is already taken by another connection`\n }\n\n await repository.save({\n ...sameId,\n ...connection,\n ...paramsToStore(connection, sameId),\n domain,\n updater: user\n })\n\n return\n }\n }\n\n await repository.save({\n ...connection,\n ...paramsToStore(connection),\n domain,\n updater: user,\n creator: user\n })\n })\n )\n\n return true\n }\n}\n"]}
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const type_graphql_1 = require("type-graphql");
6
6
  const typeorm_1 = require("typeorm");
7
7
  const scheduler_client_1 = require("@things-factory/scheduler-client");
8
+ const shell_1 = require("@things-factory/shell");
8
9
  const scenario_1 = require("./scenario");
9
10
  const scenario_history_1 = require("./scenario-history");
10
11
  const scenario_type_1 = require("./scenario-type");
@@ -254,6 +255,13 @@ let ScenarioMutation = class ScenarioMutation {
254
255
  retry_period: 60
255
256
  }
256
257
  });
258
+ /*
259
+ * registerSchedule answers nothing when the scheduler did not take it (it logs and returns). A schedule nobody holds
260
+ * was saved as started with no id - said here instead (the user, 2026-10-31).
261
+ */
262
+ if (!handle) {
263
+ throw new shell_1.Refusal('scenario-schedule-not-registered', { scenario: scenario.name }, `The scheduler did not take the schedule of '${scenario.name}'.`);
264
+ }
257
265
  return await repository.save({
258
266
  ...scenario,
259
267
  scheduleId: handle
@@ -261,6 +269,7 @@ let ScenarioMutation = class ScenarioMutation {
261
269
  }
262
270
  catch (err) {
263
271
  console.error('startScenarioSchedule', err);
272
+ throw err;
264
273
  }
265
274
  }
266
275
  async stopScenarioSchedule(scenarioId, context) {
@@ -491,6 +500,7 @@ tslib_1.__decorate([
491
500
  tslib_1.__metadata("design:returntype", Promise)
492
501
  ], ScenarioMutation.prototype, "revertScenarioVersion", null);
493
502
  exports.ScenarioMutation = ScenarioMutation = tslib_1.__decorate([
494
- (0, type_graphql_1.Resolver)(scenario_1.Scenario)
503
+ (0, type_graphql_1.Resolver)(scenario_1.Scenario),
504
+ (0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
495
505
  ], ScenarioMutation);
496
506
  //# sourceMappingURL=scenario-mutation.js.map