@things-factory/integration-base 10.0.0-zeta.3 → 10.0.0

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 (65) hide show
  1. package/dist-server/controllers/scenario-controller.d.ts +2 -2
  2. package/dist-server/controllers/scenario-controller.js +19 -8
  3. package/dist-server/controllers/scenario-controller.js.map +1 -1
  4. package/dist-server/engine/analyzer/analyze-integration.js +6 -2
  5. package/dist-server/engine/analyzer/analyze-integration.js.map +1 -1
  6. package/dist-server/engine/connector/operato-connector.js +4 -1
  7. package/dist-server/engine/connector/operato-connector.js.map +1 -1
  8. package/dist-server/engine/scenario-engine.js +7 -2
  9. package/dist-server/engine/scenario-engine.js.map +1 -1
  10. package/dist-server/engine/task/pick-pending-scenario.js +6 -1
  11. package/dist-server/engine/task/pick-pending-scenario.js.map +1 -1
  12. package/dist-server/engine/task/stop-scenario.js +1 -1
  13. package/dist-server/engine/task/stop-scenario.js.map +1 -1
  14. package/dist-server/engine/task/sub-scenario.js +6 -1
  15. package/dist-server/engine/task/sub-scenario.js.map +1 -1
  16. package/dist-server/engine/task/switch-range-scenario.js +6 -1
  17. package/dist-server/engine/task/switch-range-scenario.js.map +1 -1
  18. package/dist-server/engine/task/switch-scenario.js +6 -1
  19. package/dist-server/engine/task/switch-scenario.js.map +1 -1
  20. package/dist-server/routers/scenario-schedule-callback-router.js +4 -1
  21. package/dist-server/routers/scenario-schedule-callback-router.js.map +1 -1
  22. package/dist-server/routers/scenario-view-router.js +4 -3
  23. package/dist-server/routers/scenario-view-router.js.map +1 -1
  24. package/dist-server/service/index.d.ts +4 -1
  25. package/dist-server/service/index.js +4 -1
  26. package/dist-server/service/index.js.map +1 -1
  27. package/dist-server/service/scenario/event-subscriber.d.ts +22 -0
  28. package/dist-server/service/scenario/event-subscriber.js +49 -0
  29. package/dist-server/service/scenario/event-subscriber.js.map +1 -0
  30. package/dist-server/service/scenario/index.d.ts +6 -2
  31. package/dist-server/service/scenario/index.js +7 -3
  32. package/dist-server/service/scenario/index.js.map +1 -1
  33. package/dist-server/service/scenario/resolve-steps.d.ts +43 -0
  34. package/dist-server/service/scenario/resolve-steps.js +101 -0
  35. package/dist-server/service/scenario/resolve-steps.js.map +1 -0
  36. package/dist-server/service/scenario/scenario-history.d.ts +44 -0
  37. package/dist-server/service/scenario/scenario-history.js +167 -0
  38. package/dist-server/service/scenario/scenario-history.js.map +1 -0
  39. package/dist-server/service/scenario/scenario-mutation.d.ts +2 -0
  40. package/dist-server/service/scenario/scenario-mutation.js +150 -36
  41. package/dist-server/service/scenario/scenario-mutation.js.map +1 -1
  42. package/dist-server/service/scenario/scenario-query.js +8 -14
  43. package/dist-server/service/scenario/scenario-query.js.map +1 -1
  44. package/dist-server/service/scenario/scenario-version-diff.d.ts +8 -0
  45. package/dist-server/service/scenario/scenario-version-diff.js +107 -0
  46. package/dist-server/service/scenario/scenario-version-diff.js.map +1 -0
  47. package/dist-server/service/scenario/scenario-version-query.d.ts +11 -0
  48. package/dist-server/service/scenario/scenario-version-query.js +135 -0
  49. package/dist-server/service/scenario/scenario-version-query.js.map +1 -0
  50. package/dist-server/service/scenario/scenario-version-type.d.ts +18 -0
  51. package/dist-server/service/scenario/scenario-version-type.js +79 -0
  52. package/dist-server/service/scenario/scenario-version-type.js.map +1 -0
  53. package/dist-server/service/scenario/scenario.d.ts +23 -0
  54. package/dist-server/service/scenario/scenario.js +18 -3
  55. package/dist-server/service/scenario/scenario.js.map +1 -1
  56. package/dist-server/service/scenario-instance/scenario-instance-mutation.d.ts +2 -2
  57. package/dist-server/service/scenario-instance/scenario-instance-mutation.js +8 -6
  58. package/dist-server/service/scenario-instance/scenario-instance-mutation.js.map +1 -1
  59. package/dist-server/service/step/step-mutation.js +26 -13
  60. package/dist-server/service/step/step-mutation.js.map +1 -1
  61. package/dist-server/tsconfig.tsbuildinfo +1 -1
  62. package/dist-server/utils/version-text-column.d.ts +16 -0
  63. package/dist-server/utils/version-text-column.js +67 -0
  64. package/dist-server/utils/version-text-column.js.map +1 -0
  65. package/package.json +12 -11
@@ -6,6 +6,7 @@ const koa_router_1 = tslib_1.__importDefault(require("koa-router"));
6
6
  const shell_1 = require("@things-factory/shell");
7
7
  const auth_base_1 = require("@things-factory/auth-base");
8
8
  const scenario_1 = require("../service/scenario/scenario");
9
+ const resolve_steps_1 = require("../service/scenario/resolve-steps");
9
10
  const scenario_engine_1 = require("../engine/scenario-engine");
10
11
  exports.scenarioScheduleCallbackRouter = new koa_router_1.default();
11
12
  /* When a callback occurs from the scheduler when a scheduled scenario is on schedule. */
@@ -39,11 +40,13 @@ exports.scenarioScheduleCallbackRouter.post('/callback-schedule-for-scenario', a
39
40
  }
40
41
  const scenario = await (0, shell_1.getRepository)(scenario_1.Scenario).findOne({
41
42
  where: { domain: { id: domainId }, id: scenarioId },
42
- relations: ['domain', 'steps', 'creator']
43
+ relations: ['domain', 'creator']
43
44
  });
44
45
  if (!scenario) {
45
46
  throw new Error(`Scenario having given scenarioId(${domain?.subdomain}:${scenarioId}) not found`);
46
47
  }
48
+ // [버전관리] 스케줄(운영) 실행은 최신 릴리즈 스냅샷을 사용. 릴리즈 없으면 draft 폴백.
49
+ scenario.steps = await (0, resolve_steps_1.resolveRunnableSteps)(scenario, { mode: 'released' });
47
50
  const user = (userId && (await (0, shell_1.getRepository)(auth_base_1.User).findOne({ where: { id: userId } }))) || scenario.creator;
48
51
  scenario_engine_1.ScenarioEngine.loadIteration(scenario.name, scenario, {
49
52
  domain,
@@ -1 +1 @@
1
- {"version":3,"file":"scenario-schedule-callback-router.js","sourceRoot":"","sources":["../../server/routers/scenario-schedule-callback-router.ts"],"names":[],"mappings":";;;;AAAA,oEAA+B;AAE/B,iDAAqD;AACrD,yDAAgD;AAGhD,2DAAuD;AACvD,+DAA0D;AAE7C,QAAA,8BAA8B,GAAG,IAAI,oBAAM,EAAE,CAAA;AAE1D,yFAAyF;AACzF,sCAA8B,CAAC,IAAI,CAAC,iCAAiC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IAC7F,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,IAA+B,CAAA;IACxE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,IAAI,CAAA;IAE7B,4BAA4B;IAC5B,yBAAyB;IACzB,oBAAoB;IACpB,oBAAoB;IACpB,qBAAqB;IAErB,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAEhC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IAED,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;IACvE,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,MAAM,CAAA;IAEpE,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,SAAS,QAAQ,aAAa,UAAU,kCAAkC,CAAC,CAAA;IAC7F,CAAC;IAED,IAAI,QAAQ,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAA;IACnF,CAAC;IAED,IAAI,IAAI,IAAI,UAAU,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAA;IAClF,CAAC;IAED,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAA;IACvF,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAa,EAAC,mBAAQ,CAAC,CAAC,OAAO,CAAC;QACrD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE;QACnD,SAAS,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC;KAC1C,CAAC,CAAA;IAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,EAAE,SAAS,IAAI,UAAU,aAAa,CAAC,CAAA;IACnG,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAA;IAE3G,gCAAc,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE;QACpD,MAAM;QACN,IAAI;QACJ,qDAAqD;KACtD,CAAC,CAAA;IAEF,OAAO,CAAC,MAAM,GAAG,GAAG,CAAA;AACtB,CAAC,CAAC,CAAA","sourcesContent":["import Router from 'koa-router'\n\nimport { getRepository } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { ScheduleRegisterRequest } from '@things-factory/scheduler-client'\n\nimport { Scenario } from '../service/scenario/scenario'\nimport { ScenarioEngine } from '../engine/scenario-engine'\n\nexport const scenarioScheduleCallbackRouter = new Router()\n\n/* When a callback occurs from the scheduler when a scheduled scenario is on schedule. */\nscenarioScheduleCallbackRouter.post('/callback-schedule-for-scenario', async (context, next) => {\n const { client, task } = context.request.body as ScheduleRegisterRequest\n const { userId } = task?.data\n\n // application: Application,\n // group: `${domain.id}`,\n // type: 'scenario',\n // key: scenario.id,\n // operation: 'start'\n\n const { domain } = context.state\n\n if (!domain) {\n throw new Error('cannot identify the current domain.')\n }\n\n if (!client || typeof client !== 'object') {\n throw new Error('client property should be a part of callback body.')\n }\n\n const { group: domainId, key: scenarioId, operation, type } = client\n\n if (!domainId || !scenarioId) {\n throw new Error(`group(${domainId}) and key(${scenarioId}) properties should not be empty`)\n }\n\n if (domainId != domain.id) {\n throw new Error('client property(group) is not matched with the current domain.')\n }\n\n if (type != 'scenario') {\n throw new Error('client property(type) is not matched with the required value.')\n }\n\n if (operation != 'start') {\n throw new Error('client property(operation) is not matched with the required value.')\n }\n\n const scenario = await getRepository(Scenario).findOne({\n where: { domain: { id: domainId }, id: scenarioId },\n relations: ['domain', 'steps', 'creator']\n })\n\n if (!scenario) {\n throw new Error(`Scenario having given scenarioId(${domain?.subdomain}:${scenarioId}) not found`)\n }\n\n const user = (userId && (await getRepository(User).findOne({ where: { id: userId } }))) || scenario.creator\n\n ScenarioEngine.loadIteration(scenario.name, scenario, {\n domain,\n user\n /* variables: schedule 등록시 variables 는 설정할 방법이 없음. */\n })\n\n context.status = 200\n})\n"]}
1
+ {"version":3,"file":"scenario-schedule-callback-router.js","sourceRoot":"","sources":["../../server/routers/scenario-schedule-callback-router.ts"],"names":[],"mappings":";;;;AAAA,oEAA+B;AAE/B,iDAAqD;AACrD,yDAAgD;AAGhD,2DAAuD;AACvD,qEAAwE;AACxE,+DAA0D;AAE7C,QAAA,8BAA8B,GAAG,IAAI,oBAAM,EAAE,CAAA;AAE1D,yFAAyF;AACzF,sCAA8B,CAAC,IAAI,CAAC,iCAAiC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IAC7F,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,IAA+B,CAAA;IACxE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,IAAI,CAAA;IAE7B,4BAA4B;IAC5B,yBAAyB;IACzB,oBAAoB;IACpB,oBAAoB;IACpB,qBAAqB;IAErB,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAEhC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IAED,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;IACvE,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,MAAM,CAAA;IAEpE,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,SAAS,QAAQ,aAAa,UAAU,kCAAkC,CAAC,CAAA;IAC7F,CAAC;IAED,IAAI,QAAQ,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAA;IACnF,CAAC;IAED,IAAI,IAAI,IAAI,UAAU,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAA;IAClF,CAAC;IAED,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAA;IACvF,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAa,EAAC,mBAAQ,CAAC,CAAC,OAAO,CAAC;QACrD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE;QACnD,SAAS,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC;KACjC,CAAC,CAAA;IAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,EAAE,SAAS,IAAI,UAAU,aAAa,CAAC,CAAA;IACnG,CAAC;IAED,uDAAuD;IACvD,QAAQ,CAAC,KAAK,GAAG,MAAM,IAAA,oCAAoB,EAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAA;IAE3E,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAA;IAE3G,gCAAc,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE;QACpD,MAAM;QACN,IAAI;QACJ,qDAAqD;KACtD,CAAC,CAAA;IAEF,OAAO,CAAC,MAAM,GAAG,GAAG,CAAA;AACtB,CAAC,CAAC,CAAA","sourcesContent":["import Router from 'koa-router'\n\nimport { getRepository } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { ScheduleRegisterRequest } from '@things-factory/scheduler-client'\n\nimport { Scenario } from '../service/scenario/scenario'\nimport { resolveRunnableSteps } from '../service/scenario/resolve-steps'\nimport { ScenarioEngine } from '../engine/scenario-engine'\n\nexport const scenarioScheduleCallbackRouter = new Router()\n\n/* When a callback occurs from the scheduler when a scheduled scenario is on schedule. */\nscenarioScheduleCallbackRouter.post('/callback-schedule-for-scenario', async (context, next) => {\n const { client, task } = context.request.body as ScheduleRegisterRequest\n const { userId } = task?.data\n\n // application: Application,\n // group: `${domain.id}`,\n // type: 'scenario',\n // key: scenario.id,\n // operation: 'start'\n\n const { domain } = context.state\n\n if (!domain) {\n throw new Error('cannot identify the current domain.')\n }\n\n if (!client || typeof client !== 'object') {\n throw new Error('client property should be a part of callback body.')\n }\n\n const { group: domainId, key: scenarioId, operation, type } = client\n\n if (!domainId || !scenarioId) {\n throw new Error(`group(${domainId}) and key(${scenarioId}) properties should not be empty`)\n }\n\n if (domainId != domain.id) {\n throw new Error('client property(group) is not matched with the current domain.')\n }\n\n if (type != 'scenario') {\n throw new Error('client property(type) is not matched with the required value.')\n }\n\n if (operation != 'start') {\n throw new Error('client property(operation) is not matched with the required value.')\n }\n\n const scenario = await getRepository(Scenario).findOne({\n where: { domain: { id: domainId }, id: scenarioId },\n relations: ['domain', 'creator']\n })\n\n if (!scenario) {\n throw new Error(`Scenario having given scenarioId(${domain?.subdomain}:${scenarioId}) not found`)\n }\n\n // [버전관리] 스케줄(운영) 실행은 최신 릴리즈 스냅샷을 사용. 릴리즈 없으면 draft 폴백.\n scenario.steps = await resolveRunnableSteps(scenario, { mode: 'released' })\n\n const user = (userId && (await getRepository(User).findOne({ where: { id: userId } }))) || scenario.creator\n\n ScenarioEngine.loadIteration(scenario.name, scenario, {\n domain,\n user\n /* variables: schedule 등록시 variables 는 설정할 방법이 없음. */\n })\n\n context.status = 200\n})\n"]}
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const koa_router_1 = tslib_1.__importDefault(require("koa-router"));
6
6
  const shell_1 = require("@things-factory/shell");
7
7
  const scenario_1 = require("../service/scenario/scenario");
8
+ const resolve_steps_1 = require("../service/scenario/resolve-steps");
8
9
  exports.scenarioViewRouter = new koa_router_1.default();
9
10
  exports.scenarioViewRouter.get('/scenario-view/:name', async (context, next) => {
10
11
  const { domain } = context.state;
@@ -13,10 +14,10 @@ exports.scenarioViewRouter.get('/scenario-view/:name', async (context, next) =>
13
14
  where: {
14
15
  domain: { id: domain.id },
15
16
  name
16
- },
17
- relations: ['steps']
17
+ }
18
18
  });
19
- const steps = scenario.steps;
19
+ // [버전관리] 시나리오 흐름 뷰는 편집 중 구조(draft)를 보여준다.
20
+ const steps = await (0, resolve_steps_1.resolveScenarioSteps)(scenario);
20
21
  const nodes = {};
21
22
  const edges = [];
22
23
  steps.forEach(({ id, name }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"scenario-view-router.js","sourceRoot":"","sources":["../../server/routers/scenario-view-router.ts"],"names":[],"mappings":";;;;AAAA,oEAA+B;AAE/B,iDAAqD;AAErD,2DAAuD;AAG1C,QAAA,kBAAkB,GAAG,IAAI,oBAAM,EAAE,CAAA;AAE9C,0BAAkB,CAAC,GAAG,CAAC,sBAAsB,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IACrE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAChC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAA;IAE/B,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAa,EAAC,mBAAQ,CAAC,CAAC,OAAO,CAAC;QACrD,KAAK,EAAE;YACL,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE;YACzB,IAAI;SACL;QACD,SAAS,EAAE,CAAC,OAAO,CAAC;KACrB,CAAC,CAAA;IAEF,MAAM,KAAK,GAAW,QAAQ,CAAC,KAAK,CAAA;IACpC,MAAM,KAAK,GAAG,EAAE,CAAA;IAChB,MAAM,KAAK,GAAG,EAAE,CAAA;IAEhB,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QAC7B,KAAK,CAAC,EAAE,CAAC,GAAG;YACV,EAAE;YACF,IAAI;SACL,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC;YACT,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;YACnB,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;SACxB,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE;QACpC,KAAK,EAAE;YACL,KAAK;YACL,KAAK;SACN;KACF,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import Router from 'koa-router'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { Scenario } from '../service/scenario/scenario'\nimport { Step } from '../service/step/step-type'\n\nexport const scenarioViewRouter = new Router()\n\nscenarioViewRouter.get('/scenario-view/:name', async (context, next) => {\n const { domain } = context.state\n const { name } = context.params\n\n const scenario = await getRepository(Scenario).findOne({\n where: {\n domain: { id: domain.id },\n name\n },\n relations: ['steps']\n })\n\n const steps: Step[] = scenario.steps\n const nodes = {}\n const edges = []\n\n steps.forEach(({ id, name }) => {\n nodes[id] = {\n id,\n name\n }\n })\n\n for (let i = 0; i < steps.length - 1; i++) {\n edges.push({\n source: steps[i].id,\n target: steps[i + 1].id\n })\n }\n\n await context.render('scenario-view', {\n model: {\n nodes,\n edges\n }\n })\n})\n"]}
1
+ {"version":3,"file":"scenario-view-router.js","sourceRoot":"","sources":["../../server/routers/scenario-view-router.ts"],"names":[],"mappings":";;;;AAAA,oEAA+B;AAE/B,iDAAqD;AAErD,2DAAuD;AAEvD,qEAAwE;AAE3D,QAAA,kBAAkB,GAAG,IAAI,oBAAM,EAAE,CAAA;AAE9C,0BAAkB,CAAC,GAAG,CAAC,sBAAsB,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IACrE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAChC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAA;IAE/B,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAa,EAAC,mBAAQ,CAAC,CAAC,OAAO,CAAC;QACrD,KAAK,EAAE;YACL,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE;YACzB,IAAI;SACL;KACF,CAAC,CAAA;IAEF,0CAA0C;IAC1C,MAAM,KAAK,GAAW,MAAM,IAAA,oCAAoB,EAAC,QAAQ,CAAC,CAAA;IAC1D,MAAM,KAAK,GAAG,EAAE,CAAA;IAChB,MAAM,KAAK,GAAG,EAAE,CAAA;IAEhB,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QAC7B,KAAK,CAAC,EAAE,CAAC,GAAG;YACV,EAAE;YACF,IAAI;SACL,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC;YACT,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;YACnB,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;SACxB,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE;QACpC,KAAK,EAAE;YACL,KAAK;YACL,KAAK;SACN;KACF,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import Router from 'koa-router'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { Scenario } from '../service/scenario/scenario'\nimport { Step } from '../service/step/step-type'\nimport { resolveScenarioSteps } from '../service/scenario/resolve-steps'\n\nexport const scenarioViewRouter = new Router()\n\nscenarioViewRouter.get('/scenario-view/:name', async (context, next) => {\n const { domain } = context.state\n const { name } = context.params\n\n const scenario = await getRepository(Scenario).findOne({\n where: {\n domain: { id: domain.id },\n name\n }\n })\n\n // [버전관리] 시나리오 흐름 뷰는 편집 중 구조(draft)를 보여준다.\n const steps: Step[] = await resolveScenarioSteps(scenario)\n const nodes = {}\n const edges = []\n\n steps.forEach(({ id, name }) => {\n nodes[id] = {\n id,\n name\n }\n })\n\n for (let i = 0; i < steps.length - 1; i++) {\n edges.push({\n source: steps[i].id,\n target: steps[i + 1].id\n })\n }\n\n await context.render('scenario-view', {\n model: {\n nodes,\n edges\n }\n })\n})\n"]}
@@ -4,6 +4,8 @@ export * from './connector/connector-type';
4
4
  export * from './connection/connection';
5
5
  export * from './connection/connection-type';
6
6
  export * from './scenario/scenario';
7
+ export * from './scenario/scenario-history';
8
+ export * from './scenario/scenario-version-type';
7
9
  export * from './scenario-instance/scenario-instance-type';
8
10
  export * from './scenario-queue/scenario-queue-type';
9
11
  export * from './step/step-type';
@@ -11,8 +13,9 @@ export * from './scenario-flow/scenario-flow';
11
13
  export * from './payload-log/payload-log';
12
14
  export * from './state-register/state-register';
13
15
  export declare const entities: any[];
16
+ export declare const subscribers: typeof import("./scenario/event-subscriber").ScenarioHistoryEntitySubscriber[];
14
17
  export declare const schema: {
15
- resolverClasses: (typeof import("./connection/connection-query").ConnectionQuery | typeof import("./connection/connection-mutation").ConnectionMutation | typeof import("./connection/connection-subscription").ConnectionSubscription | typeof import("./connector/connector-query").ConnectorQuery | typeof import("./scenario/scenario-query").ScenarioQuery | typeof import("./scenario/scenario-mutation").ScenarioMutation | typeof import("./scenario-instance/scenario-instance-query").ScenarioInstanceQuery | typeof import("./scenario-instance/scenario-instance-mutation").ScenarioInstanceMutation | typeof import("./scenario-instance/scenario-instance-subscription").ScenarioInstanceSubscription | typeof import("./scenario-queue/scenario-queue-subscription").ScenarioQueueSubscription | typeof import("./step/step-query").StepQuery | typeof import("./step/step-mutation").StepMutation | typeof import("./task-type/task-type-query").TaskTypeQuery | typeof import("./payload-log/payload-log-query").PayloadLogQuery | typeof import("./payload-log/payload-log-mutation").PayloadLogMutation | typeof import("./state-register/state-register-query").StateRegisterQuery | typeof import("./state-register/state-register-mutation").StateRegisterMutation | typeof import("./state-register/data-resolver").DataResolver | typeof import("./analysis/analysis-query").IntegrationAnalysisQuery | typeof import("./domain-attribute/domain-attribute-query").DomainAttributeQuery)[];
18
+ resolverClasses: (typeof import("./connection/connection-query").ConnectionQuery | typeof import("./connection/connection-mutation").ConnectionMutation | typeof import("./connection/connection-subscription").ConnectionSubscription | typeof import("./connector/connector-query").ConnectorQuery | typeof import("./scenario/scenario-query").ScenarioQuery | typeof import("./scenario/scenario-mutation").ScenarioMutation | typeof import("./scenario/scenario-version-query").ScenarioVersionQuery | typeof import("./scenario-instance/scenario-instance-query").ScenarioInstanceQuery | typeof import("./scenario-instance/scenario-instance-mutation").ScenarioInstanceMutation | typeof import("./scenario-instance/scenario-instance-subscription").ScenarioInstanceSubscription | typeof import("./scenario-queue/scenario-queue-subscription").ScenarioQueueSubscription | typeof import("./step/step-query").StepQuery | typeof import("./step/step-mutation").StepMutation | typeof import("./task-type/task-type-query").TaskTypeQuery | typeof import("./payload-log/payload-log-query").PayloadLogQuery | typeof import("./payload-log/payload-log-mutation").PayloadLogMutation | typeof import("./state-register/state-register-query").StateRegisterQuery | typeof import("./state-register/state-register-mutation").StateRegisterMutation | typeof import("./state-register/data-resolver").DataResolver | typeof import("./analysis/analysis-query").IntegrationAnalysisQuery | typeof import("./domain-attribute/domain-attribute-query").DomainAttributeQuery)[];
16
19
  };
17
20
  export { PayloadType } from './payload-log/payload-log';
18
21
  export { createPayloadLog } from './payload-log/payload-log-mutation';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createPayloadLog = exports.PayloadType = exports.schema = exports.entities = void 0;
3
+ exports.createPayloadLog = exports.PayloadType = exports.schema = exports.subscribers = exports.entities = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const connection_1 = require("./connection");
6
6
  const connector_1 = require("./connector");
@@ -19,6 +19,8 @@ tslib_1.__exportStar(require("./connector/connector-type"), exports);
19
19
  tslib_1.__exportStar(require("./connection/connection"), exports);
20
20
  tslib_1.__exportStar(require("./connection/connection-type"), exports);
21
21
  tslib_1.__exportStar(require("./scenario/scenario"), exports);
22
+ tslib_1.__exportStar(require("./scenario/scenario-history"), exports);
23
+ tslib_1.__exportStar(require("./scenario/scenario-version-type"), exports);
22
24
  tslib_1.__exportStar(require("./scenario-instance/scenario-instance-type"), exports);
23
25
  tslib_1.__exportStar(require("./scenario-queue/scenario-queue-type"), exports);
24
26
  tslib_1.__exportStar(require("./step/step-type"), exports);
@@ -36,6 +38,7 @@ exports.entities = [
36
38
  ...payload_log_1.entities,
37
39
  ...state_register_1.entities
38
40
  ];
41
+ exports.subscribers = [...scenario_1.subscribers];
39
42
  exports.schema = {
40
43
  resolverClasses: [
41
44
  ...task_type_1.resolvers,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,6CAA+F;AAC/F,2CAA4F;AAC5F,yCAAyF;AACzF,2DAAkH;AAClH,qDAAyG;AACzG,iCAA6E;AAC7E,2CAA0F;AAC1F,+CAAgG;AAChG,qDAAyG;AACzG,yCAAkE;AAClE,yDAA0E;AAE1E,0DAA+B;AAC/B,qEAA0C;AAC1C,qEAA0C;AAC1C,kEAAuC;AACvC,uEAA4C;AAC5C,8DAAmC;AACnC,qFAA0D;AAC1D,+EAAoD;AACpD,2DAAgC;AAChC,wEAA6C;AAC7C,oEAAyC;AACzC,0EAA+C;AAElC,QAAA,QAAQ,GAAG;IACtB,GAAG,oBAAgB;IACnB,GAAG,oBAAiB;IACpB,GAAG,qBAAkB;IACrB,GAAG,mBAAgB;IACnB,GAAG,4BAAwB;IAC3B,GAAG,yBAAqB;IACxB,GAAG,eAAY;IACf,GAAG,sBAAkB;IACrB,GAAG,yBAAqB;CACzB,CAAA;AAEY,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE;QACf,GAAG,qBAAiB;QACpB,GAAG,qBAAkB;QACrB,GAAG,sBAAmB;QACtB,GAAG,oBAAiB;QACpB,GAAG,6BAAyB;QAC5B,GAAG,0BAAsB;QACzB,GAAG,gBAAa;QAChB,GAAG,uBAAmB;QACtB,GAAG,oBAAwB;QAC3B,GAAG,0BAAsB;QACzB,GAAG,4BAAwB;KAC5B;CACF,CAAA;AAED,yDAAuD;AAA9C,0GAAA,WAAW,OAAA;AACpB,2EAAqE;AAA5D,wHAAA,gBAAgB,OAAA","sourcesContent":["import { entities as ConnectionEntities, resolvers as ConnectionResolvers } from './connection'\nimport { entities as ConnectorEntities, resolvers as ConnectorResolvers } from './connector'\nimport { entities as ScenarioEntities, resolvers as ScenarioResolvers } from './scenario'\nimport { entities as ScenarioInstanceEntities, resolvers as ScenarioInstanceResolvers } from './scenario-instance'\nimport { entities as ScenarioQueueEntities, resolvers as ScenarioQueueResolvers } from './scenario-queue'\nimport { entities as StepEntities, resolvers as StepResolvers } from './step'\nimport { entities as TaskTypeEntities, resolvers as TaskTypeResolvers } from './task-type'\nimport { entities as PayloadLogEntities, resolvers as PayloadLogResolvers } from './payload-log'\nimport { entities as StateRegisterEntities, resolvers as StateRegisterResolvers } from './state-register'\nimport { resolvers as IntegrationAnalysisQuery } from './analysis'\nimport { resolvers as DomainAttributeResolvers } from './domain-attribute'\n\nexport * from './property-spec'\nexport * from './task-type/task-type-type'\nexport * from './connector/connector-type'\nexport * from './connection/connection'\nexport * from './connection/connection-type'\nexport * from './scenario/scenario'\nexport * from './scenario-instance/scenario-instance-type'\nexport * from './scenario-queue/scenario-queue-type'\nexport * from './step/step-type'\nexport * from './scenario-flow/scenario-flow'\nexport * from './payload-log/payload-log'\nexport * from './state-register/state-register'\n\nexport const entities = [\n ...TaskTypeEntities,\n ...ConnectorEntities,\n ...ConnectionEntities,\n ...ScenarioEntities,\n ...ScenarioInstanceEntities,\n ...ScenarioQueueEntities,\n ...StepEntities,\n ...PayloadLogEntities,\n ...StateRegisterEntities\n]\n\nexport const schema = {\n resolverClasses: [\n ...TaskTypeResolvers,\n ...ConnectorResolvers,\n ...ConnectionResolvers,\n ...ScenarioResolvers,\n ...ScenarioInstanceResolvers,\n ...ScenarioQueueResolvers,\n ...StepResolvers,\n ...PayloadLogResolvers,\n ...IntegrationAnalysisQuery,\n ...StateRegisterResolvers,\n ...DomainAttributeResolvers\n ]\n}\n\nexport { PayloadType } from './payload-log/payload-log'\nexport { createPayloadLog } from './payload-log/payload-log-mutation'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,6CAA+F;AAC/F,2CAA4F;AAC5F,yCAImB;AACnB,2DAAkH;AAClH,qDAAyG;AACzG,iCAA6E;AAC7E,2CAA0F;AAC1F,+CAAgG;AAChG,qDAAyG;AACzG,yCAAkE;AAClE,yDAA0E;AAE1E,0DAA+B;AAC/B,qEAA0C;AAC1C,qEAA0C;AAC1C,kEAAuC;AACvC,uEAA4C;AAC5C,8DAAmC;AACnC,sEAA2C;AAC3C,2EAAgD;AAChD,qFAA0D;AAC1D,+EAAoD;AACpD,2DAAgC;AAChC,wEAA6C;AAC7C,oEAAyC;AACzC,0EAA+C;AAElC,QAAA,QAAQ,GAAG;IACtB,GAAG,oBAAgB;IACnB,GAAG,oBAAiB;IACpB,GAAG,qBAAkB;IACrB,GAAG,mBAAgB;IACnB,GAAG,4BAAwB;IAC3B,GAAG,yBAAqB;IACxB,GAAG,eAAY;IACf,GAAG,sBAAkB;IACrB,GAAG,yBAAqB;CACzB,CAAA;AAEY,QAAA,WAAW,GAAG,CAAC,GAAG,sBAAmB,CAAC,CAAA;AAEtC,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE;QACf,GAAG,qBAAiB;QACpB,GAAG,qBAAkB;QACrB,GAAG,sBAAmB;QACtB,GAAG,oBAAiB;QACpB,GAAG,6BAAyB;QAC5B,GAAG,0BAAsB;QACzB,GAAG,gBAAa;QAChB,GAAG,uBAAmB;QACtB,GAAG,oBAAwB;QAC3B,GAAG,0BAAsB;QACzB,GAAG,4BAAwB;KAC5B;CACF,CAAA;AAED,yDAAuD;AAA9C,0GAAA,WAAW,OAAA;AACpB,2EAAqE;AAA5D,wHAAA,gBAAgB,OAAA","sourcesContent":["import { entities as ConnectionEntities, resolvers as ConnectionResolvers } from './connection'\nimport { entities as ConnectorEntities, resolvers as ConnectorResolvers } from './connector'\nimport {\n entities as ScenarioEntities,\n resolvers as ScenarioResolvers,\n subscribers as ScenarioSubscribers\n} from './scenario'\nimport { entities as ScenarioInstanceEntities, resolvers as ScenarioInstanceResolvers } from './scenario-instance'\nimport { entities as ScenarioQueueEntities, resolvers as ScenarioQueueResolvers } from './scenario-queue'\nimport { entities as StepEntities, resolvers as StepResolvers } from './step'\nimport { entities as TaskTypeEntities, resolvers as TaskTypeResolvers } from './task-type'\nimport { entities as PayloadLogEntities, resolvers as PayloadLogResolvers } from './payload-log'\nimport { entities as StateRegisterEntities, resolvers as StateRegisterResolvers } from './state-register'\nimport { resolvers as IntegrationAnalysisQuery } from './analysis'\nimport { resolvers as DomainAttributeResolvers } from './domain-attribute'\n\nexport * from './property-spec'\nexport * from './task-type/task-type-type'\nexport * from './connector/connector-type'\nexport * from './connection/connection'\nexport * from './connection/connection-type'\nexport * from './scenario/scenario'\nexport * from './scenario/scenario-history'\nexport * from './scenario/scenario-version-type'\nexport * from './scenario-instance/scenario-instance-type'\nexport * from './scenario-queue/scenario-queue-type'\nexport * from './step/step-type'\nexport * from './scenario-flow/scenario-flow'\nexport * from './payload-log/payload-log'\nexport * from './state-register/state-register'\n\nexport const entities = [\n ...TaskTypeEntities,\n ...ConnectorEntities,\n ...ConnectionEntities,\n ...ScenarioEntities,\n ...ScenarioInstanceEntities,\n ...ScenarioQueueEntities,\n ...StepEntities,\n ...PayloadLogEntities,\n ...StateRegisterEntities\n]\n\nexport const subscribers = [...ScenarioSubscribers]\n\nexport const schema = {\n resolverClasses: [\n ...TaskTypeResolvers,\n ...ConnectorResolvers,\n ...ConnectionResolvers,\n ...ScenarioResolvers,\n ...ScenarioInstanceResolvers,\n ...ScenarioQueueResolvers,\n ...StepResolvers,\n ...PayloadLogResolvers,\n ...IntegrationAnalysisQuery,\n ...StateRegisterResolvers,\n ...DomainAttributeResolvers\n ]\n}\n\nexport { PayloadType } from './payload-log/payload-log'\nexport { createPayloadLog } from './payload-log/payload-log-mutation'\n"]}
@@ -0,0 +1,22 @@
1
+ import { InsertEvent, UpdateEvent } from 'typeorm';
2
+ import { HistoryEntitySubscriber } from '@operato/typeorm-history';
3
+ import { Scenario } from './scenario';
4
+ import { ScenarioHistory } from './scenario-history';
5
+ /**
6
+ * 시나리오 릴리즈(배포) 스냅샷 서브스크라이버.
7
+ *
8
+ * board-service 의 BoardHistoryEntitySubscriber 와 동형:
9
+ * - Scenario 저장 시 publishState === 'released' 인 경우에만 ScenarioHistory 스냅샷 생성.
10
+ * - draft 편집 저장은 히스토리를 남기지 않는다(= 배포 시에만 버전 부여).
11
+ *
12
+ * steps 는 Scenario 의 일반 컬럼이라 base.createHistoryEntity(manager.create) 가 자동 복사한다.
13
+ * comment 는 Scenario 컬럼이 아니므로 releaseScenario 가 넣어준 entity.__releaseComment 로부터 주입한다.
14
+ */
15
+ export declare class ScenarioHistoryEntitySubscriber extends HistoryEntitySubscriber<Scenario, ScenarioHistory> {
16
+ get entity(): typeof Scenario;
17
+ get historyEntity(): typeof ScenarioHistory;
18
+ beforeInsertHistory(history: ScenarioHistory, entity: Scenario): ScenarioHistory;
19
+ beforeUpdateHistory(history: ScenarioHistory, entity: Scenario): ScenarioHistory;
20
+ afterInsert(event: InsertEvent<Scenario>): Promise<void>;
21
+ afterUpdate(event: UpdateEvent<Scenario>): Promise<void>;
22
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ScenarioHistoryEntitySubscriber = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const typeorm_1 = require("typeorm");
6
+ const typeorm_history_1 = require("@operato/typeorm-history");
7
+ const scenario_1 = require("./scenario");
8
+ const scenario_history_1 = require("./scenario-history");
9
+ /**
10
+ * 시나리오 릴리즈(배포) 스냅샷 서브스크라이버.
11
+ *
12
+ * board-service 의 BoardHistoryEntitySubscriber 와 동형:
13
+ * - Scenario 저장 시 publishState === 'released' 인 경우에만 ScenarioHistory 스냅샷 생성.
14
+ * - draft 편집 저장은 히스토리를 남기지 않는다(= 배포 시에만 버전 부여).
15
+ *
16
+ * steps 는 Scenario 의 일반 컬럼이라 base.createHistoryEntity(manager.create) 가 자동 복사한다.
17
+ * comment 는 Scenario 컬럼이 아니므로 releaseScenario 가 넣어준 entity.__releaseComment 로부터 주입한다.
18
+ */
19
+ let ScenarioHistoryEntitySubscriber = class ScenarioHistoryEntitySubscriber extends typeorm_history_1.HistoryEntitySubscriber {
20
+ get entity() {
21
+ return scenario_1.Scenario;
22
+ }
23
+ get historyEntity() {
24
+ return scenario_history_1.ScenarioHistory;
25
+ }
26
+ beforeInsertHistory(history, entity) {
27
+ history.comment = entity.__releaseComment ?? null;
28
+ return history;
29
+ }
30
+ beforeUpdateHistory(history, entity) {
31
+ history.comment = entity.__releaseComment ?? null;
32
+ return history;
33
+ }
34
+ async afterInsert(event) {
35
+ if (event.entity?.publishState === 'released') {
36
+ await super.afterInsert(event);
37
+ }
38
+ }
39
+ async afterUpdate(event) {
40
+ if (event.entity?.publishState === 'released') {
41
+ await super.afterUpdate(event);
42
+ }
43
+ }
44
+ };
45
+ exports.ScenarioHistoryEntitySubscriber = ScenarioHistoryEntitySubscriber;
46
+ exports.ScenarioHistoryEntitySubscriber = ScenarioHistoryEntitySubscriber = tslib_1.__decorate([
47
+ (0, typeorm_1.EventSubscriber)()
48
+ ], ScenarioHistoryEntitySubscriber);
49
+ //# sourceMappingURL=event-subscriber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-subscriber.js","sourceRoot":"","sources":["../../../server/service/scenario/event-subscriber.ts"],"names":[],"mappings":";;;;AAAA,qCAAmE;AAEnE,8DAAkE;AAElE,yCAAqC;AACrC,yDAAoD;AAEpD;;;;;;;;;GASG;AAEI,IAAM,+BAA+B,GAArC,MAAM,+BAAgC,SAAQ,yCAAkD;IACrG,IAAW,MAAM;QACf,OAAO,mBAAQ,CAAA;IACjB,CAAC;IAED,IAAW,aAAa;QACtB,OAAO,kCAAe,CAAA;IACxB,CAAC;IAEM,mBAAmB,CAAC,OAAwB,EAAE,MAAgB;QACnE,OAAO,CAAC,OAAO,GAAI,MAAc,CAAC,gBAAgB,IAAI,IAAI,CAAA;QAC1D,OAAO,OAAO,CAAA;IAChB,CAAC;IAEM,mBAAmB,CAAC,OAAwB,EAAE,MAAgB;QACnE,OAAO,CAAC,OAAO,GAAI,MAAc,CAAC,gBAAgB,IAAI,IAAI,CAAA;QAC1D,OAAO,OAAO,CAAA;IAChB,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,KAA4B;QACnD,IAAK,KAAK,CAAC,MAAc,EAAE,YAAY,KAAK,UAAU,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC,WAAW,CAAC,KAAY,CAAC,CAAA;QACvC,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,KAA4B;QACnD,IAAK,KAAK,CAAC,MAAc,EAAE,YAAY,KAAK,UAAU,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC,WAAW,CAAC,KAAY,CAAC,CAAA;QACvC,CAAC;IACH,CAAC;CACF,CAAA;AA9BY,0EAA+B;0CAA/B,+BAA+B;IAD3C,IAAA,yBAAe,GAAE;GACL,+BAA+B,CA8B3C","sourcesContent":["import { EventSubscriber, InsertEvent, UpdateEvent } from 'typeorm'\n\nimport { HistoryEntitySubscriber } from '@operato/typeorm-history'\n\nimport { Scenario } from './scenario'\nimport { ScenarioHistory } from './scenario-history'\n\n/**\n * 시나리오 릴리즈(배포) 스냅샷 서브스크라이버.\n *\n * board-service 의 BoardHistoryEntitySubscriber 와 동형:\n * - Scenario 저장 시 publishState === 'released' 인 경우에만 ScenarioHistory 스냅샷 생성.\n * - draft 편집 저장은 히스토리를 남기지 않는다(= 배포 시에만 버전 부여).\n *\n * steps 는 Scenario 의 일반 컬럼이라 base.createHistoryEntity(manager.create) 가 자동 복사한다.\n * comment 는 Scenario 컬럼이 아니므로 releaseScenario 가 넣어준 entity.__releaseComment 로부터 주입한다.\n */\n@EventSubscriber()\nexport class ScenarioHistoryEntitySubscriber extends HistoryEntitySubscriber<Scenario, ScenarioHistory> {\n public get entity() {\n return Scenario\n }\n\n public get historyEntity() {\n return ScenarioHistory\n }\n\n public beforeInsertHistory(history: ScenarioHistory, entity: Scenario): ScenarioHistory {\n history.comment = (entity as any).__releaseComment ?? null\n return history\n }\n\n public beforeUpdateHistory(history: ScenarioHistory, entity: Scenario): ScenarioHistory {\n history.comment = (entity as any).__releaseComment ?? null\n return history\n }\n\n public async afterInsert(event: InsertEvent<Scenario>): Promise<void> {\n if ((event.entity as any)?.publishState === 'released') {\n await super.afterInsert(event as any)\n }\n }\n\n public async afterUpdate(event: UpdateEvent<Scenario>): Promise<void> {\n if ((event.entity as any)?.publishState === 'released') {\n await super.afterUpdate(event as any)\n }\n }\n}\n"]}
@@ -1,5 +1,9 @@
1
1
  import { Scenario } from './scenario';
2
+ import { ScenarioHistory } from './scenario-history';
2
3
  import { ScenarioQuery } from './scenario-query';
3
4
  import { ScenarioMutation } from './scenario-mutation';
4
- export declare const entities: (typeof Scenario)[];
5
- export declare const resolvers: (typeof ScenarioQuery | typeof ScenarioMutation)[];
5
+ import { ScenarioVersionQuery } from './scenario-version-query';
6
+ import { ScenarioHistoryEntitySubscriber } from './event-subscriber';
7
+ export declare const entities: (typeof Scenario | typeof ScenarioHistory)[];
8
+ export declare const resolvers: (typeof ScenarioQuery | typeof ScenarioMutation | typeof ScenarioVersionQuery)[];
9
+ export declare const subscribers: (typeof ScenarioHistoryEntitySubscriber)[];
@@ -1,9 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolvers = exports.entities = void 0;
3
+ exports.subscribers = exports.resolvers = exports.entities = void 0;
4
4
  const scenario_1 = require("./scenario");
5
+ const scenario_history_1 = require("./scenario-history");
5
6
  const scenario_query_1 = require("./scenario-query");
6
7
  const scenario_mutation_1 = require("./scenario-mutation");
7
- exports.entities = [scenario_1.Scenario];
8
- exports.resolvers = [scenario_query_1.ScenarioQuery, scenario_mutation_1.ScenarioMutation];
8
+ const scenario_version_query_1 = require("./scenario-version-query");
9
+ const event_subscriber_1 = require("./event-subscriber");
10
+ exports.entities = [scenario_1.Scenario, scenario_history_1.ScenarioHistory];
11
+ exports.resolvers = [scenario_query_1.ScenarioQuery, scenario_mutation_1.ScenarioMutation, scenario_version_query_1.ScenarioVersionQuery];
12
+ exports.subscribers = [event_subscriber_1.ScenarioHistoryEntitySubscriber];
9
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/scenario/index.ts"],"names":[],"mappings":";;;AAAA,yCAAqC;AACrC,qDAAgD;AAChD,2DAAsD;AAEzC,QAAA,QAAQ,GAAG,CAAC,mBAAQ,CAAC,CAAA;AACrB,QAAA,SAAS,GAAG,CAAC,8BAAa,EAAE,oCAAgB,CAAC,CAAA","sourcesContent":["import { Scenario } from './scenario'\nimport { ScenarioQuery } from './scenario-query'\nimport { ScenarioMutation } from './scenario-mutation'\n\nexport const entities = [Scenario]\nexport const resolvers = [ScenarioQuery, ScenarioMutation]\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/scenario/index.ts"],"names":[],"mappings":";;;AAAA,yCAAqC;AACrC,yDAAoD;AACpD,qDAAgD;AAChD,2DAAsD;AACtD,qEAA+D;AAC/D,yDAAoE;AAEvD,QAAA,QAAQ,GAAG,CAAC,mBAAQ,EAAE,kCAAe,CAAC,CAAA;AACtC,QAAA,SAAS,GAAG,CAAC,8BAAa,EAAE,oCAAgB,EAAE,6CAAoB,CAAC,CAAA;AACnE,QAAA,WAAW,GAAG,CAAC,kDAA+B,CAAC,CAAA","sourcesContent":["import { Scenario } from './scenario'\nimport { ScenarioHistory } from './scenario-history'\nimport { ScenarioQuery } from './scenario-query'\nimport { ScenarioMutation } from './scenario-mutation'\nimport { ScenarioVersionQuery } from './scenario-version-query'\nimport { ScenarioHistoryEntitySubscriber } from './event-subscriber'\n\nexport const entities = [Scenario, ScenarioHistory]\nexport const resolvers = [ScenarioQuery, ScenarioMutation, ScenarioVersionQuery]\nexport const subscribers = [ScenarioHistoryEntitySubscriber]\n"]}
@@ -0,0 +1,43 @@
1
+ import { EntityManager } from 'typeorm';
2
+ import { Step } from '../step/step-type';
3
+ import { Scenario } from './scenario';
4
+ import { ScenarioHistory } from './scenario-history';
5
+ /**
6
+ * 시나리오의 **draft(작업본)** 스텝을 반환한다.
7
+ *
8
+ * [하위 호환 규칙]
9
+ * - scenario.steps (JSON 컬럼) 가 채워져 있으면 그것을 사용.
10
+ * - 없으면(=아직 이관되지 않은 기존 시나리오) 레거시 Step 테이블에서 sequence 순으로 읽는다.
11
+ *
12
+ * 저장 경로는 항상 scenario.steps(JSON) 에 기록하므로, 최초 편집/릴리즈 시점에 자연 이관된다.
13
+ */
14
+ export declare function resolveScenarioSteps(scenario: Scenario, manager?: EntityManager): Promise<Step[]>;
15
+ /**
16
+ * 시나리오 실행/분석에 사용할 스텝을 반환한다. **기본은 released(배포본)**.
17
+ *
18
+ * [운영 정렬 규칙]
19
+ * - mode='released'(기본): 최신 릴리즈 스냅샷(ScenarioHistory 최대 version)의 steps 를 사용.
20
+ * 릴리즈된 버전이 없으면 draft(resolveScenarioSteps) 로 폴백.
21
+ * - mode='draft': 항상 draft(resolveScenarioSteps). 디버깅 실행 등.
22
+ */
23
+ export declare function resolveRunnableSteps(scenario: Scenario, options?: {
24
+ mode?: 'released' | 'draft';
25
+ manager?: EntityManager;
26
+ }): Promise<Step[]>;
27
+ /**
28
+ * [전환기 dual-write] 레거시 Step 테이블을 주어진 steps 로 동기화한다.
29
+ *
30
+ * Scenario.steps(JSON) 이 정본이지만, 신/구 바이너리 교체 실행(롤백) 시 구버전 코드가 Step 테이블을
31
+ * 읽어도 동작하도록 당분간 Step 테이블에도 최신 스텝(보통 draft)을 함께 보관한다.
32
+ * JSON step 의 id 를 Step PK 로 재사용해 식별자 일관성을 유지한다.
33
+ *
34
+ * 이 함수는 향후 Step 테이블 완전 제거 시 함께 제거될 임시 코드다.
35
+ */
36
+ export declare function syncLegacyStepTable(scenario: Scenario, steps: any[], ctx: {
37
+ domain: any;
38
+ user: any;
39
+ }, manager?: EntityManager): Promise<void>;
40
+ /**
41
+ * 시나리오의 최신 릴리즈 스냅샷(최대 version) 을 반환. 없으면 undefined.
42
+ */
43
+ export declare function getLatestReleasedHistory(scenario: Scenario, manager?: EntityManager): Promise<ScenarioHistory | undefined>;
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveScenarioSteps = resolveScenarioSteps;
4
+ exports.resolveRunnableSteps = resolveRunnableSteps;
5
+ exports.syncLegacyStepTable = syncLegacyStepTable;
6
+ exports.getLatestReleasedHistory = getLatestReleasedHistory;
7
+ const tslib_1 = require("tslib");
8
+ const orderBy_1 = tslib_1.__importDefault(require("lodash/orderBy"));
9
+ const shell_1 = require("@things-factory/shell");
10
+ const step_type_1 = require("../step/step-type");
11
+ const scenario_history_1 = require("./scenario-history");
12
+ /**
13
+ * 시나리오의 **draft(작업본)** 스텝을 반환한다.
14
+ *
15
+ * [하위 호환 규칙]
16
+ * - scenario.steps (JSON 컬럼) 가 채워져 있으면 그것을 사용.
17
+ * - 없으면(=아직 이관되지 않은 기존 시나리오) 레거시 Step 테이블에서 sequence 순으로 읽는다.
18
+ *
19
+ * 저장 경로는 항상 scenario.steps(JSON) 에 기록하므로, 최초 편집/릴리즈 시점에 자연 이관된다.
20
+ */
21
+ async function resolveScenarioSteps(scenario, manager) {
22
+ if (Array.isArray(scenario?.steps)) {
23
+ return scenario.steps;
24
+ }
25
+ if (!scenario?.id) {
26
+ return [];
27
+ }
28
+ const stepRepo = (0, shell_1.getRepository)(step_type_1.Step, manager);
29
+ const legacySteps = await stepRepo.find({ where: { scenario: { id: scenario.id } } });
30
+ return (0, orderBy_1.default)(legacySteps || [], step => step.sequence);
31
+ }
32
+ /**
33
+ * 시나리오 실행/분석에 사용할 스텝을 반환한다. **기본은 released(배포본)**.
34
+ *
35
+ * [운영 정렬 규칙]
36
+ * - mode='released'(기본): 최신 릴리즈 스냅샷(ScenarioHistory 최대 version)의 steps 를 사용.
37
+ * 릴리즈된 버전이 없으면 draft(resolveScenarioSteps) 로 폴백.
38
+ * - mode='draft': 항상 draft(resolveScenarioSteps). 디버깅 실행 등.
39
+ */
40
+ async function resolveRunnableSteps(scenario, options) {
41
+ const mode = options?.mode || 'released';
42
+ const manager = options?.manager;
43
+ if (mode === 'draft') {
44
+ return await resolveScenarioSteps(scenario, manager);
45
+ }
46
+ const published = await getLatestReleasedHistory(scenario, manager);
47
+ if (published && Array.isArray(published.steps)) {
48
+ return published.steps;
49
+ }
50
+ // 릴리즈된 버전 없음 → draft 폴백
51
+ return await resolveScenarioSteps(scenario, manager);
52
+ }
53
+ /**
54
+ * [전환기 dual-write] 레거시 Step 테이블을 주어진 steps 로 동기화한다.
55
+ *
56
+ * Scenario.steps(JSON) 이 정본이지만, 신/구 바이너리 교체 실행(롤백) 시 구버전 코드가 Step 테이블을
57
+ * 읽어도 동작하도록 당분간 Step 테이블에도 최신 스텝(보통 draft)을 함께 보관한다.
58
+ * JSON step 의 id 를 Step PK 로 재사용해 식별자 일관성을 유지한다.
59
+ *
60
+ * 이 함수는 향후 Step 테이블 완전 제거 시 함께 제거될 임시 코드다.
61
+ */
62
+ async function syncLegacyStepTable(scenario, steps, ctx, manager) {
63
+ if (!scenario?.id) {
64
+ return;
65
+ }
66
+ const stepRepo = (0, shell_1.getRepository)(step_type_1.Step, manager);
67
+ await stepRepo.delete({ domain: { id: ctx.domain?.id }, scenario: { id: scenario.id } });
68
+ if (!Array.isArray(steps) || steps.length === 0) {
69
+ return;
70
+ }
71
+ await stepRepo.save(steps.map((step, i) => ({
72
+ id: step.id,
73
+ name: step.name,
74
+ description: step.description,
75
+ sequence: step.sequence ?? i,
76
+ task: step.task,
77
+ skip: step.skip,
78
+ log: step.log,
79
+ connection: step.connection,
80
+ params: step.params,
81
+ result: step.result,
82
+ scenario: { id: scenario.id },
83
+ domain: ctx.domain,
84
+ creator: ctx.user,
85
+ updater: ctx.user
86
+ })));
87
+ }
88
+ /**
89
+ * 시나리오의 최신 릴리즈 스냅샷(최대 version) 을 반환. 없으면 undefined.
90
+ */
91
+ async function getLatestReleasedHistory(scenario, manager) {
92
+ if (!scenario?.id) {
93
+ return undefined;
94
+ }
95
+ const historyRepo = (0, shell_1.getRepository)(scenario_history_1.ScenarioHistory, manager);
96
+ return ((await historyRepo.findOne({
97
+ where: { originalId: scenario.id },
98
+ order: { version: 'DESC' }
99
+ })) || undefined);
100
+ }
101
+ //# sourceMappingURL=resolve-steps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-steps.js","sourceRoot":"","sources":["../../../server/service/scenario/resolve-steps.ts"],"names":[],"mappings":";;AAkBA,oDAYC;AAUD,oDAkBC;AAWD,kDAmCC;AAKD,4DAeC;;AA3HD,qEAAoC;AAEpC,iDAAqD;AAErD,iDAAwC;AAExC,yDAAoD;AAEpD;;;;;;;;GAQG;AACI,KAAK,UAAU,oBAAoB,CAAC,QAAkB,EAAE,OAAuB;IACpF,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,QAAQ,CAAC,KAAK,CAAA;IACvB,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC;QAClB,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,QAAQ,GAAG,IAAA,qBAAa,EAAC,gBAAI,EAAE,OAAO,CAAC,CAAA;IAC7C,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;IACrF,OAAO,IAAA,iBAAO,EAAC,WAAW,IAAI,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;AAC1D,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,oBAAoB,CACxC,QAAkB,EAClB,OAAkE;IAElE,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,UAAU,CAAA;IACxC,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,CAAA;IAEhC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,MAAM,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IACtD,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IACnE,IAAI,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,SAAS,CAAC,KAAK,CAAA;IACxB,CAAC;IAED,wBAAwB;IACxB,OAAO,MAAM,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;AACtD,CAAC;AAED;;;;;;;;GAQG;AACI,KAAK,UAAU,mBAAmB,CACvC,QAAkB,EAClB,KAAY,EACZ,GAA+B,EAC/B,OAAuB;IAEvB,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC;QAClB,OAAM;IACR,CAAC;IAED,MAAM,QAAQ,GAAG,IAAA,qBAAa,EAAC,gBAAI,EAAE,OAAO,CAAC,CAAA;IAC7C,MAAM,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;IAExF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAM;IACR,CAAC;IAED,MAAM,QAAQ,CAAC,IAAI,CACjB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACtB,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,CAAC;QAC5B,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,QAAQ,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE;QAC7B,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,GAAG,CAAC,IAAI;QACjB,OAAO,EAAE,GAAG,CAAC,IAAI;KAClB,CAAC,CAAC,CACJ,CAAA;AACH,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,wBAAwB,CAC5C,QAAkB,EAClB,OAAuB;IAEvB,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC;QAClB,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,WAAW,GAAG,IAAA,qBAAa,EAAC,kCAAe,EAAE,OAAO,CAAC,CAAA;IAC3D,OAAO,CACL,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC;QACzB,KAAK,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE;QAClC,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;KAC3B,CAAC,CAAC,IAAI,SAAS,CACjB,CAAA;AACH,CAAC","sourcesContent":["import { EntityManager } from 'typeorm'\nimport orderBy from 'lodash/orderBy'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { Step } from '../step/step-type'\nimport { Scenario } from './scenario'\nimport { ScenarioHistory } from './scenario-history'\n\n/**\n * 시나리오의 **draft(작업본)** 스텝을 반환한다.\n *\n * [하위 호환 규칙]\n * - scenario.steps (JSON 컬럼) 가 채워져 있으면 그것을 사용.\n * - 없으면(=아직 이관되지 않은 기존 시나리오) 레거시 Step 테이블에서 sequence 순으로 읽는다.\n *\n * 저장 경로는 항상 scenario.steps(JSON) 에 기록하므로, 최초 편집/릴리즈 시점에 자연 이관된다.\n */\nexport async function resolveScenarioSteps(scenario: Scenario, manager?: EntityManager): Promise<Step[]> {\n if (Array.isArray(scenario?.steps)) {\n return scenario.steps\n }\n\n if (!scenario?.id) {\n return []\n }\n\n const stepRepo = getRepository(Step, manager)\n const legacySteps = await stepRepo.find({ where: { scenario: { id: scenario.id } } })\n return orderBy(legacySteps || [], step => step.sequence)\n}\n\n/**\n * 시나리오 실행/분석에 사용할 스텝을 반환한다. **기본은 released(배포본)**.\n *\n * [운영 정렬 규칙]\n * - mode='released'(기본): 최신 릴리즈 스냅샷(ScenarioHistory 최대 version)의 steps 를 사용.\n * 릴리즈된 버전이 없으면 draft(resolveScenarioSteps) 로 폴백.\n * - mode='draft': 항상 draft(resolveScenarioSteps). 디버깅 실행 등.\n */\nexport async function resolveRunnableSteps(\n scenario: Scenario,\n options?: { mode?: 'released' | 'draft'; manager?: EntityManager }\n): Promise<Step[]> {\n const mode = options?.mode || 'released'\n const manager = options?.manager\n\n if (mode === 'draft') {\n return await resolveScenarioSteps(scenario, manager)\n }\n\n const published = await getLatestReleasedHistory(scenario, manager)\n if (published && Array.isArray(published.steps)) {\n return published.steps\n }\n\n // 릴리즈된 버전 없음 → draft 폴백\n return await resolveScenarioSteps(scenario, manager)\n}\n\n/**\n * [전환기 dual-write] 레거시 Step 테이블을 주어진 steps 로 동기화한다.\n *\n * Scenario.steps(JSON) 이 정본이지만, 신/구 바이너리 교체 실행(롤백) 시 구버전 코드가 Step 테이블을\n * 읽어도 동작하도록 당분간 Step 테이블에도 최신 스텝(보통 draft)을 함께 보관한다.\n * JSON step 의 id 를 Step PK 로 재사용해 식별자 일관성을 유지한다.\n *\n * 이 함수는 향후 Step 테이블 완전 제거 시 함께 제거될 임시 코드다.\n */\nexport async function syncLegacyStepTable(\n scenario: Scenario,\n steps: any[],\n ctx: { domain: any; user: any },\n manager?: EntityManager\n): Promise<void> {\n if (!scenario?.id) {\n return\n }\n\n const stepRepo = getRepository(Step, manager)\n await stepRepo.delete({ domain: { id: ctx.domain?.id }, scenario: { id: scenario.id } })\n\n if (!Array.isArray(steps) || steps.length === 0) {\n return\n }\n\n await stepRepo.save(\n steps.map((step, i) => ({\n id: step.id,\n name: step.name,\n description: step.description,\n sequence: step.sequence ?? i,\n task: step.task,\n skip: step.skip,\n log: step.log,\n connection: step.connection,\n params: step.params,\n result: step.result,\n scenario: { id: scenario.id },\n domain: ctx.domain,\n creator: ctx.user,\n updater: ctx.user\n }))\n )\n}\n\n/**\n * 시나리오의 최신 릴리즈 스냅샷(최대 version) 을 반환. 없으면 undefined.\n */\nexport async function getLatestReleasedHistory(\n scenario: Scenario,\n manager?: EntityManager\n): Promise<ScenarioHistory | undefined> {\n if (!scenario?.id) {\n return undefined\n }\n\n const historyRepo = getRepository(ScenarioHistory, manager)\n return (\n (await historyRepo.findOne({\n where: { originalId: scenario.id },\n order: { version: 'DESC' }\n })) || undefined\n )\n}\n"]}
@@ -0,0 +1,44 @@
1
+ import { HistoryActionType } from '@operato/typeorm-history';
2
+ import { PrivilegeObject, Role, User } from '@things-factory/auth-base';
3
+ import { Domain } from '@things-factory/shell';
4
+ import { Step } from '../step/step-type';
5
+ /**
6
+ * 시나리오의 릴리즈(배포) 시점 불변 스냅샷.
7
+ *
8
+ * board-service 의 BoardHistory 와 동형(@operato/typeorm-history).
9
+ * ScenarioHistoryEntitySubscriber 가 Scenario 저장 시 publishState === 'released' 인 경우에만
10
+ * 이 레코드를 생성한다. steps 는 Scenario 의 일반 컬럼이므로 자동 복사된다(별도 직렬화 불필요).
11
+ */
12
+ export declare class ScenarioHistory {
13
+ readonly id: string;
14
+ version?: number;
15
+ domain?: Domain;
16
+ domainId?: string;
17
+ name?: string;
18
+ description?: string;
19
+ type?: string;
20
+ schedule?: string;
21
+ timezone?: string;
22
+ ttl?: number;
23
+ iteration?: string;
24
+ privilege?: PrivilegeObject;
25
+ role?: Role;
26
+ roleId?: string;
27
+ /**
28
+ * 이 버전 스냅샷의 스텝 배열(JSON). Scenario.steps 와 동일 형식이라 서브스크라이버가 자동 복사한다.
29
+ */
30
+ steps?: Step[];
31
+ /**
32
+ * 릴리즈 시 남기는 코멘트(변경 요약 등). Scenario 의 컬럼이 아니므로
33
+ * ScenarioHistoryEntitySubscriber 가 entity.__releaseComment 로부터 주입한다.
34
+ */
35
+ comment?: string;
36
+ createdAt?: Date;
37
+ updatedAt?: Date;
38
+ creator?: User;
39
+ creatorId?: string;
40
+ updater?: User;
41
+ updaterId?: string;
42
+ originalId: string;
43
+ action: HistoryActionType;
44
+ }