@gadmin2n/schematics 0.0.142 → 0.0.144

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 (140) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +5 -23
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/lib/page-helpers.ts +4 -2
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/page-manage.ts +36 -1
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/agenda.seed.ts +14 -14
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/bootstrap.ts +18 -13
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/canvas.seed.ts +14 -14
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/index.ts +1 -1
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +67 -404
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow.seed.ts +16 -40
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflows.ts +12 -124
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/app.module.ts +3 -0
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/index.ts +0 -21
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.controller.ts +3 -10
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/codeRuntime.module.ts +1 -2
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-callback.controller.spec.ts +48 -0
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-callback.controller.ts +96 -0
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.controller.spec.ts +1 -59
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.controller.ts +8 -43
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.dto.ts +0 -23
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction.service.ts +2 -0
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-wait.handler.ts +2 -0
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/externalInteraction.module.ts +7 -3
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/workflow-callback-url.controller.ts +2 -2
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/workflow-callback-url.service.spec.ts +18 -123
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/workflow-callback-url.service.ts +4 -0
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.controller.ts +3 -10
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/httpRequest.module.ts +1 -2
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.controller.ts +0 -10
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.dto.ts +12 -4
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.errors.ts +1 -1
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.external-decision.spec.ts +42 -209
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.service.ts +108 -225
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/humanApproval.module.ts +0 -2
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.controller.ts +27 -22
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.dto.ts +9 -1
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/runtime-token.guard.spec.ts +30 -0
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/runtime-token.guard.ts +8 -15
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/index.ts +0 -2
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/runtime-connectivity-probe.service.spec.ts +14 -0
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/runtime-connectivity-probe.service.ts +37 -0
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.controller.spec.ts +41 -0
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.controller.ts +53 -0
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.module.ts +7 -2
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/workflow-runtime-health.controller.ts +21 -0
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.spec.ts +2 -2
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-callable.spec.ts +16 -88
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-callable.ts +23 -59
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +125 -39
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.ts +95 -28
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-handle-validator.ts +0 -20
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-http-response.spec.ts +23 -26
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-http-response.ts +6 -52
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +2 -2
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +24 -0
  55. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +26 -21
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/widget-catalog.service.spec.ts +0 -1
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/widget-catalog.service.ts +0 -1
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowRuntimeConfig/workflow-runtime-config.service.spec.ts +32 -0
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowRuntimeConfig/workflow-runtime-config.service.ts +41 -0
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowRuntimeConfig/workflowRuntimeConfig.module.ts +10 -0
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/server/tsconfig.build.json +10 -1
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/README.md +16 -12
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/web/package.json +1 -1
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/PageHeader.tsx +1 -1
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/agentPanel/inspectorActions.ts +19 -19
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/contexts/color-mode/index.tsx +1 -1
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/header.tsx +15 -11
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +0 -6
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/AddDataModal.tsx +3 -3
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/AddPageModal.tsx +1 -1
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/DeleteDataConfirm.tsx +1 -1
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/EditDataModal.tsx +1 -1
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +1 -0
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +85 -95
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +85 -95
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agenda/index.tsx +2 -2
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/list.tsx +21 -2
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/game/list.tsx +21 -2
  79. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/human-approval/inbox.tsx +14 -66
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/list.tsx +4 -4
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/list.tsx +3 -3
  82. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/list.tsx +3 -3
  83. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CustomNode.test.tsx +29 -0
  84. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CustomNode.tsx +4 -2
  85. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/EnhancedFlowRenderer.tsx +4 -6
  86. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ExecutionStatusNode.test.tsx +3 -0
  87. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ExecutionStatusNode.tsx +3 -1
  88. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/FlowRenderer.tsx +4 -6
  89. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NewNodeDefaults.test.tsx +23 -92
  90. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeOutputSummary.tsx +200 -0
  91. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.test.tsx +61 -136
  92. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.tsx +96 -195
  93. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeTypeBadge.tsx +36 -0
  94. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/CreateNodeInstanceModal.tsx +5 -10
  95. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/NodeInstanceForm.tsx +47 -22
  96. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/create.tsx +7 -5
  97. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/edit.tsx +8 -6
  98. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-config.css +35 -0
  99. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/default-widgets.tsx +1 -6
  100. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.tsx +1 -4
  101. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CodeConfigEditor.tsx +1 -1
  102. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalRequestConfigEditor.tsx +1 -1
  103. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalWaitConfigEditor.tsx +82 -259
  104. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HttpRequestConfigEditor.tsx +1 -2
  105. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.test.tsx +7 -6
  106. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.tsx +77 -71
  107. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.test.tsx +10 -57
  108. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.tsx +8 -273
  109. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.test.tsx +54 -0
  110. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.tsx +110 -20
  111. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/newNodeConfig.ts +4 -34
  112. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveOutputs.test.ts +3 -10
  113. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveOutputs.ts +2 -37
  114. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/list.tsx +26 -2
  115. package/package.json +1 -1
  116. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/approvalChannel/approval-channel.controller.ts +0 -89
  117. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/approvalChannel/approval-channel.dto.ts +0 -68
  118. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/approvalChannel/approval-channel.service.spec.ts +0 -177
  119. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/approvalChannel/approval-channel.service.ts +0 -283
  120. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/approvalChannel/approvalChannel.module.ts +0 -10
  121. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/approval-channels/ApprovalChannelModal.test.tsx +0 -84
  122. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/approval-channels/ApprovalChannelModal.tsx +0 -141
  123. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/approval-channels/approval-channel.types.ts +0 -16
  124. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/approval-channels/index.tsx +0 -210
  125. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApprovalRequestTriggerConfigEditor.tsx +0 -39
  126. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubmitApprovalResultConfigEditor.tsx +0 -104
  127. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubmitExternalResultConfigEditor.tsx +0 -98
  128. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/{Components → components}/AssignRolesModal.tsx +0 -0
  129. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/{Components → components}/CreatePageModal.tsx +0 -0
  130. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/{Components → components}/EditPageModal.tsx +0 -0
  131. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/{Components → components}/PageDetailDrawer.tsx +0 -0
  132. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/{Components → components}/PageFormModal.tsx +0 -0
  133. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/{Components → components}/CreateModal.tsx +0 -0
  134. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/{Components → components}/EditModal.tsx +0 -0
  135. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/{Components → components}/ResourceDetailDrawer.tsx +0 -0
  136. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/{Components → components}/modal.tsx +0 -0
  137. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/{Components → components}/CreateModal.tsx +0 -0
  138. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/{Components → components}/EditModal.tsx +0 -0
  139. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/{Components → components}/RoleDetailDrawer.tsx +0 -0
  140. /package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/{Components → components}/modal.tsx +0 -0
@@ -2,6 +2,7 @@
2
2
  import { ConfigService } from '@nestjs/config';
3
3
  import { Test, TestingModule } from '@nestjs/testing';
4
4
  import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
5
+ import { RuntimeConnectivityProbeService } from './runtime-connectivity-probe.service';
5
6
  import { TemporalTenantConfigController } from './temporalTenantConfig.controller';
6
7
  import { TemporalTenantConfigService } from './temporalTenantConfig.service';
7
8
 
@@ -18,6 +19,10 @@ const mockConfigService = {
18
19
  get: jest.fn(),
19
20
  };
20
21
 
22
+ const mockProbes = {
23
+ create: jest.fn().mockReturnValue('signed-probe'),
24
+ };
25
+
21
26
  // Mock Logger
22
27
  const mockLogger = {
23
28
  child: jest.fn().mockReturnThis(),
@@ -42,6 +47,7 @@ describe('TemporalTenantConfigController', () => {
42
47
  useValue: mockTemporalTenantConfigService,
43
48
  },
44
49
  { provide: ConfigService, useValue: mockConfigService },
50
+ { provide: RuntimeConnectivityProbeService, useValue: mockProbes },
45
51
  { provide: WINSTON_MODULE_PROVIDER, useValue: mockLogger },
46
52
  ],
47
53
  })
@@ -63,6 +69,41 @@ describe('TemporalTenantConfigController', () => {
63
69
  expect(controller).toBeDefined();
64
70
  });
65
71
 
72
+ it('tests the current connection values without persisting them', async () => {
73
+ global.fetch = jest.fn().mockResolvedValue({
74
+ ok: true,
75
+ json: jest.fn().mockResolvedValue({
76
+ ok: true,
77
+ checks: [{ key: 'database', ok: true }],
78
+ }),
79
+ });
80
+
81
+ const result = await controller.testConnection({
82
+ adminUrl: 'http://temporal.example:8081/',
83
+ adminToken: 'admin-token',
84
+ namespace: 'gadmin-test',
85
+ dbUrl: 'postgresql://user:pass@gadmin-db:5432/gadmin_demo',
86
+ displayName: 'Gadmin Test',
87
+ runtimeBaseUrl: 'http://gadmin-server:8000/api',
88
+ runtimeToken: '0123456789abcdef0123456789abcdef',
89
+ } as any);
90
+
91
+ expect(global.fetch).toHaveBeenCalledWith(
92
+ 'http://temporal.example:8081/admin/test-connection',
93
+ expect.objectContaining({
94
+ method: 'POST',
95
+ body: JSON.stringify({
96
+ dbUrl: 'postgresql://user:pass@gadmin-db:5432/gadmin_demo',
97
+ runtimeBaseUrl: 'http://gadmin-server:8000/api',
98
+ runtimeProbeToken: 'signed-probe',
99
+ }),
100
+ }),
101
+ );
102
+ expect(result).toMatchObject({ ok: true });
103
+ expect(mockTemporalTenantConfigService.createOne).not.toHaveBeenCalled();
104
+ expect(mockTemporalTenantConfigService.updateUnique).not.toHaveBeenCalled();
105
+ });
106
+
66
107
  it('registers and persists the tenant runtime connection', async () => {
67
108
  global.fetch = jest.fn().mockResolvedValue({
68
109
  ok: true,
@@ -10,6 +10,7 @@ import {
10
10
  UserType,
11
11
  } from '@gadmin2n/nest-common';
12
12
  import {
13
+ BadGatewayException,
13
14
  BadRequestException,
14
15
  Body,
15
16
  Controller,
@@ -44,6 +45,7 @@ import {
44
45
  } from '../../generated/temporalTenantConfig/dto/temporalTenantConfig-types.dto';
45
46
  import { UpdateTemporalTenantConfigDto } from '../../generated/temporalTenantConfig/dto/update-temporalTenantConfig.dto';
46
47
  import { TemporalTenantConfigEntity } from '../../generated/temporalTenantConfig/entities/temporalTenantConfig.entity';
48
+ import { RuntimeConnectivityProbeService } from './runtime-connectivity-probe.service';
47
49
  import { TemporalTenantConfigService } from './temporalTenantConfig.service';
48
50
 
49
51
  import { ConfigService } from '@nestjs/config';
@@ -55,10 +57,54 @@ import { FileInterceptor } from '@nestjs/platform-express';
55
57
  export class TemporalTenantConfigController {
56
58
  constructor(
57
59
  private readonly temporalTenantConfigService: TemporalTenantConfigService,
60
+ private readonly probes: RuntimeConnectivityProbeService,
58
61
  private readonly config: ConfigService,
59
62
  @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
60
63
  ) {}
61
64
 
65
+ @Post('testConnection')
66
+ @UseRoles({
67
+ resource: 'temporalTenantConfig',
68
+ action: 'create',
69
+ possession: 'any',
70
+ })
71
+ async testConnection(@Body() body: CreateTemporalTenantConfigDto) {
72
+ assertRuntimeToken(body.runtimeToken);
73
+ let response: Response;
74
+ const adminUrl = body.adminUrl.replace(/\/+$/, '');
75
+
76
+ try {
77
+ response = await fetch(`${adminUrl}/admin/test-connection`, {
78
+ method: 'POST',
79
+ headers: {
80
+ 'Content-Type': 'application/json',
81
+ 'X-Admin-Token': body.adminToken,
82
+ },
83
+ body: JSON.stringify({
84
+ dbUrl: body.dbUrl,
85
+ runtimeBaseUrl: body.runtimeBaseUrl,
86
+ runtimeProbeToken: this.probes.create(),
87
+ }),
88
+ signal: AbortSignal.timeout(15_000),
89
+ });
90
+ } catch (error: any) {
91
+ throw new BadGatewayException(
92
+ `无法连接 Temporal 管理 API: ${String(error?.message ?? error)}`,
93
+ );
94
+ }
95
+
96
+ const result = await response.json().catch(async () => ({
97
+ error: await response.text().catch(() => ''),
98
+ }));
99
+ if (!response.ok) {
100
+ throw new BadGatewayException({
101
+ message: `Temporal 管理 API 连通性测试失败 (${response.status})`,
102
+ detail: result,
103
+ });
104
+ }
105
+ return result;
106
+ }
107
+
62
108
  @Post('createOne')
63
109
  @UseRoles({
64
110
  resource: 'temporalTenantConfig',
@@ -71,6 +117,7 @@ export class TemporalTenantConfigController {
71
117
  @ACAttrFilter() acAttrFilter,
72
118
  @Req() request: Request & { user: UserType },
73
119
  ) {
120
+ assertRuntimeToken(body.runtimeToken);
74
121
  body.creator = request.user.username;
75
122
 
76
123
  // 先调 shared temporal admin API(原子:失败则不写 DB)
@@ -163,6 +210,7 @@ export class TemporalTenantConfigController {
163
210
  @Body() body: UpdateTemporalTenantConfigDto,
164
211
  @ACAttrFilter() acAttrFilter,
165
212
  ) {
213
+ if (body.runtimeToken !== undefined) assertRuntimeToken(body.runtimeToken);
166
214
  const existing = await this.temporalTenantConfigService.findUnique(id, {
167
215
  adminUrl: true,
168
216
  adminToken: true,
@@ -247,3 +295,8 @@ export class TemporalTenantConfigController {
247
295
  };
248
296
  }
249
297
  }
298
+
299
+ function assertRuntimeToken(value: string | undefined): void {
300
+ if (!value || value.length < 32)
301
+ throw new BadRequestException('Runtime Token 至少需要 32 个字符');
302
+ }
@@ -1,10 +1,15 @@
1
1
  import { Module } from '@nestjs/common';
2
+ import { RuntimeConnectivityProbeService } from './runtime-connectivity-probe.service';
2
3
  import { TemporalTenantConfigController } from './temporalTenantConfig.controller';
3
4
  import { TemporalTenantConfigService } from './temporalTenantConfig.service';
5
+ import { WorkflowRuntimeHealthController } from './workflow-runtime-health.controller';
4
6
 
5
7
  @Module({
6
- controllers: [TemporalTenantConfigController],
7
- providers: [TemporalTenantConfigService],
8
+ controllers: [
9
+ TemporalTenantConfigController,
10
+ WorkflowRuntimeHealthController,
11
+ ],
12
+ providers: [TemporalTenantConfigService, RuntimeConnectivityProbeService],
8
13
  exports: [TemporalTenantConfigService],
9
14
  })
10
15
  export class TemporalTenantConfigModule {}
@@ -0,0 +1,21 @@
1
+ import {
2
+ Controller,
3
+ Get,
4
+ Headers,
5
+ UnauthorizedException,
6
+ } from '@nestjs/common';
7
+ import { AllowUnauthorizedRequest } from '../../lib/auth.guard';
8
+ import { RuntimeConnectivityProbeService } from './runtime-connectivity-probe.service';
9
+
10
+ @Controller('workflow-runtime/health')
11
+ export class WorkflowRuntimeHealthController {
12
+ constructor(private readonly probes: RuntimeConnectivityProbeService) {}
13
+
14
+ @Get('ready')
15
+ @AllowUnauthorizedRequest()
16
+ readiness(@Headers('x-workflow-runtime-probe') probe = '') {
17
+ if (!this.probes.verify(probe))
18
+ throw new UnauthorizedException('Invalid workflow runtime probe');
19
+ return { status: 'ok' };
20
+ }
21
+ }
@@ -5,7 +5,7 @@ describe('validateDslGraph', () => {
5
5
  nodes: [
6
6
  { id: 't1', type: 'manual_trigger' },
7
7
  { id: 'n1', type: 'http_request' },
8
- { id: 'n2', type: 'send_notification' },
8
+ { id: 'n2', type: 'code' },
9
9
  ],
10
10
  edges: [
11
11
  { source: 't1', target: 'n1' },
@@ -25,7 +25,7 @@ describe('validateDslGraph', () => {
25
25
  { id: 't1', type: 'manual_trigger' },
26
26
  { id: 'a', type: 'http_request' },
27
27
  { id: 'b', type: 'http_request' },
28
- { id: 'c', type: 'send_notification' },
28
+ { id: 'c', type: 'code' },
29
29
  ],
30
30
  edges: [
31
31
  { source: 't1', target: 'a' },
@@ -15,27 +15,18 @@ const validDsl = {
15
15
  },
16
16
  },
17
17
  { id: 'http', type: 'http_request', config: {} },
18
- {
19
- id: 'return',
20
- type: 'return_result',
21
- config: {
22
- resultType: 'APPROVAL_SUBJECTS',
23
- sourceMode: 'INPUT',
24
- },
25
- },
18
+ { id: 'return', type: 'return_result', config: {} },
26
19
  ],
27
20
  edges: [{ source: 'http', target: 'return', kind: 'FLOW' }],
28
21
  };
29
22
 
30
23
  describe('callable Workflow contract', () => {
31
- it('describes declared inputs and normalized result type', () => {
24
+ it('describes declared inputs and a returning workflow without a result type', () => {
32
25
  expect(describeCallableWorkflow(validDsl)).toEqual({
33
26
  mode: 'RETURN',
34
27
  inputParameters: [
35
28
  { key: 'employeeId', label: '员工 ID', required: true },
36
29
  ],
37
- resultType: 'APPROVAL_SUBJECTS',
38
- sourceMode: 'INPUT',
39
30
  });
40
31
  });
41
32
 
@@ -51,18 +42,13 @@ describe('callable Workflow contract', () => {
51
42
  ).toThrow('不能同时包含其他触发器');
52
43
  });
53
44
 
54
- it('describes a callable Workflow without a return node as one-way', () => {
55
- expect(
45
+ it('rejects a callable Workflow without a return node', () => {
46
+ expect(() =>
56
47
  validateCallableWorkflow({
57
48
  ...validDsl,
58
49
  nodes: validDsl.nodes.filter((node) => node.type !== 'return_result'),
59
50
  }),
60
- ).toEqual({
61
- mode: 'ONE_WAY',
62
- inputParameters: [
63
- { key: 'employeeId', label: '员工 ID', required: true },
64
- ],
65
- });
51
+ ).toThrow('必须且只能包含一个“返回调用”节点');
66
52
  });
67
53
 
68
54
  it('rejects more than one return node', () => {
@@ -71,88 +57,30 @@ describe('callable Workflow contract', () => {
71
57
  ...validDsl,
72
58
  nodes: [
73
59
  ...validDsl.nodes,
74
- {
75
- id: 'return-2',
76
- type: 'return_result',
77
- config: {
78
- resultType: 'APPROVAL_SUBJECTS',
79
- sourceMode: 'WORKFLOW',
80
- path: 'approvers',
81
- },
82
- },
60
+ { id: 'return-2', type: 'return_result', config: {} },
83
61
  ],
84
62
  }),
85
- ).toThrow('最多包含一个“返回结果”节点');
86
- });
87
-
88
- it('accepts returning the previous pipeline result as input', () => {
89
- expect(
90
- validateCallableWorkflow({
91
- ...validDsl,
92
- nodes: validDsl.nodes.map((node) =>
93
- node.type === 'return_result'
94
- ? {
95
- ...node,
96
- config: {
97
- resultType: 'APPROVAL_SUBJECTS',
98
- sourceMode: 'INPUT',
99
- },
100
- }
101
- : node,
102
- ),
103
- edges: [{ source: 'http', target: 'return', kind: 'FLOW' }],
104
- }),
105
- ).toEqual({
106
- mode: 'RETURN',
107
- inputParameters: [
108
- { key: 'employeeId', label: '员工 ID', required: true },
109
- ],
110
- resultType: 'APPROVAL_SUBJECTS',
111
- sourceMode: 'INPUT',
112
- });
63
+ ).toThrow('必须且只能包含一个“返回调用”节点');
113
64
  });
114
65
 
115
- it('rejects an input return node that is not connected', () => {
66
+ it('requires exactly one previous node', () => {
116
67
  expect(() =>
117
68
  validateCallableWorkflow({
118
69
  ...validDsl,
119
- nodes: validDsl.nodes.map((node) =>
120
- node.type === 'return_result'
121
- ? {
122
- ...node,
123
- config: {
124
- resultType: 'APPROVAL_SUBJECTS',
125
- sourceMode: 'INPUT',
126
- },
127
- }
128
- : node,
129
- ),
130
70
  edges: [],
131
71
  }),
132
- ).toThrow('返回结果前需要连接一个节点');
72
+ ).toThrow('“返回调用”前需要连接一个节点');
133
73
  });
134
74
 
135
- it('accepts returning a field from Workflow data', () => {
136
- expect(
75
+ it('requires the return node to be terminal', () => {
76
+ expect(() =>
137
77
  validateCallableWorkflow({
138
78
  ...validDsl,
139
- nodes: validDsl.nodes.map((node) =>
140
- node.type === 'return_result'
141
- ? {
142
- ...node,
143
- config: {
144
- resultType: 'APPROVAL_SUBJECTS',
145
- sourceMode: 'WORKFLOW',
146
- path: 'approvers',
147
- },
148
- }
149
- : node,
150
- ),
79
+ edges: [
80
+ ...validDsl.edges,
81
+ { source: 'return', target: 'after', kind: 'FLOW' },
82
+ ],
151
83
  }),
152
- ).toMatchObject({
153
- resultType: 'APPROVAL_SUBJECTS',
154
- sourceMode: 'WORKFLOW',
155
- path: 'approvers',
156
- });
84
+ ).toThrow('“返回调用”必须是流程最后一个节点');
157
85
  });
158
86
  });
@@ -1,32 +1,14 @@
1
- export type CallableResultType = 'APPROVAL_SUBJECTS';
2
-
3
1
  export interface CallableInputParameter {
4
2
  key: string;
5
3
  label?: string;
6
4
  required?: boolean;
7
5
  }
8
6
 
9
- interface CallableWorkflowBaseDescriptor {
7
+ export interface CallableWorkflowDescriptor {
10
8
  inputParameters: CallableInputParameter[];
11
- }
12
-
13
- export interface OneWayCallableWorkflowDescriptor
14
- extends CallableWorkflowBaseDescriptor {
15
- mode: 'ONE_WAY';
16
- }
17
-
18
- export interface ReturningCallableWorkflowDescriptor
19
- extends CallableWorkflowBaseDescriptor {
20
9
  mode: 'RETURN';
21
- resultType: CallableResultType;
22
- sourceMode: 'INPUT' | 'WORKFLOW';
23
- path?: string;
24
10
  }
25
11
 
26
- export type CallableWorkflowDescriptor =
27
- | OneWayCallableWorkflowDescriptor
28
- | ReturningCallableWorkflowDescriptor;
29
-
30
12
  type DslLike = {
31
13
  nodes?: Array<{
32
14
  id?: unknown;
@@ -49,11 +31,11 @@ export function describeCallableWorkflow(
49
31
  return validateCallableWorkflow(dsl);
50
32
  }
51
33
 
52
- export function describeApprovalChannelInputs(
34
+ export function describeReturningWorkflowInputs(
53
35
  dsl: unknown,
54
36
  ): CallableInputParameter[] {
55
37
  const descriptor = describeCallableWorkflow(dsl);
56
- if (!descriptor || descriptor.mode !== 'ONE_WAY') return [];
38
+ if (!descriptor) return [];
57
39
  return descriptor.inputParameters;
58
40
  }
59
41
 
@@ -79,48 +61,30 @@ export function validateCallableWorkflow(
79
61
  const inputParameters = normalizeInputParameters(
80
62
  triggerConfig.inputParameters,
81
63
  );
82
- if (returns.length === 0)
83
- return {
84
- mode: 'ONE_WAY',
85
- inputParameters,
86
- };
87
- if (returns.length > 1)
88
- throw new Error('可调用 Workflow 最多包含一个“返回结果”节点');
89
-
90
- const returnConfig = asObject(returns[0].config);
91
- if (returnConfig.resultType !== 'APPROVAL_SUBJECTS')
92
- throw new Error('返回结果类型必须是审批人');
93
-
94
- if (returnConfig.sourceMode === 'INPUT') {
95
- const returnNodeId = returns[0].id;
96
- const predecessors = (asDsl(dsl).edges ?? []).filter(
97
- (edge) =>
98
- edge.target === returnNodeId &&
99
- (!edge.kind || edge.kind === 'FLOW') &&
100
- !edge.pairId,
101
- );
102
- if (predecessors.length !== 1)
103
- throw new Error('返回结果前需要连接一个节点');
104
-
105
- return {
106
- mode: 'RETURN',
107
- inputParameters,
108
- resultType: 'APPROVAL_SUBJECTS',
109
- sourceMode: 'INPUT',
110
- };
111
- }
112
-
113
- if (returnConfig.sourceMode !== 'WORKFLOW')
114
- throw new Error('返回结果来源必须是上一个节点或 Workflow 数据');
115
- if (typeof returnConfig.path !== 'string' || !returnConfig.path.trim())
116
- throw new Error('返回 Workflow 数据时必须填写字段路径');
64
+ if (returns.length !== 1)
65
+ throw new Error('可调用 Workflow 必须且只能包含一个“返回调用”节点');
66
+
67
+ const returnNodeId = returns[0].id;
68
+ const predecessors = (asDsl(dsl).edges ?? []).filter(
69
+ (edge) =>
70
+ edge.target === returnNodeId &&
71
+ (!edge.kind || edge.kind === 'FLOW') &&
72
+ !edge.pairId,
73
+ );
74
+ if (predecessors.length !== 1)
75
+ throw new Error('“返回调用”前需要连接一个节点');
76
+ const successors = (asDsl(dsl).edges ?? []).filter(
77
+ (edge) =>
78
+ edge.source === returnNodeId &&
79
+ (!edge.kind || edge.kind === 'FLOW') &&
80
+ !edge.pairId,
81
+ );
82
+ if (successors.length > 0)
83
+ throw new Error('“返回调用”必须是流程最后一个节点');
117
84
 
118
85
  return {
119
86
  mode: 'RETURN',
120
87
  inputParameters,
121
- resultType: 'APPROVAL_SUBJECTS',
122
- sourceMode: 'WORKFLOW',
123
- path: returnConfig.path.trim(),
124
88
  };
125
89
  }
126
90