@solidxai/core 0.1.15 → 0.1.16-beta.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 (171) hide show
  1. package/CHANGELOG.md +642 -0
  2. package/dist/commands/run-tests.command.d.ts +3 -1
  3. package/dist/commands/run-tests.command.d.ts.map +1 -1
  4. package/dist/commands/run-tests.command.js +6 -2
  5. package/dist/commands/run-tests.command.js.map +1 -1
  6. package/dist/controllers/test-run.controller.d.ts +12 -0
  7. package/dist/controllers/test-run.controller.d.ts.map +1 -0
  8. package/dist/controllers/test-run.controller.js +54 -0
  9. package/dist/controllers/test-run.controller.js.map +1 -0
  10. package/dist/dtos/test-run-request.dto.d.ts +35 -0
  11. package/dist/dtos/test-run-request.dto.d.ts.map +1 -0
  12. package/dist/dtos/test-run-request.dto.js +120 -0
  13. package/dist/dtos/test-run-request.dto.js.map +1 -0
  14. package/dist/guards/access-token.guard.d.ts +5 -1
  15. package/dist/guards/access-token.guard.d.ts.map +1 -1
  16. package/dist/guards/access-token.guard.js +20 -1
  17. package/dist/guards/access-token.guard.js.map +1 -1
  18. package/dist/index.d.ts +12 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +17 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/interfaces/active-user-data.interface.d.ts +1 -0
  23. package/dist/interfaces/active-user-data.interface.d.ts.map +1 -1
  24. package/dist/interfaces/active-user-data.interface.js.map +1 -1
  25. package/dist/jobs/database/test-run-queue-options-database.d.ts +8 -0
  26. package/dist/jobs/database/test-run-queue-options-database.d.ts.map +1 -0
  27. package/dist/jobs/database/test-run-queue-options-database.js +10 -0
  28. package/dist/jobs/database/test-run-queue-options-database.js.map +1 -0
  29. package/dist/jobs/database/test-run-queue-publisher-database.service.d.ts +12 -0
  30. package/dist/jobs/database/test-run-queue-publisher-database.service.d.ts.map +1 -0
  31. package/dist/jobs/database/test-run-queue-publisher-database.service.js +39 -0
  32. package/dist/jobs/database/test-run-queue-publisher-database.service.js.map +1 -0
  33. package/dist/jobs/database/test-run-queue-subscriber-database.service.d.ts +26 -0
  34. package/dist/jobs/database/test-run-queue-subscriber-database.service.d.ts.map +1 -0
  35. package/dist/jobs/database/test-run-queue-subscriber-database.service.js +120 -0
  36. package/dist/jobs/database/test-run-queue-subscriber-database.service.js.map +1 -0
  37. package/dist/seeders/seed-data/solid-core-metadata.json +3 -1
  38. package/dist/services/access-token-denylist.service.d.ts +16 -0
  39. package/dist/services/access-token-denylist.service.d.ts.map +1 -0
  40. package/dist/services/access-token-denylist.service.js +74 -0
  41. package/dist/services/access-token-denylist.service.js.map +1 -0
  42. package/dist/services/authentication.service.d.ts +9 -1
  43. package/dist/services/authentication.service.d.ts.map +1 -1
  44. package/dist/services/authentication.service.js +39 -4
  45. package/dist/services/authentication.service.js.map +1 -1
  46. package/dist/services/import-transaction.service.d.ts +1 -1
  47. package/dist/services/import-transaction.service.d.ts.map +1 -1
  48. package/dist/services/import-transaction.service.js +13 -23
  49. package/dist/services/import-transaction.service.js.map +1 -1
  50. package/dist/services/settings/default-settings-provider.service.d.ts +20 -0
  51. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  52. package/dist/services/settings/default-settings-provider.service.js +11 -0
  53. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  54. package/dist/services/workflow-secret.service.d.ts +3 -0
  55. package/dist/services/workflow-secret.service.d.ts.map +1 -1
  56. package/dist/services/workflow-secret.service.js +25 -0
  57. package/dist/services/workflow-secret.service.js.map +1 -1
  58. package/dist/solid-core.module.d.ts.map +1 -1
  59. package/dist/solid-core.module.js +9 -0
  60. package/dist/solid-core.module.js.map +1 -1
  61. package/dist/testing/adapters/ui/browser-provisioner.d.ts +5 -0
  62. package/dist/testing/adapters/ui/browser-provisioner.d.ts.map +1 -0
  63. package/dist/testing/adapters/ui/browser-provisioner.js +102 -0
  64. package/dist/testing/adapters/ui/browser-provisioner.js.map +1 -0
  65. package/dist/testing/adapters/ui/playwright-adapter.d.ts +40 -1
  66. package/dist/testing/adapters/ui/playwright-adapter.d.ts.map +1 -1
  67. package/dist/testing/adapters/ui/playwright-adapter.js +185 -3
  68. package/dist/testing/adapters/ui/playwright-adapter.js.map +1 -1
  69. package/dist/testing/adapters/ui/ui.types.d.ts +6 -0
  70. package/dist/testing/adapters/ui/ui.types.d.ts.map +1 -1
  71. package/dist/testing/adapters/ui/ui.types.js.map +1 -1
  72. package/dist/testing/contracts/runtime-context.types.d.ts +2 -0
  73. package/dist/testing/contracts/runtime-context.types.d.ts.map +1 -1
  74. package/dist/testing/contracts/runtime-context.types.js.map +1 -1
  75. package/dist/testing/core/interpolation.d.ts +1 -0
  76. package/dist/testing/core/interpolation.d.ts.map +1 -1
  77. package/dist/testing/core/interpolation.js +28 -68
  78. package/dist/testing/core/interpolation.js.map +1 -1
  79. package/dist/testing/core/path-resolution.spec.d.ts +2 -0
  80. package/dist/testing/core/path-resolution.spec.d.ts.map +1 -0
  81. package/dist/testing/core/path-resolution.spec.js +106 -0
  82. package/dist/testing/core/path-resolution.spec.js.map +1 -0
  83. package/dist/testing/core/path-segments.d.ts +2 -0
  84. package/dist/testing/core/path-segments.d.ts.map +1 -0
  85. package/dist/testing/core/path-segments.js +70 -0
  86. package/dist/testing/core/path-segments.js.map +1 -0
  87. package/dist/testing/core/resource-store.d.ts.map +1 -1
  88. package/dist/testing/core/resource-store.js +5 -2
  89. package/dist/testing/core/resource-store.js.map +1 -1
  90. package/dist/testing/core/testing-engine.d.ts.map +1 -1
  91. package/dist/testing/core/testing-engine.js +16 -0
  92. package/dist/testing/core/testing-engine.js.map +1 -1
  93. package/dist/testing/reporter/artifact-sink.d.ts +14 -0
  94. package/dist/testing/reporter/artifact-sink.d.ts.map +1 -0
  95. package/dist/testing/reporter/artifact-sink.js +3 -0
  96. package/dist/testing/reporter/artifact-sink.js.map +1 -0
  97. package/dist/testing/reporter/console-reporter.d.ts.map +1 -1
  98. package/dist/testing/reporter/console-reporter.js +7 -0
  99. package/dist/testing/reporter/console-reporter.js.map +1 -1
  100. package/dist/testing/reporter/file-service-artifact-sink.d.ts +22 -0
  101. package/dist/testing/reporter/file-service-artifact-sink.d.ts.map +1 -0
  102. package/dist/testing/reporter/file-service-artifact-sink.js +31 -0
  103. package/dist/testing/reporter/file-service-artifact-sink.js.map +1 -0
  104. package/dist/testing/reporter/lifecycle-events.types.d.ts +67 -0
  105. package/dist/testing/reporter/lifecycle-events.types.d.ts.map +1 -0
  106. package/dist/testing/reporter/lifecycle-events.types.js +3 -0
  107. package/dist/testing/reporter/lifecycle-events.types.js.map +1 -0
  108. package/dist/testing/reporter/lifecycle-webhook-reporter.d.ts +77 -0
  109. package/dist/testing/reporter/lifecycle-webhook-reporter.d.ts.map +1 -0
  110. package/dist/testing/reporter/lifecycle-webhook-reporter.js +275 -0
  111. package/dist/testing/reporter/lifecycle-webhook-reporter.js.map +1 -0
  112. package/dist/testing/reporter/progress-reporter.d.ts +3 -3
  113. package/dist/testing/reporter/progress-reporter.d.ts.map +1 -1
  114. package/dist/testing/reporter/progress-reporter.js.map +1 -1
  115. package/dist/testing/reporter/reporter.types.d.ts +13 -1
  116. package/dist/testing/reporter/reporter.types.d.ts.map +1 -1
  117. package/dist/testing/reporter/reporter.types.js.map +1 -1
  118. package/dist/testing/runner/read-scenarios-file.d.ts +9 -0
  119. package/dist/testing/runner/read-scenarios-file.d.ts.map +1 -0
  120. package/dist/testing/runner/read-scenarios-file.js +56 -0
  121. package/dist/testing/runner/read-scenarios-file.js.map +1 -0
  122. package/dist/testing/runner/run-from-metadata.d.ts +7 -2
  123. package/dist/testing/runner/run-from-metadata.d.ts.map +1 -1
  124. package/dist/testing/runner/run-from-metadata.js +57 -6
  125. package/dist/testing/runner/run-from-metadata.js.map +1 -1
  126. package/dist/testing/steps/ui/navigation.step.d.ts.map +1 -1
  127. package/dist/testing/steps/ui/navigation.step.js +12 -12
  128. package/dist/testing/steps/ui/navigation.step.js.map +1 -1
  129. package/package.json +1 -1
  130. package/postman/instant-logout.postman_collection.json +1493 -0
  131. package/src/commands/run-tests.command.ts +3 -0
  132. package/src/controllers/test-run.controller.ts +44 -0
  133. package/src/dtos/test-run-request.dto.ts +130 -0
  134. package/src/guards/access-token.guard.ts +48 -0
  135. package/src/index.ts +21 -1
  136. package/src/interfaces/active-user-data.interface.ts +8 -0
  137. package/src/jobs/database/test-run-queue-options-database.ts +9 -0
  138. package/src/jobs/database/test-run-queue-publisher-database.service.ts +24 -0
  139. package/src/jobs/database/test-run-queue-subscriber-database.service.ts +122 -0
  140. package/src/seeders/seed-data/solid-core-metadata.json +3 -1
  141. package/src/services/access-token-denylist.service.ts +145 -0
  142. package/src/services/authentication.service.ts +118 -2
  143. package/src/services/import-transaction.service.ts +19 -36
  144. package/src/services/settings/default-settings-provider.service.ts +12 -0
  145. package/src/services/workflow-secret.service.ts +61 -2
  146. package/src/solid-core.module.ts +11 -0
  147. package/src/testing/README.md +44 -1
  148. package/src/testing/adapters/ui/browser-provisioner.ts +115 -0
  149. package/src/testing/adapters/ui/playwright-adapter.ts +255 -5
  150. package/src/testing/adapters/ui/ui.types.ts +14 -0
  151. package/src/testing/contracts/runtime-context.types.ts +6 -0
  152. package/src/testing/core/interpolation.ts +39 -69
  153. package/src/testing/core/path-resolution.spec.ts +133 -0
  154. package/src/testing/core/path-segments.ts +81 -0
  155. package/src/testing/core/resource-store.ts +8 -2
  156. package/src/testing/core/testing-engine.ts +22 -0
  157. package/src/testing/reporter/artifact-sink.ts +16 -0
  158. package/src/testing/reporter/console-reporter.ts +9 -0
  159. package/src/testing/reporter/file-service-artifact-sink.ts +46 -0
  160. package/src/testing/reporter/lifecycle-events.types.ts +103 -0
  161. package/src/testing/reporter/lifecycle-webhook-reporter.ts +385 -0
  162. package/src/testing/reporter/progress-reporter.ts +3 -1
  163. package/src/testing/reporter/reporter.types.ts +10 -1
  164. package/src/testing/runner/read-scenarios-file.ts +44 -0
  165. package/src/testing/runner/run-from-metadata.ts +102 -9
  166. package/src/testing/steps/ui/navigation.step.ts +24 -20
  167. package/dist/services/access-token-storage.service.d.ts +0 -1
  168. package/dist/services/access-token-storage.service.d.ts.map +0 -1
  169. package/dist/services/access-token-storage.service.js +0 -1
  170. package/dist/services/access-token-storage.service.js.map +0 -1
  171. package/src/services/access-token-storage.service.ts +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"run-tests.command.d.ts","sourceRoot":"","sources":["../../src/commands/run-tests.command.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAEnE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AAOzF,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAG9D,UAAU,qBAAqB;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAIa,cAAe,SAAQ,aAAa;IAI7C,OAAO,CAAC,QAAQ,CAAC,2BAA2B;IAC5C,OAAO,CAAC,QAAQ,CAAC,cAAc;IAJjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;gBAGvC,2BAA2B,EAAE,2BAA2B,EACxD,cAAc,EAAE,cAAc;IAK3C,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoHhF,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAShC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASrC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASrC,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASzC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASlC,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAUrC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAUxC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASpC,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASnC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAUnC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAUrC,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAS/C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASnC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASjC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASjC,eAAe,IAAI,OAAO;CAG3B"}
1
+ {"version":3,"file":"run-tests.command.d.ts","sourceRoot":"","sources":["../../src/commands/run-tests.command.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAEnE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AAOzF,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAG7E,UAAU,qBAAqB;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAIa,cAAe,SAAQ,aAAa;IAI7C,OAAO,CAAC,QAAQ,CAAC,2BAA2B;IAC5C,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IALxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;gBAGvC,2BAA2B,EAAE,2BAA2B,EACxD,cAAc,EAAE,cAAc,EAC9B,qBAAqB,EAAE,qBAAqB;IAKzD,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqHhF,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAShC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASrC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASrC,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASzC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASlC,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAUrC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAUxC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASpC,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASnC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAUnC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAUrC,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAS/C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASnC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASjC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IASjC,eAAe,IAAI,OAAO;CAG3B"}
@@ -54,11 +54,13 @@ const webhook_reporter_1 = require("../testing/reporter/webhook-reporter");
54
54
  const run_from_metadata_1 = require("../testing/runner/run-from-metadata");
55
55
  const spec_registry_1 = require("../testing/core/spec-registry");
56
56
  const setting_service_1 = require("../services/setting.service");
57
+ const workflow_secret_service_1 = require("../services/workflow-secret.service");
57
58
  let TestRunCommand = TestRunCommand_1 = class TestRunCommand extends nest_commander_1.CommandRunner {
58
- constructor(moduleMetadataHelperService, settingService) {
59
+ constructor(moduleMetadataHelperService, settingService, workflowSecretService) {
59
60
  super();
60
61
  this.moduleMetadataHelperService = moduleMetadataHelperService;
61
62
  this.settingService = settingService;
63
+ this.workflowSecretService = workflowSecretService;
62
64
  this.logger = new common_1.Logger(TestRunCommand_1.name);
63
65
  }
64
66
  async run(passedParam, options) {
@@ -139,6 +141,7 @@ let TestRunCommand = TestRunCommand_1 = class TestRunCommand extends nest_comman
139
141
  retries: options?.retries,
140
142
  },
141
143
  options: { printApiLogs },
144
+ resolveSecrets: (keys) => this.workflowSecretService.resolveAvailable(keys),
142
145
  specs: specEntries.length
143
146
  ? (registry) => loadSpecRegistrations(specEntries, metadataPath, registry)
144
147
  : undefined,
@@ -383,7 +386,8 @@ exports.TestRunCommand = TestRunCommand = TestRunCommand_1 = __decorate([
383
386
  description: 'Run testing scenarios from module metadata.',
384
387
  }),
385
388
  __metadata("design:paramtypes", [module_metadata_helper_service_1.ModuleMetadataHelperService,
386
- setting_service_1.SettingService])
389
+ setting_service_1.SettingService,
390
+ workflow_secret_service_1.WorkflowSecretService])
387
391
  ], TestRunCommand);
388
392
  function splitCsv(value) {
389
393
  if (!value)
@@ -1 +1 @@
1
- {"version":3,"file":"run-tests.command.js","sourceRoot":"","sources":["../../src/commands/run-tests.command.ts"],"names":[],"mappings":"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","sourcesContent":["import { Logger } from '@nestjs/common';\nimport { SubCommand, CommandRunner, Option } from 'nest-commander';\nimport * as path from 'path';\nimport { ModuleMetadataHelperService } from 'src/helpers/module-metadata-helper.service';\nimport { ConsoleReporter } from 'src/testing/reporter/console-reporter';\nimport { ProgressReporter } from 'src/testing/reporter/progress-reporter';\nimport { WebhookReporter } from 'src/testing/reporter/webhook-reporter';\nimport { runFromMetadata } from 'src/testing/runner/run-from-metadata';\nimport type { TestingMetadata } from 'src/testing/contracts/testing-metadata.types';\nimport { SpecRegistry } from 'src/testing/core/spec-registry';\nimport { SettingService } from 'src/services/setting.service';\nimport type { SolidCoreSetting } from 'src/services/settings/default-settings-provider.service';\n\ninterface TestRunCommandOptions {\n module?: string;\n moduleName?: string;\n scenarioIds?: string;\n includeTags?: string;\n skipScenarioIds?: string;\n reporter?: string;\n apiBaseUrl?: string;\n uiBaseUrl?: string;\n headless?: boolean;\n uiTimeoutMs?: number;\n uiNavigationTimeoutMs?: number;\n timeoutMs?: number;\n retries?: number;\n listSpecs?: boolean;\n printApiLogs?: boolean;\n runName?: string;\n progress?: boolean;\n}\n\n@SubCommand({\n name: 'run',\n description: 'Run testing scenarios from module metadata.',\n})\nexport class TestRunCommand extends CommandRunner {\n private readonly logger = new Logger(TestRunCommand.name);\n\n constructor(\n private readonly moduleMetadataHelperService: ModuleMetadataHelperService,\n private readonly settingService: SettingService,\n ) {\n super();\n }\n\n async run(passedParam: string[], options?: TestRunCommandOptions): Promise<void> {\n try {\n const moduleName = options?.moduleName ?? options?.module ?? passedParam?.[0];\n if (!moduleName) {\n this.logger.error('Module name is required. Use --module or pass it as the first argument.');\n return;\n }\n\n const metadataPath = await this.moduleMetadataHelperService.getModuleMetadataFilePath(moduleName);\n if (!metadataPath) {\n this.logger.error(`Unable to resolve metadata path for module: ${moduleName}`);\n return;\n }\n\n const metadata = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(metadataPath);\n if (!metadata?.testing) {\n this.logger.error(`No testing configuration found in metadata: ${metadataPath}`);\n return;\n }\n\n const listSpecs = options?.listSpecs ?? false;\n const specEntries = Array.isArray(metadata.testing?.specs)\n ? metadata.testing.specs\n : [];\n\n if (listSpecs) {\n const registry = new SpecRegistry();\n if (specEntries.length) {\n loadSpecRegistrations(specEntries, metadataPath, registry);\n }\n printSpecList(registry.list());\n return;\n }\n if (!metadata?.testing?.scenarios || !Array.isArray(metadata.testing.scenarios)) {\n this.logger.error(`No testing.scenarios found in metadata: ${metadataPath}`);\n return;\n }\n\n const scenarioIds = splitCsv(options?.scenarioIds);\n const includeTags = splitCsv(options?.includeTags);\n const skipScenarioIds = splitCsv(options?.skipScenarioIds);\n\n const reporterName = options?.reporter ?? 'console';\n if (reporterName !== 'console') {\n this.logger.error(`Unsupported reporter: ${reporterName}. Use \"console\".`);\n return;\n }\n\n const apiBaseUrl = options?.apiBaseUrl ?? process.env.BASE_URL;\n const uiBaseUrl = options?.uiBaseUrl ?? process.env.FRONTEND_BASE_URL;\n const headless = options?.headless ?? true;\n const uiTimeoutMs =\n options?.uiTimeoutMs\n ?? toPositiveNumber(process.env.UI_TIMEOUT_MS)\n ?? toPositiveNumber(this.settingService.getConfigValue<SolidCoreSetting>('uiTestDefaultTimeoutMs'));\n const uiNavigationTimeoutMs =\n options?.uiNavigationTimeoutMs\n ?? toPositiveNumber(process.env.UI_NAVIGATION_TIMEOUT_MS)\n ?? toPositiveNumber(this.settingService.getConfigValue<SolidCoreSetting>('uiTestNavigationTimeoutMs'));\n const printApiLogs = options?.printApiLogs ?? false;\n\n const webhookUrl = process.env.SOLIDCTL_WEBHOOK_URL;\n const runName = options?.runName ?? `run-${Date.now()}`;\n const baseReporter = webhookUrl\n ? new WebhookReporter(webhookUrl, runName)\n : new ConsoleReporter();\n const reporter = options?.progress === false\n ? baseReporter\n : new ProgressReporter(baseReporter);\n\n try {\n await runFromMetadata({\n metadata: metadata as TestingMetadata,\n scenarioIds,\n includeTags,\n skipScenarioIds,\n reporter,\n api: apiBaseUrl ? { baseUrl: apiBaseUrl } : undefined,\n ui: {\n baseUrl: uiBaseUrl,\n headless,\n defaultTimeoutMs: uiTimeoutMs,\n navigationTimeoutMs: uiNavigationTimeoutMs,\n },\n defaults: {\n timeoutMs: options?.timeoutMs,\n retries: options?.retries,\n },\n options: { printApiLogs },\n specs: specEntries.length\n ? (registry) => loadSpecRegistrations(specEntries, metadataPath, registry)\n : undefined,\n });\n } catch (err: any) {\n this.logger.error('Run tests command failed');\n console.error('Run tests command failed');\n process.exitCode = 1;\n } finally {\n if (baseReporter instanceof WebhookReporter) {\n await baseReporter.flush(Number(process.exitCode ?? 0));\n }\n }\n return;\n } catch (err: any) {\n this.logger.error('Run tests command failed');\n console.error('Run tests command failed');\n process.exitCode = 1;\n return;\n }\n }\n\n @Option({\n flags: '-m, --module [module name]',\n description: 'Module name to load metadata from.',\n required: false,\n })\n parseModule(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--scenario-ids [ids]',\n description: 'Comma-separated list of scenario ids to run.',\n required: false,\n })\n parseScenarioIds(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--include-tags [tags]',\n description: 'Comma-separated list of tags; scenario must include all.',\n required: false,\n })\n parseIncludeTags(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--skip-scenario-ids [ids]',\n description: 'Comma-separated list of scenario ids to skip.',\n required: false,\n })\n parseSkipScenarioIds(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--reporter [name]',\n description: 'Reporter name (currently only \"console\").',\n required: false,\n })\n parseReporter(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--list-specs [true|false]',\n description: 'List registered test specs and exit.',\n required: false,\n })\n parseListSpecs(val?: string): boolean {\n if (val === undefined) return true;\n return val === 'false' ? false : true;\n }\n\n @Option({\n flags: '--print-api-logs [true|false]',\n description: 'Print full API request/response logs for api.request steps.',\n required: false,\n })\n parsePrintApiLogs(val?: string): boolean {\n if (val === undefined) return true;\n return val === 'false' ? false : true;\n }\n\n @Option({\n flags: '--api-base-url [url]',\n description: 'API base URL (defaults to process.env.BASE_URL).',\n required: false,\n })\n parseApiBaseUrl(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--ui-base-url [url]',\n description: 'UI base URL (defaults to process.env.FRONTEND_BASE_URL).',\n required: false,\n })\n parseUiBaseUrl(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--headless [true|false]',\n description: 'Run UI browser in headless mode (default: true).',\n required: false,\n })\n parseHeadless(val: string): boolean {\n return val === 'false' ? false : true;\n }\n\n @Option({\n flags: '--ui-timeout-ms [number]',\n description:\n 'Default timeout in ms for UI steps (waits, clicks, fills). Defaults to process.env.UI_TIMEOUT_MS, then the uiTestDefaultTimeoutMs setting, then 30000.',\n required: false,\n })\n parseUiTimeoutMs(val: string): number {\n return Number(val);\n }\n\n @Option({\n flags: '--ui-navigation-timeout-ms [number]',\n description:\n 'Default timeout in ms for ui.goto navigation. Defaults to process.env.UI_NAVIGATION_TIMEOUT_MS, then the uiTestNavigationTimeoutMs setting, then --ui-timeout-ms.',\n required: false,\n })\n parseUiNavigationTimeoutMs(val: string): number {\n return Number(val);\n }\n\n @Option({\n flags: '--timeout-ms [number]',\n description: 'Default scenario timeout in milliseconds.',\n required: false,\n })\n parseTimeoutMs(val: string): number {\n return Number(val);\n }\n\n @Option({\n flags: '--retries [number]',\n description: 'Default scenario retries.',\n required: false,\n })\n parseRetries(val: string): number {\n return Number(val);\n }\n\n @Option({\n flags: '--run-name [name]',\n description: 'Logical name for this test run (used by webhook reporter).',\n required: false,\n })\n parseRunName(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--no-progress',\n description: 'Disable the interactive test progress footer.',\n required: false,\n })\n parseNoProgress(): boolean {\n return false;\n }\n}\n\nfunction splitCsv(value?: string): string[] | undefined {\n if (!value) return undefined;\n const items = value\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean);\n return items.length ? items : undefined;\n}\n\n// Accepts unknown because settings come back already parsed as numbers, while env\n// vars arrive as strings.\nfunction toPositiveNumber(value?: unknown): number | undefined {\n if (value === null || value === undefined || value === '') return undefined;\n const parsed = Number(value);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n}\n\nfunction resolveSpecPath(entry: string, metadataPath: string): string {\n if (path.isAbsolute(entry)) {\n return entry;\n }\n if (entry.startsWith('.')) {\n return path.resolve(path.dirname(metadataPath), entry);\n }\n return path.resolve(process.cwd(), entry);\n}\n\nfunction loadSpecRegistrations(entries: string[], metadataPath: string, registry: SpecRegistry): void {\n for (const entry of entries) {\n const resolved = resolveSpecPath(entry, metadataPath);\n let mod: any;\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n mod = require(resolved);\n } catch (err: any) {\n const message = err?.message ?? String(err);\n throw new Error(\n `Failed to load test spec module \"${entry}\" resolved to \"${resolved}\": ${message}`,\n );\n }\n const register = mod?.registerTestSpecs ?? mod?.default ?? mod;\n if (typeof register !== 'function') {\n throw new Error(\n `Test spec module \"${entry}\" did not export a register function (expected \"registerTestSpecs\" or default export).`,\n );\n }\n register(registry);\n }\n}\nfunction printSpecList(specIds: string[]): void {\n if (!specIds.length) {\n console.log('No test specs registered.');\n return;\n }\n console.log('Registered test specs:');\n for (const id of specIds) {\n console.log(`- ${id}`);\n }\n}\n"]}
1
+ {"version":3,"file":"run-tests.command.js","sourceRoot":"","sources":["../../src/commands/run-tests.command.ts"],"names":[],"mappings":"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","sourcesContent":["import { Logger } from '@nestjs/common';\nimport { SubCommand, CommandRunner, Option } from 'nest-commander';\nimport * as path from 'path';\nimport { ModuleMetadataHelperService } from 'src/helpers/module-metadata-helper.service';\nimport { ConsoleReporter } from 'src/testing/reporter/console-reporter';\nimport { ProgressReporter } from 'src/testing/reporter/progress-reporter';\nimport { WebhookReporter } from 'src/testing/reporter/webhook-reporter';\nimport { runFromMetadata } from 'src/testing/runner/run-from-metadata';\nimport type { TestingMetadata } from 'src/testing/contracts/testing-metadata.types';\nimport { SpecRegistry } from 'src/testing/core/spec-registry';\nimport { SettingService } from 'src/services/setting.service';\nimport { WorkflowSecretService } from 'src/services/workflow-secret.service';\nimport type { SolidCoreSetting } from 'src/services/settings/default-settings-provider.service';\n\ninterface TestRunCommandOptions {\n module?: string;\n moduleName?: string;\n scenarioIds?: string;\n includeTags?: string;\n skipScenarioIds?: string;\n reporter?: string;\n apiBaseUrl?: string;\n uiBaseUrl?: string;\n headless?: boolean;\n uiTimeoutMs?: number;\n uiNavigationTimeoutMs?: number;\n timeoutMs?: number;\n retries?: number;\n listSpecs?: boolean;\n printApiLogs?: boolean;\n runName?: string;\n progress?: boolean;\n}\n\n@SubCommand({\n name: 'run',\n description: 'Run testing scenarios from module metadata.',\n})\nexport class TestRunCommand extends CommandRunner {\n private readonly logger = new Logger(TestRunCommand.name);\n\n constructor(\n private readonly moduleMetadataHelperService: ModuleMetadataHelperService,\n private readonly settingService: SettingService,\n private readonly workflowSecretService: WorkflowSecretService,\n ) {\n super();\n }\n\n async run(passedParam: string[], options?: TestRunCommandOptions): Promise<void> {\n try {\n const moduleName = options?.moduleName ?? options?.module ?? passedParam?.[0];\n if (!moduleName) {\n this.logger.error('Module name is required. Use --module or pass it as the first argument.');\n return;\n }\n\n const metadataPath = await this.moduleMetadataHelperService.getModuleMetadataFilePath(moduleName);\n if (!metadataPath) {\n this.logger.error(`Unable to resolve metadata path for module: ${moduleName}`);\n return;\n }\n\n const metadata = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(metadataPath);\n if (!metadata?.testing) {\n this.logger.error(`No testing configuration found in metadata: ${metadataPath}`);\n return;\n }\n\n const listSpecs = options?.listSpecs ?? false;\n const specEntries = Array.isArray(metadata.testing?.specs)\n ? metadata.testing.specs\n : [];\n\n if (listSpecs) {\n const registry = new SpecRegistry();\n if (specEntries.length) {\n loadSpecRegistrations(specEntries, metadataPath, registry);\n }\n printSpecList(registry.list());\n return;\n }\n if (!metadata?.testing?.scenarios || !Array.isArray(metadata.testing.scenarios)) {\n this.logger.error(`No testing.scenarios found in metadata: ${metadataPath}`);\n return;\n }\n\n const scenarioIds = splitCsv(options?.scenarioIds);\n const includeTags = splitCsv(options?.includeTags);\n const skipScenarioIds = splitCsv(options?.skipScenarioIds);\n\n const reporterName = options?.reporter ?? 'console';\n if (reporterName !== 'console') {\n this.logger.error(`Unsupported reporter: ${reporterName}. Use \"console\".`);\n return;\n }\n\n const apiBaseUrl = options?.apiBaseUrl ?? process.env.BASE_URL;\n const uiBaseUrl = options?.uiBaseUrl ?? process.env.FRONTEND_BASE_URL;\n const headless = options?.headless ?? true;\n const uiTimeoutMs =\n options?.uiTimeoutMs\n ?? toPositiveNumber(process.env.UI_TIMEOUT_MS)\n ?? toPositiveNumber(this.settingService.getConfigValue<SolidCoreSetting>('uiTestDefaultTimeoutMs'));\n const uiNavigationTimeoutMs =\n options?.uiNavigationTimeoutMs\n ?? toPositiveNumber(process.env.UI_NAVIGATION_TIMEOUT_MS)\n ?? toPositiveNumber(this.settingService.getConfigValue<SolidCoreSetting>('uiTestNavigationTimeoutMs'));\n const printApiLogs = options?.printApiLogs ?? false;\n\n const webhookUrl = process.env.SOLIDCTL_WEBHOOK_URL;\n const runName = options?.runName ?? `run-${Date.now()}`;\n const baseReporter = webhookUrl\n ? new WebhookReporter(webhookUrl, runName)\n : new ConsoleReporter();\n const reporter = options?.progress === false\n ? baseReporter\n : new ProgressReporter(baseReporter);\n\n try {\n await runFromMetadata({\n metadata: metadata as TestingMetadata,\n scenarioIds,\n includeTags,\n skipScenarioIds,\n reporter,\n api: apiBaseUrl ? { baseUrl: apiBaseUrl } : undefined,\n ui: {\n baseUrl: uiBaseUrl,\n headless,\n defaultTimeoutMs: uiTimeoutMs,\n navigationTimeoutMs: uiNavigationTimeoutMs,\n },\n defaults: {\n timeoutMs: options?.timeoutMs,\n retries: options?.retries,\n },\n options: { printApiLogs },\n resolveSecrets: (keys) => this.workflowSecretService.resolveAvailable(keys),\n specs: specEntries.length\n ? (registry) => loadSpecRegistrations(specEntries, metadataPath, registry)\n : undefined,\n });\n } catch (err: any) {\n this.logger.error('Run tests command failed');\n console.error('Run tests command failed');\n process.exitCode = 1;\n } finally {\n if (baseReporter instanceof WebhookReporter) {\n await baseReporter.flush(Number(process.exitCode ?? 0));\n }\n }\n return;\n } catch (err: any) {\n this.logger.error('Run tests command failed');\n console.error('Run tests command failed');\n process.exitCode = 1;\n return;\n }\n }\n\n @Option({\n flags: '-m, --module [module name]',\n description: 'Module name to load metadata from.',\n required: false,\n })\n parseModule(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--scenario-ids [ids]',\n description: 'Comma-separated list of scenario ids to run.',\n required: false,\n })\n parseScenarioIds(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--include-tags [tags]',\n description: 'Comma-separated list of tags; scenario must include all.',\n required: false,\n })\n parseIncludeTags(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--skip-scenario-ids [ids]',\n description: 'Comma-separated list of scenario ids to skip.',\n required: false,\n })\n parseSkipScenarioIds(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--reporter [name]',\n description: 'Reporter name (currently only \"console\").',\n required: false,\n })\n parseReporter(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--list-specs [true|false]',\n description: 'List registered test specs and exit.',\n required: false,\n })\n parseListSpecs(val?: string): boolean {\n if (val === undefined) return true;\n return val === 'false' ? false : true;\n }\n\n @Option({\n flags: '--print-api-logs [true|false]',\n description: 'Print full API request/response logs for api.request steps.',\n required: false,\n })\n parsePrintApiLogs(val?: string): boolean {\n if (val === undefined) return true;\n return val === 'false' ? false : true;\n }\n\n @Option({\n flags: '--api-base-url [url]',\n description: 'API base URL (defaults to process.env.BASE_URL).',\n required: false,\n })\n parseApiBaseUrl(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--ui-base-url [url]',\n description: 'UI base URL (defaults to process.env.FRONTEND_BASE_URL).',\n required: false,\n })\n parseUiBaseUrl(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--headless [true|false]',\n description: 'Run UI browser in headless mode (default: true).',\n required: false,\n })\n parseHeadless(val: string): boolean {\n return val === 'false' ? false : true;\n }\n\n @Option({\n flags: '--ui-timeout-ms [number]',\n description:\n 'Default timeout in ms for UI steps (waits, clicks, fills). Defaults to process.env.UI_TIMEOUT_MS, then the uiTestDefaultTimeoutMs setting, then 30000.',\n required: false,\n })\n parseUiTimeoutMs(val: string): number {\n return Number(val);\n }\n\n @Option({\n flags: '--ui-navigation-timeout-ms [number]',\n description:\n 'Default timeout in ms for ui.goto navigation. Defaults to process.env.UI_NAVIGATION_TIMEOUT_MS, then the uiTestNavigationTimeoutMs setting, then --ui-timeout-ms.',\n required: false,\n })\n parseUiNavigationTimeoutMs(val: string): number {\n return Number(val);\n }\n\n @Option({\n flags: '--timeout-ms [number]',\n description: 'Default scenario timeout in milliseconds.',\n required: false,\n })\n parseTimeoutMs(val: string): number {\n return Number(val);\n }\n\n @Option({\n flags: '--retries [number]',\n description: 'Default scenario retries.',\n required: false,\n })\n parseRetries(val: string): number {\n return Number(val);\n }\n\n @Option({\n flags: '--run-name [name]',\n description: 'Logical name for this test run (used by webhook reporter).',\n required: false,\n })\n parseRunName(val: string): string {\n return val;\n }\n\n @Option({\n flags: '--no-progress',\n description: 'Disable the interactive test progress footer.',\n required: false,\n })\n parseNoProgress(): boolean {\n return false;\n }\n}\n\nfunction splitCsv(value?: string): string[] | undefined {\n if (!value) return undefined;\n const items = value\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean);\n return items.length ? items : undefined;\n}\n\n// Accepts unknown because settings come back already parsed as numbers, while env\n// vars arrive as strings.\nfunction toPositiveNumber(value?: unknown): number | undefined {\n if (value === null || value === undefined || value === '') return undefined;\n const parsed = Number(value);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n}\n\nfunction resolveSpecPath(entry: string, metadataPath: string): string {\n if (path.isAbsolute(entry)) {\n return entry;\n }\n if (entry.startsWith('.')) {\n return path.resolve(path.dirname(metadataPath), entry);\n }\n return path.resolve(process.cwd(), entry);\n}\n\nfunction loadSpecRegistrations(entries: string[], metadataPath: string, registry: SpecRegistry): void {\n for (const entry of entries) {\n const resolved = resolveSpecPath(entry, metadataPath);\n let mod: any;\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n mod = require(resolved);\n } catch (err: any) {\n const message = err?.message ?? String(err);\n throw new Error(\n `Failed to load test spec module \"${entry}\" resolved to \"${resolved}\": ${message}`,\n );\n }\n const register = mod?.registerTestSpecs ?? mod?.default ?? mod;\n if (typeof register !== 'function') {\n throw new Error(\n `Test spec module \"${entry}\" did not export a register function (expected \"registerTestSpecs\" or default export).`,\n );\n }\n register(registry);\n }\n}\nfunction printSpecList(specIds: string[]): void {\n if (!specIds.length) {\n console.log('No test specs registered.');\n return;\n }\n console.log('Registered test specs:');\n for (const id of specIds) {\n console.log(`- ${id}`);\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { PublisherFactory } from '../services/queues/publisher-factory.service';
2
+ import { TestRunJobPayload, TestRunRequestDto } from '../dtos/test-run-request.dto';
3
+ export declare class TestRunController {
4
+ private readonly publisherFactory;
5
+ constructor(publisherFactory: PublisherFactory<TestRunJobPayload>);
6
+ trigger(dto: TestRunRequestDto & Record<string, any>): Promise<{
7
+ runId: `${string}-${string}-${string}-${string}-${string}`;
8
+ jobId: string;
9
+ status: string;
10
+ }>;
11
+ }
12
+ //# sourceMappingURL=test-run.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-run.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/test-run.controller.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,+BAA+B,CAAC;AAQvC,qBAGa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAAhB,gBAAgB,EAAE,gBAAgB,CAAC,iBAAiB,CAAC;IAO5E,OAAO,CAAS,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;;;;;CAanE"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.TestRunController = void 0;
16
+ const openapi = require("@nestjs/swagger");
17
+ const crypto_1 = require("crypto");
18
+ const common_1 = require("@nestjs/common");
19
+ const swagger_1 = require("@nestjs/swagger");
20
+ const auth_decorator_1 = require("../decorators/auth.decorator");
21
+ const public_decorator_1 = require("../decorators/public.decorator");
22
+ const auth_type_enum_1 = require("../enums/auth-type.enum");
23
+ const publisher_factory_service_1 = require("../services/queues/publisher-factory.service");
24
+ let TestRunController = class TestRunController {
25
+ constructor(publisherFactory) {
26
+ this.publisherFactory = publisherFactory;
27
+ }
28
+ async trigger(dto) {
29
+ const runId = (0, crypto_1.randomUUID)();
30
+ const jobId = await this.publisherFactory.publish({
31
+ payload: { ...dto, runId },
32
+ parentEntity: 'testRun',
33
+ }, 'TestRunQueuePublisher', dto.broker);
34
+ return { runId, jobId, status: 'queued' };
35
+ }
36
+ };
37
+ exports.TestRunController = TestRunController;
38
+ __decorate([
39
+ (0, public_decorator_1.Public)(),
40
+ (0, common_1.Post)(),
41
+ (0, common_1.HttpCode)(common_1.HttpStatus.ACCEPTED),
42
+ openapi.ApiResponse({ status: common_1.HttpStatus.ACCEPTED }),
43
+ __param(0, (0, common_1.Body)()),
44
+ __metadata("design:type", Function),
45
+ __metadata("design:paramtypes", [Object]),
46
+ __metadata("design:returntype", Promise)
47
+ ], TestRunController.prototype, "trigger", null);
48
+ exports.TestRunController = TestRunController = __decorate([
49
+ (0, auth_decorator_1.Auth)(auth_type_enum_1.AuthType.None),
50
+ (0, common_1.Controller)('test-runs'),
51
+ (0, swagger_1.ApiTags)('Solid Core'),
52
+ __metadata("design:paramtypes", [publisher_factory_service_1.PublisherFactory])
53
+ ], TestRunController);
54
+ //# sourceMappingURL=test-run.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-run.controller.js","sourceRoot":"","sources":["../../src/controllers/test-run.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mCAAoC;AACpC,2CAA8E;AAC9E,6CAA0C;AAE1C,iEAAqD;AACrD,qEAAyD;AACzD,4DAAoD;AACpD,4FAAiF;AAe1E,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAC5B,YAA6B,gBAAqD;QAArD,qBAAgB,GAAhB,gBAAgB,CAAqC;IAAG,CAAC;IAOhF,AAAN,KAAK,CAAC,OAAO,CAAS,GAA4C;QAChE,MAAM,KAAK,GAAG,IAAA,mBAAU,GAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAC/C;YACE,OAAO,EAAE,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE;YAC1B,YAAY,EAAE,SAAS;SACxB,EACD,uBAAuB,EACvB,GAAG,CAAC,MAAM,CACX,CAAC;QAEF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC5C,CAAC;CACF,CAAA;AArBY,8CAAiB;AAQtB;IALL,IAAA,yBAAM,GAAE;IACR,IAAA,aAAI,GAAE;IACN,IAAA,iBAAQ,EAAC,mBAAU,CAAC,QAAQ,CAAC;kCAApB,mBAAU,CAAC,QAAQ;IAGd,WAAA,IAAA,aAAI,GAAE,CAAA;;;;gDAYpB;4BApBU,iBAAiB;IAH7B,IAAA,qBAAI,EAAC,yBAAQ,CAAC,IAAI,CAAC;IACnB,IAAA,mBAAU,EAAC,WAAW,CAAC;IACvB,IAAA,iBAAO,EAAC,YAAY,CAAC;qCAE2B,4CAAgB;GADpD,iBAAiB,CAqB7B","sourcesContent":["import { randomUUID } from 'crypto';\nimport { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\n\nimport { Auth } from 'src/decorators/auth.decorator';\nimport { Public } from 'src/decorators/public.decorator';\nimport { AuthType } from 'src/enums/auth-type.enum';\nimport { PublisherFactory } from 'src/services/queues/publisher-factory.service';\nimport {\n TestRunJobPayload,\n TestRunRequestDto,\n} from 'src/dtos/test-run-request.dto';\n\n/**\n * Triggers a BDD test run from CUSTOM INPUT (inline scenarios). Enqueues the run and\n * returns immediately; a worker (QUEUES_SERVICE_ROLE=subscriber) executes it and\n * streams lifecycle webhooks to `dto.webhookUrl`. Reusable by any Solid app\n * (testingHub calls this from its StartRunController).\n */\n@Auth(AuthType.None)\n@Controller('test-runs')\n@ApiTags('Solid Core')\nexport class TestRunController {\n constructor(private readonly publisherFactory: PublisherFactory<TestRunJobPayload>) {}\n\n @Public()\n @Post()\n @HttpCode(HttpStatus.ACCEPTED)\n // Accept the raw body (not the typed DTO) so the global ValidationPipe's\n // implicit-conversion does not coerce inline scenario objects into empty arrays.\n async trigger(@Body() dto: TestRunRequestDto & Record<string, any>) {\n const runId = randomUUID();\n const jobId = await this.publisherFactory.publish(\n {\n payload: { ...dto, runId },\n parentEntity: 'testRun',\n },\n 'TestRunQueuePublisher',\n dto.broker,\n );\n\n return { runId, jobId, status: 'queued' };\n }\n}\n"]}
@@ -0,0 +1,35 @@
1
+ import type { ScenarioSpec, ScenarioType, TestingDataRecord, TestingRoleSpec, TestingUserSpec } from '../testing/contracts/testing-metadata.types';
2
+ export interface CaptureOptionsInput {
3
+ console?: boolean;
4
+ network?: boolean;
5
+ screenshotOnFailure?: boolean;
6
+ screenshotAtEnd?: boolean;
7
+ video?: boolean;
8
+ har?: boolean;
9
+ }
10
+ export declare class TestRunRequestDto {
11
+ scenarios?: ScenarioSpec[];
12
+ scenariosPath?: string;
13
+ data?: TestingDataRecord[];
14
+ roles?: TestingRoleSpec[];
15
+ users?: TestingUserSpec[];
16
+ baseUrl?: string;
17
+ uiBaseUrl?: string;
18
+ type?: ScenarioType;
19
+ env?: string;
20
+ headless?: boolean;
21
+ recordVideo?: boolean;
22
+ includeTags?: string[];
23
+ scenarioIds?: string[];
24
+ skipScenarioIds?: string[];
25
+ webhookUrl: string;
26
+ externalRunId?: string;
27
+ variables?: Record<string, string>;
28
+ capture?: CaptureOptionsInput;
29
+ printApiLogs?: boolean;
30
+ broker?: string;
31
+ }
32
+ export interface TestRunJobPayload extends TestRunRequestDto {
33
+ runId: string;
34
+ }
35
+ //# sourceMappingURL=test-run-request.dto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-run-request.dto.d.ts","sourceRoot":"","sources":["../../src/dtos/test-run-request.dto.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,eAAe,EAChB,MAAM,6CAA6C,CAAC;AAMrD,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAQD,qBAAa,iBAAiB;IAG5B,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;IAI3B,aAAa,CAAC,EAAE,MAAM,CAAC;IAIvB,IAAI,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAI3B,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAI1B,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;IAK1B,OAAO,CAAC,EAAE,MAAM,CAAC;IAKjB,SAAS,CAAC,EAAE,MAAM,CAAC;IAInB,IAAI,CAAC,EAAE,YAAY,CAAC;IAIpB,GAAG,CAAC,EAAE,MAAM,CAAC;IAIb,QAAQ,CAAC,EAAE,OAAO,CAAC;IAInB,WAAW,CAAC,EAAE,OAAO,CAAC;IAItB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAIvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAIvB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAI3B,UAAU,EAAG,MAAM,CAAC;IAKpB,aAAa,CAAC,EAAE,MAAM,CAAC;IASvB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAInC,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAI9B,YAAY,CAAC,EAAE,OAAO,CAAC;IAKvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,KAAK,EAAE,MAAM,CAAC;CACf"}
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.TestRunRequestDto = void 0;
13
+ const openapi = require("@nestjs/swagger");
14
+ const class_validator_1 = require("class-validator");
15
+ class TestRunRequestDto {
16
+ static _OPENAPI_METADATA_FACTORY() {
17
+ return { scenarios: { required: false, type: () => [Object] }, scenariosPath: { required: false, type: () => String }, data: { required: false, type: () => [Object] }, roles: { required: false, type: () => [Object] }, users: { required: false, type: () => [Object] }, baseUrl: { required: false, type: () => String }, uiBaseUrl: { required: false, type: () => String }, type: { required: false, type: () => Object }, env: { required: false, type: () => String }, headless: { required: false, type: () => Boolean }, recordVideo: { required: false, type: () => Boolean }, includeTags: { required: false, type: () => [String] }, scenarioIds: { required: false, type: () => [String] }, skipScenarioIds: { required: false, type: () => [String] }, webhookUrl: { required: true, type: () => String }, externalRunId: { required: false, type: () => String }, variables: { required: false, type: () => Object }, capture: { required: false, type: () => Object }, printApiLogs: { required: false, type: () => Boolean }, broker: { required: false, type: () => String } };
18
+ }
19
+ }
20
+ exports.TestRunRequestDto = TestRunRequestDto;
21
+ __decorate([
22
+ (0, class_validator_1.IsOptional)(),
23
+ (0, class_validator_1.IsArray)(),
24
+ __metadata("design:type", Array)
25
+ ], TestRunRequestDto.prototype, "scenarios", void 0);
26
+ __decorate([
27
+ (0, class_validator_1.IsOptional)(),
28
+ (0, class_validator_1.IsString)(),
29
+ __metadata("design:type", String)
30
+ ], TestRunRequestDto.prototype, "scenariosPath", void 0);
31
+ __decorate([
32
+ (0, class_validator_1.IsOptional)(),
33
+ (0, class_validator_1.IsArray)(),
34
+ __metadata("design:type", Array)
35
+ ], TestRunRequestDto.prototype, "data", void 0);
36
+ __decorate([
37
+ (0, class_validator_1.IsOptional)(),
38
+ (0, class_validator_1.IsArray)(),
39
+ __metadata("design:type", Array)
40
+ ], TestRunRequestDto.prototype, "roles", void 0);
41
+ __decorate([
42
+ (0, class_validator_1.IsOptional)(),
43
+ (0, class_validator_1.IsArray)(),
44
+ __metadata("design:type", Array)
45
+ ], TestRunRequestDto.prototype, "users", void 0);
46
+ __decorate([
47
+ (0, class_validator_1.IsOptional)(),
48
+ (0, class_validator_1.IsString)(),
49
+ __metadata("design:type", String)
50
+ ], TestRunRequestDto.prototype, "baseUrl", void 0);
51
+ __decorate([
52
+ (0, class_validator_1.IsOptional)(),
53
+ (0, class_validator_1.IsString)(),
54
+ __metadata("design:type", String)
55
+ ], TestRunRequestDto.prototype, "uiBaseUrl", void 0);
56
+ __decorate([
57
+ (0, class_validator_1.IsOptional)(),
58
+ (0, class_validator_1.IsString)(),
59
+ __metadata("design:type", String)
60
+ ], TestRunRequestDto.prototype, "type", void 0);
61
+ __decorate([
62
+ (0, class_validator_1.IsOptional)(),
63
+ (0, class_validator_1.IsString)(),
64
+ __metadata("design:type", String)
65
+ ], TestRunRequestDto.prototype, "env", void 0);
66
+ __decorate([
67
+ (0, class_validator_1.IsOptional)(),
68
+ (0, class_validator_1.IsBoolean)(),
69
+ __metadata("design:type", Boolean)
70
+ ], TestRunRequestDto.prototype, "headless", void 0);
71
+ __decorate([
72
+ (0, class_validator_1.IsOptional)(),
73
+ (0, class_validator_1.IsBoolean)(),
74
+ __metadata("design:type", Boolean)
75
+ ], TestRunRequestDto.prototype, "recordVideo", void 0);
76
+ __decorate([
77
+ (0, class_validator_1.IsOptional)(),
78
+ (0, class_validator_1.IsArray)(),
79
+ __metadata("design:type", Array)
80
+ ], TestRunRequestDto.prototype, "includeTags", void 0);
81
+ __decorate([
82
+ (0, class_validator_1.IsOptional)(),
83
+ (0, class_validator_1.IsArray)(),
84
+ __metadata("design:type", Array)
85
+ ], TestRunRequestDto.prototype, "scenarioIds", void 0);
86
+ __decorate([
87
+ (0, class_validator_1.IsOptional)(),
88
+ (0, class_validator_1.IsArray)(),
89
+ __metadata("design:type", Array)
90
+ ], TestRunRequestDto.prototype, "skipScenarioIds", void 0);
91
+ __decorate([
92
+ (0, class_validator_1.IsString)(),
93
+ __metadata("design:type", String)
94
+ ], TestRunRequestDto.prototype, "webhookUrl", void 0);
95
+ __decorate([
96
+ (0, class_validator_1.IsOptional)(),
97
+ (0, class_validator_1.IsString)(),
98
+ __metadata("design:type", String)
99
+ ], TestRunRequestDto.prototype, "externalRunId", void 0);
100
+ __decorate([
101
+ (0, class_validator_1.IsOptional)(),
102
+ (0, class_validator_1.IsObject)(),
103
+ __metadata("design:type", Object)
104
+ ], TestRunRequestDto.prototype, "variables", void 0);
105
+ __decorate([
106
+ (0, class_validator_1.IsOptional)(),
107
+ (0, class_validator_1.IsObject)(),
108
+ __metadata("design:type", Object)
109
+ ], TestRunRequestDto.prototype, "capture", void 0);
110
+ __decorate([
111
+ (0, class_validator_1.IsOptional)(),
112
+ (0, class_validator_1.IsBoolean)(),
113
+ __metadata("design:type", Boolean)
114
+ ], TestRunRequestDto.prototype, "printApiLogs", void 0);
115
+ __decorate([
116
+ (0, class_validator_1.IsOptional)(),
117
+ (0, class_validator_1.IsString)(),
118
+ __metadata("design:type", String)
119
+ ], TestRunRequestDto.prototype, "broker", void 0);
120
+ //# sourceMappingURL=test-run-request.dto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-run-request.dto.js","sourceRoot":"","sources":["../../src/dtos/test-run-request.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,qDAMyB;AA6BzB,MAAa,iBAAiB;;;;CAyF7B;AAzFD,8CAyFC;AAtFC;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,GAAE;;oDACiB;AAI3B;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;wDACY;AAIvB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,GAAE;;+CACiB;AAI3B;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,GAAE;;gDACgB;AAI1B;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,GAAE;;gDACgB;AAK1B;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;kDACM;AAKjB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;oDACQ;AAInB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;+CACS;AAIpB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;8CACE;AAIb;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,2BAAS,GAAE;;mDACO;AAInB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,2BAAS,GAAE;;sDACU;AAItB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,GAAE;;sDACa;AAIvB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,GAAE;;sDACa;AAIvB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,GAAE;;0DACiB;AAI3B;IADC,IAAA,0BAAQ,GAAE;;qDACS;AAKpB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;wDACY;AASvB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;oDACwB;AAInC;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;kDACmB;AAI9B;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,2BAAS,GAAE;;uDACW;AAKvB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;iDACK","sourcesContent":["import {\n IsArray,\n IsBoolean,\n IsObject,\n IsOptional,\n IsString,\n} from 'class-validator';\n\nimport type {\n ScenarioSpec,\n ScenarioType,\n TestingDataRecord,\n TestingRoleSpec,\n TestingUserSpec,\n} from '../testing/contracts/testing-metadata.types';\n\n/**\n * Per-scenario capture toggles. Structurally compatible with the typed\n * `CaptureOptions` introduced in Phase 2 (A3, in adapters/ui/ui.types.ts).\n */\nexport interface CaptureOptionsInput {\n console?: boolean;\n network?: boolean;\n screenshotOnFailure?: boolean;\n screenshotAtEnd?: boolean;\n video?: boolean;\n har?: boolean;\n}\n\n/**\n * Body of `POST /test-runs`. Carries the FULL test definition inline (scenarios +\n * optional data/roles/users — the `testing` block minus `specs`), so the runner is\n * location-agnostic and never reads a fixed module/path. `specs` (custom step code)\n * cannot travel inline and must be deployed on the worker.\n */\nexport class TestRunRequestDto {\n @IsOptional()\n @IsArray()\n scenarios?: ScenarioSpec[];\n\n @IsOptional()\n @IsString()\n scenariosPath?: string;\n\n @IsOptional()\n @IsArray()\n data?: TestingDataRecord[];\n\n @IsOptional()\n @IsArray()\n roles?: TestingRoleSpec[];\n\n @IsOptional()\n @IsArray()\n users?: TestingUserSpec[];\n\n /** API base URL for relative request URLs. */\n @IsOptional()\n @IsString()\n baseUrl?: string;\n\n /** UI base URL for relative navigation (Playwright). */\n @IsOptional()\n @IsString()\n uiBaseUrl?: string;\n\n @IsOptional()\n @IsString()\n type?: ScenarioType;\n\n @IsOptional()\n @IsString()\n env?: string;\n\n @IsOptional()\n @IsBoolean()\n headless?: boolean;\n\n @IsOptional()\n @IsBoolean()\n recordVideo?: boolean;\n\n @IsOptional()\n @IsArray()\n includeTags?: string[];\n\n @IsOptional()\n @IsArray()\n scenarioIds?: string[];\n\n @IsOptional()\n @IsArray()\n skipScenarioIds?: string[];\n\n /** Where lifecycle events are POSTed (e.g. testingHub ingest endpoint). */\n @IsString()\n webhookUrl!: string;\n\n /** Correlation id supplied by the caller (e.g. testingHub TestRun id). */\n @IsOptional()\n @IsString()\n externalRunId?: string;\n\n /**\n * Per-run env variables for `${env:X}` interpolation — e.g. { BASE_URL: app.url }\n * so scenarios target the application under test rather than the runner itself.\n * (Distinct from `env` above, which is the dev/uat/prod environment label.)\n */\n @IsOptional()\n @IsObject()\n variables?: Record<string, string>;\n\n @IsOptional()\n @IsObject()\n capture?: CaptureOptionsInput;\n\n @IsOptional()\n @IsBoolean()\n printApiLogs?: boolean;\n\n /** Queue broker override: database | redis | rabbitmq (default: database). */\n @IsOptional()\n @IsString()\n broker?: string;\n}\n\n/** Queue payload = the request plus the runner-generated run id. */\nexport interface TestRunJobPayload extends TestRunRequestDto {\n runId: string;\n}\n"]}
@@ -3,17 +3,21 @@ import { JwtService } from '@nestjs/jwt';
3
3
  import { PermissionMetadataService } from '../services/permission-metadata.service';
4
4
  import { ClsService } from 'nestjs-cls';
5
5
  import { ActiveSessionStorageService } from "../services/active-session-storage.service";
6
+ import { AccessTokenDenylistService } from "../services/access-token-denylist.service";
6
7
  import { SettingService } from '../services/setting.service';
7
8
  export declare class AccessTokenGuard implements CanActivate {
8
9
  private readonly jwtService;
9
10
  private readonly permissionsService;
10
11
  private readonly activeSessionStorage;
12
+ private readonly accessTokenDenylist;
11
13
  private readonly settingService;
12
14
  private readonly cls;
13
- constructor(jwtService: JwtService, permissionsService: PermissionMetadataService, activeSessionStorage: ActiveSessionStorageService, settingService: SettingService, cls: ClsService);
15
+ constructor(jwtService: JwtService, permissionsService: PermissionMetadataService, activeSessionStorage: ActiveSessionStorageService, accessTokenDenylist: AccessTokenDenylistService, settingService: SettingService, cls: ClsService);
14
16
  canActivate(context: ExecutionContext): Promise<boolean>;
15
17
  private extractTokenFromHeader;
16
18
  private resolveSessionId;
19
+ private resolveRevocationKey;
20
+ private validateNotRevoked;
17
21
  private validateConcurrentLoginSession;
18
22
  }
19
23
  //# sourceMappingURL=access-token.guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"access-token.guard.d.ts","sourceRoot":"","sources":["../../src/guards/access-token.guard.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,gBAAgB,EAGjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D,qBACa,gBAAiB,YAAW,WAAW;IAEhD,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAJH,UAAU,EAAE,UAAU,EACtB,kBAAkB,EAAE,yBAAyB,EAC7C,oBAAoB,EAAE,2BAA2B,EACjD,cAAc,EAAE,cAAc,EAC9B,GAAG,EAAE,UAAU;IAG5B,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAwC9D,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,gBAAgB;YAUV,8BAA8B;CAqB7C"}
1
+ {"version":3,"file":"access-token.guard.d.ts","sourceRoot":"","sources":["../../src/guards/access-token.guard.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,gBAAgB,EAGjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D,qBACa,gBAAiB,YAAW,WAAW;IAEhD,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IACrC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG;gBALH,UAAU,EAAE,UAAU,EACtB,kBAAkB,EAAE,yBAAyB,EAC7C,oBAAoB,EAAE,2BAA2B,EACjD,mBAAmB,EAAE,0BAA0B,EAC/C,cAAc,EAAE,cAAc,EAC9B,GAAG,EAAE,UAAU;IAG5B,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IA+C9D,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,oBAAoB;YAQd,kBAAkB;YAmBlB,8BAA8B;CAqB7C"}
@@ -17,13 +17,15 @@ const constants_1 = require("../constants");
17
17
  const permission_metadata_service_1 = require("../services/permission-metadata.service");
18
18
  const nestjs_cls_1 = require("nestjs-cls");
19
19
  const active_session_storage_service_1 = require("../services/active-session-storage.service");
20
+ const access_token_denylist_service_1 = require("../services/access-token-denylist.service");
20
21
  const setting_service_1 = require("../services/setting.service");
21
22
  const crypto_1 = require("crypto");
22
23
  let AccessTokenGuard = class AccessTokenGuard {
23
- constructor(jwtService, permissionsService, activeSessionStorage, settingService, cls) {
24
+ constructor(jwtService, permissionsService, activeSessionStorage, accessTokenDenylist, settingService, cls) {
24
25
  this.jwtService = jwtService;
25
26
  this.permissionsService = permissionsService;
26
27
  this.activeSessionStorage = activeSessionStorage;
28
+ this.accessTokenDenylist = accessTokenDenylist;
27
29
  this.settingService = settingService;
28
30
  this.cls = cls;
29
31
  }
@@ -42,6 +44,7 @@ let AccessTokenGuard = class AccessTokenGuard {
42
44
  refreshTokenTtl: this.settingService.getConfigValue("refreshTokenTtl")
43
45
  };
44
46
  const payload = await this.jwtService.verifyAsync(token, jwtConfiguration);
47
+ await this.validateNotRevoked(payload, token);
45
48
  await this.validateConcurrentLoginSession(payload, token);
46
49
  const permissions = await this.permissionsService.findAllUsingRoles(payload.roles);
47
50
  payload.permissions = permissions.map((permission) => permission.name);
@@ -65,6 +68,21 @@ let AccessTokenGuard = class AccessTokenGuard {
65
68
  }
66
69
  return (0, crypto_1.createHash)('sha256').update(token).digest('hex');
67
70
  }
71
+ resolveRevocationKey(payload, token) {
72
+ return (payload.sessionId ??
73
+ payload.deviceKey ??
74
+ (0, crypto_1.createHash)('sha256').update(token).digest('hex'));
75
+ }
76
+ async validateNotRevoked(payload, token) {
77
+ if (!this.accessTokenDenylist.isEnabled()) {
78
+ return;
79
+ }
80
+ const revocationKey = this.resolveRevocationKey(payload, token);
81
+ const revoked = await this.accessTokenDenylist.isRevoked(payload.sub, revocationKey, payload.iat);
82
+ if (revoked) {
83
+ throw new common_1.UnauthorizedException(error_messages_1.ERROR_MESSAGES.SESSION_INVALID);
84
+ }
85
+ }
68
86
  async validateConcurrentLoginSession(payload, token) {
69
87
  if (!this.settingService.getConfigValue("preventConcurrentLogins")) {
70
88
  return;
@@ -86,6 +104,7 @@ exports.AccessTokenGuard = AccessTokenGuard = __decorate([
86
104
  __metadata("design:paramtypes", [jwt_1.JwtService,
87
105
  permission_metadata_service_1.PermissionMetadataService,
88
106
  active_session_storage_service_1.ActiveSessionStorageService,
107
+ access_token_denylist_service_1.AccessTokenDenylistService,
89
108
  setting_service_1.SettingService,
90
109
  nestjs_cls_1.ClsService])
91
110
  ], AccessTokenGuard);
@@ -1 +1 @@
1
- {"version":3,"file":"access-token.guard.js","sourceRoot":"","sources":["../../src/guards/access-token.guard.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SolidCoreSetting } from \"src/services/settings/default-settings-provider.service\";\nimport {\n CanActivate,\n ExecutionContext,\n Injectable,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { JwtService } from '@nestjs/jwt';\nimport { Request } from 'express';\nimport { ERROR_MESSAGES } from \"src/constants/error-messages\";\nimport { ActiveUserData } from '../interfaces/active-user-data.interface';\nimport { REQUEST_USER_KEY } from \"../constants\";\nimport { PermissionMetadataService } from '../services/permission-metadata.service';\nimport { ClsService } from 'nestjs-cls';\nimport { ActiveSessionStorageService } from \"../services/active-session-storage.service\";\nimport { SettingService } from '../services/setting.service';\nimport { createHash } from \"crypto\";\n\n@Injectable()\nexport class AccessTokenGuard implements CanActivate {\n constructor(\n private readonly jwtService: JwtService,\n private readonly permissionsService: PermissionMetadataService,\n private readonly activeSessionStorage: ActiveSessionStorageService,\n private readonly settingService: SettingService,\n private readonly cls: ClsService\n ) { }\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n // 💡 NOTE: For GraphQL applications, you'd have to use the wrapper GqlExecutionContext here instead.\n const request = context.switchToHttp().getRequest();\n const token = this.extractTokenFromHeader(request);\n if (!token) {\n throw new UnauthorizedException();\n }\n try {\n\n const jwtConfiguration = {\n secret: this.settingService.getConfigValue<SolidCoreSetting>(\"secret\"),\n audience: this.settingService.getConfigValue<SolidCoreSetting>(\"audience\"),\n issuer: this.settingService.getConfigValue<SolidCoreSetting>(\"issuer\"),\n accessTokenTtl: this.settingService.getConfigValue<SolidCoreSetting>(\"accessTokenTtl\"),\n refreshTokenTtl: this.settingService.getConfigValue<SolidCoreSetting>(\"refreshTokenTtl\")\n }\n const payload: ActiveUserData = await this.jwtService.verifyAsync(\n token,\n jwtConfiguration\n );\n\n // Prevent Concurrent Login Feature\n await this.validateConcurrentLoginSession(payload, token);\n\n // Load permissions given the user. \n const permissions = await this.permissionsService.findAllUsingRoles(payload.roles);\n payload.permissions = permissions.map((permission) => permission.name);\n\n request[REQUEST_USER_KEY] = payload;\n this.cls.set(REQUEST_USER_KEY, payload);\n // console.log(`About to set payload in the request user key:`);\n // console.log(payload);\n } catch (err) {\n throw err instanceof UnauthorizedException\n ? err\n : new UnauthorizedException();\n }\n return true;\n }\n\n private extractTokenFromHeader(request: Request): string | undefined {\n // Since token is included in the Authorization header something like \n // Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEsImVtYWlsIjoidXNlcjFAbmVzdGpzLmNvbSIsImlhdCI6MTcwMDk5NTk1MywiZXhwIjoxNzAwOTk5NTUzLCJhdWQiOiJsb2NhbGhvc3Q6MzAwMCIsImlzcyI6ImxvY2FsaG9zdDozMDAwIn0.303Y04SZjKqoPjJRq4hXHcarHeZYS878gPGWmw2SoUc\n const [_, token] = request.headers.authorization?.split(' ') ?? [];\n return token;\n }\n\n private resolveSessionId(payload: ActiveUserData, token: string): string {\n if (payload.sessionId) {\n return payload.sessionId;\n }\n\n // Legacy tokens (issued before preventConcurrentLogins was enabled)\n // have no sessionId claim, so derive a stable fallback from the token.\n return createHash('sha256').update(token).digest('hex');\n }\n\n private async validateConcurrentLoginSession(payload: ActiveUserData, token: string,): Promise<void> {\n if (!this.settingService.getConfigValue<SolidCoreSetting>(\"preventConcurrentLogins\",)) {\n return;\n }\n\n const activeSessionId = await this.activeSessionStorage.getActiveSession(payload.sub);\n const currentSessionId = this.resolveSessionId(payload, token);\n\n if (!activeSessionId) {\n // No active session recorded yet for this user — this is the first\n // request we've seen since the feature was enabled (or storage was\n // cleared). Adopt this request's session as the active one so this\n // browser stays logged in going forward.\n await this.activeSessionStorage.setActiveSession(payload.sub, currentSessionId,);\n return;\n }\n\n if (currentSessionId !== activeSessionId) {\n throw new UnauthorizedException(ERROR_MESSAGES.SESSION_INVALID);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"access-token.guard.js","sourceRoot":"","sources":["../../src/guards/access-token.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,2CAKwB;AACxB,qCAAyC;AAEzC,gEAA8D;AAE9D,4CAAgD;AAChD,yFAAoF;AACpF,2CAAwC;AACxC,+FAAyF;AACzF,6FAAuF;AACvF,iEAA6D;AAC7D,mCAAoC;AAG7B,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAC3B,YACmB,UAAsB,EACtB,kBAA6C,EAC7C,oBAAiD,EACjD,mBAA+C,EAC/C,cAA8B,EAC9B,GAAe;QALf,eAAU,GAAV,UAAU,CAAY;QACtB,uBAAkB,GAAlB,kBAAkB,CAA2B;QAC7C,yBAAoB,GAApB,oBAAoB,CAA6B;QACjD,wBAAmB,GAAnB,mBAAmB,CAA4B;QAC/C,mBAAc,GAAd,cAAc,CAAgB;QAC9B,QAAG,GAAH,GAAG,CAAY;IAC9B,CAAC;IAEL,KAAK,CAAC,WAAW,CAAC,OAAyB;QAEzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,8BAAqB,EAAE,CAAC;QACpC,CAAC;QACD,IAAI,CAAC;YAEH,MAAM,gBAAgB,GAAG;gBACvB,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAmB,QAAQ,CAAC;gBACtE,QAAQ,EAAE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAmB,UAAU,CAAC;gBAC1E,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAmB,QAAQ,CAAC;gBACtE,cAAc,EAAE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAmB,gBAAgB,CAAC;gBACtF,eAAe,EAAE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAmB,iBAAiB,CAAC;aACzF,CAAA;YACD,MAAM,OAAO,GAAmB,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAC/D,KAAK,EACL,gBAAgB,CACjB,CAAC;YAOF,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAG9C,MAAM,IAAI,CAAC,8BAA8B,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAG1D,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACnF,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAEvE,OAAO,CAAC,4BAAgB,CAAC,GAAG,OAAO,CAAC;YACpC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,4BAAgB,EAAE,OAAO,CAAC,CAAC;QAG1C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,YAAY,8BAAqB;gBACxC,CAAC,CAAC,GAAG;gBACL,CAAC,CAAC,IAAI,8BAAqB,EAAE,CAAC;QAClC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,sBAAsB,CAAC,OAAgB;QAG7C,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACnE,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,gBAAgB,CAAC,OAAuB,EAAE,KAAa;QAC7D,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,OAAO,OAAO,CAAC,SAAS,CAAC;QAC3B,CAAC;QAID,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC;IAcO,oBAAoB,CAAC,OAAuB,EAAE,KAAa;QACjE,OAAO,CACL,OAAO,CAAC,SAAS;YACjB,OAAO,CAAC,SAAS;YACjB,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACjD,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,OAAuB,EAAE,KAAa;QAIrE,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,EAAE,CAAC;YAC1C,OAAO;QACT,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,SAAS,CACtD,OAAO,CAAC,GAAG,EACX,aAAa,EACb,OAAO,CAAC,GAAG,CACZ,CAAC;QACF,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,8BAAqB,CAAC,+BAAc,CAAC,eAAe,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,8BAA8B,CAAC,OAAuB,EAAE,KAAa;QACjF,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,cAAc,CAAmB,yBAAyB,CAAE,EAAE,CAAC;YACtF,OAAO;QACT,CAAC;QAED,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACtF,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAE/D,IAAI,CAAC,eAAe,EAAE,CAAC;YAKrB,MAAM,IAAI,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,EAAE,gBAAgB,CAAE,CAAC;YACjF,OAAO;QACT,CAAC;QAED,IAAI,gBAAgB,KAAK,eAAe,EAAE,CAAC;YACzC,MAAM,IAAI,8BAAqB,CAAC,+BAAc,CAAC,eAAe,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;CACF,CAAA;AAtIY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;qCAGoB,gBAAU;QACF,uDAAyB;QACvB,4DAA2B;QAC5B,0DAA0B;QAC/B,gCAAc;QACzB,uBAAU;GAPvB,gBAAgB,CAsI5B","sourcesContent":["import type { SolidCoreSetting } from \"src/services/settings/default-settings-provider.service\";\nimport {\n CanActivate,\n ExecutionContext,\n Injectable,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { JwtService } from '@nestjs/jwt';\nimport { Request } from 'express';\nimport { ERROR_MESSAGES } from \"src/constants/error-messages\";\nimport { ActiveUserData } from '../interfaces/active-user-data.interface';\nimport { REQUEST_USER_KEY } from \"../constants\";\nimport { PermissionMetadataService } from '../services/permission-metadata.service';\nimport { ClsService } from 'nestjs-cls';\nimport { ActiveSessionStorageService } from \"../services/active-session-storage.service\";\nimport { AccessTokenDenylistService } from \"../services/access-token-denylist.service\";\nimport { SettingService } from '../services/setting.service';\nimport { createHash } from \"crypto\";\n\n@Injectable()\nexport class AccessTokenGuard implements CanActivate {\n constructor(\n private readonly jwtService: JwtService,\n private readonly permissionsService: PermissionMetadataService,\n private readonly activeSessionStorage: ActiveSessionStorageService,\n private readonly accessTokenDenylist: AccessTokenDenylistService,\n private readonly settingService: SettingService,\n private readonly cls: ClsService\n ) { }\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n // 💡 NOTE: For GraphQL applications, you'd have to use the wrapper GqlExecutionContext here instead.\n const request = context.switchToHttp().getRequest();\n const token = this.extractTokenFromHeader(request);\n if (!token) {\n throw new UnauthorizedException();\n }\n try {\n\n const jwtConfiguration = {\n secret: this.settingService.getConfigValue<SolidCoreSetting>(\"secret\"),\n audience: this.settingService.getConfigValue<SolidCoreSetting>(\"audience\"),\n issuer: this.settingService.getConfigValue<SolidCoreSetting>(\"issuer\"),\n accessTokenTtl: this.settingService.getConfigValue<SolidCoreSetting>(\"accessTokenTtl\"),\n refreshTokenTtl: this.settingService.getConfigValue<SolidCoreSetting>(\"refreshTokenTtl\")\n }\n const payload: ActiveUserData = await this.jwtService.verifyAsync(\n token,\n jwtConfiguration\n );\n\n // Immediate access-token revocation. Runs BEFORE the concurrent-login\n // check on purpose: rejecting a revoked token first stops it reaching the\n // adopt-on-empty branch below and reclaiming the active session slot.\n // No setting check here - isRevoked short-circuits when the feature is\n // off, without touching the cache.\n await this.validateNotRevoked(payload, token);\n\n // Prevent Concurrent Login Feature\n await this.validateConcurrentLoginSession(payload, token);\n\n // Load permissions given the user. \n const permissions = await this.permissionsService.findAllUsingRoles(payload.roles);\n payload.permissions = permissions.map((permission) => permission.name);\n\n request[REQUEST_USER_KEY] = payload;\n this.cls.set(REQUEST_USER_KEY, payload);\n // console.log(`About to set payload in the request user key:`);\n // console.log(payload);\n } catch (err) {\n throw err instanceof UnauthorizedException\n ? err\n : new UnauthorizedException();\n }\n return true;\n }\n\n private extractTokenFromHeader(request: Request): string | undefined {\n // Since token is included in the Authorization header something like \n // Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEsImVtYWlsIjoidXNlcjFAbmVzdGpzLmNvbSIsImlhdCI6MTcwMDk5NTk1MywiZXhwIjoxNzAwOTk5NTUzLCJhdWQiOiJsb2NhbGhvc3Q6MzAwMCIsImlzcyI6ImxvY2FsaG9zdDozMDAwIn0.303Y04SZjKqoPjJRq4hXHcarHeZYS878gPGWmw2SoUc\n const [_, token] = request.headers.authorization?.split(' ') ?? [];\n return token;\n }\n\n private resolveSessionId(payload: ActiveUserData, token: string): string {\n if (payload.sessionId) {\n return payload.sessionId;\n }\n\n // Legacy tokens (issued before preventConcurrentLogins was enabled)\n // have no sessionId claim, so derive a stable fallback from the token.\n return createHash('sha256').update(token).digest('hex');\n }\n\n /**\n * The key this token's session is denylisted under.\n *\n * Deliberately NOT merged with resolveSessionId above, which differs only by\n * the deviceKey step. Merging them would change validateConcurrentLoginSession\n * for tokens issued while preventConcurrentLogins was off that are still live\n * when it is switched on: those resolve to sha256(token) today and would\n * resolve to deviceKey instead. The divergence is invisible in normal\n * operation - that check only runs while the setting is on, and tokens issued\n * in that state never carry a deviceKey - so the two formulas already agree\n * for every token it sees. Only toggle-crossover tokens tell them apart.\n */\n private resolveRevocationKey(payload: ActiveUserData, token: string): string {\n return (\n payload.sessionId ??\n payload.deviceKey ??\n createHash('sha256').update(token).digest('hex')\n );\n }\n\n private async validateNotRevoked(payload: ActiveUserData, token: string): Promise<void> {\n // isRevoked would short-circuit on its own, but resolving the key first can\n // cost a sha256 for a token carrying neither claim. Checking here keeps the\n // opted-out path genuinely free.\n if (!this.accessTokenDenylist.isEnabled()) {\n return;\n }\n\n const revocationKey = this.resolveRevocationKey(payload, token);\n const revoked = await this.accessTokenDenylist.isRevoked(\n payload.sub,\n revocationKey,\n payload.iat,\n );\n if (revoked) {\n throw new UnauthorizedException(ERROR_MESSAGES.SESSION_INVALID);\n }\n }\n\n private async validateConcurrentLoginSession(payload: ActiveUserData, token: string,): Promise<void> {\n if (!this.settingService.getConfigValue<SolidCoreSetting>(\"preventConcurrentLogins\",)) {\n return;\n }\n\n const activeSessionId = await this.activeSessionStorage.getActiveSession(payload.sub);\n const currentSessionId = this.resolveSessionId(payload, token);\n\n if (!activeSessionId) {\n // No active session recorded yet for this user — this is the first\n // request we've seen since the feature was enabled (or storage was\n // cleared). Adopt this request's session as the active one so this\n // browser stays logged in going forward.\n await this.activeSessionStorage.setActiveSession(payload.sub, currentSessionId,);\n return;\n }\n\n if (currentSessionId !== activeSessionId) {\n throw new UnauthorizedException(ERROR_MESSAGES.SESSION_INVALID);\n }\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -307,6 +307,15 @@ export * from './jobs/redis/smtp-email-subscriber-redis.service';
307
307
  export * from './jobs/redis/test-queue-publisher-redis.service';
308
308
  export * from './jobs/redis/test-queue-options-redis';
309
309
  export * from './jobs/redis/test-queue-subscriber-redis.service';
310
+ export * from './jobs/database/test-run-queue-publisher-database.service';
311
+ export * from './jobs/database/test-run-queue-subscriber-database.service';
312
+ export * from './controllers/test-run.controller';
313
+ export * from './dtos/test-run-request.dto';
314
+ export * from './testing/reporter/lifecycle-events.types';
315
+ export * from './testing/reporter/lifecycle-webhook-reporter';
316
+ export * from './testing/reporter/artifact-sink';
317
+ export * from './testing/reporter/file-service-artifact-sink';
318
+ export * from './services/file/file-service.interface';
310
319
  export * from './jobs/redis/three60-whatsapp-publisher-redis.service';
311
320
  export * from './jobs/redis/three60-whatsapp-queue-options-redis';
312
321
  export * from './jobs/redis/three60-whatsapp-subscriber-redis.service';
@@ -321,6 +330,7 @@ export * from './passport-strategies/microsoft-active-directory-oauth.strategy';
321
330
  export * from './services/selection-providers/list-of-values-selection-providers.service';
322
331
  export * from './seeders/permission-metadata-seeder.service';
323
332
  export * from './seeders/module-metadata-seeder.service';
333
+ export * from './services/access-token-denylist.service';
324
334
  export * from './services/action-metadata.service';
325
335
  export * from './services/authentication.service';
326
336
  export * from './services/bcrypt.service';
@@ -438,4 +448,6 @@ export * from './interfaces';
438
448
  export * from './solid-core.module';
439
449
  export * from './winston.logger';
440
450
  export { ERROR_MESSAGES } from './constants/error-messages';
451
+ export { SUCCESS_MESSAGES } from './constants/success-messages';
452
+ export { ensureChromiumInstalled, isChromiumInstalled, cancelChromiumInstall, } from './testing/adapters/ui/browser-provisioner';
441
453
  //# sourceMappingURL=index.d.ts.map