create-qpq-app 0.1.25 → 0.1.27

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 (283) hide show
  1. package/package.json +2 -2
  2. package/template/README.md +4 -0
  3. package/template/apps/qpqjs/account.qpq.ts +4 -0
  4. package/template/apps/qpqjs/bootstrap.qpq.ts +13 -2
  5. package/template/apps/qpqjs/packages/service-utils/src/defineQpqjsService.ts +4 -0
  6. package/template/apps/qpqjs/services/test/models/src/SmokeProbeRecord.ts +12 -0
  7. package/template/apps/qpqjs/services/test/models/src/SmokeRunSummary.ts +8 -1
  8. package/template/apps/qpqjs/services/test/models/src/SmokeTestStatus.ts +2 -0
  9. package/template/apps/qpqjs/services/test/service/src/infrastructure.ts +0 -6
  10. package/template/apps/qpqjs/services/test/service/src/smoke/config/defineSmoke.ts +8 -174
  11. package/template/apps/qpqjs/services/test/service/src/smoke/harness/assert/askSmokePollForMarker.ts +44 -0
  12. package/template/apps/qpqjs/services/test/service/src/smoke/harness/assert/index.ts +2 -0
  13. package/template/apps/qpqjs/services/test/service/src/smoke/harness/config/defineSmokeHarness.ts +115 -0
  14. package/template/apps/qpqjs/services/test/service/src/smoke/harness/config/index.ts +1 -0
  15. package/template/apps/qpqjs/services/test/service/src/smoke/{constants → harness/constants}/index.ts +0 -2
  16. package/template/apps/qpqjs/services/test/service/src/smoke/harness/index.ts +10 -0
  17. package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/smokeRun/askExecuteSmokeTest.ts +6 -5
  18. package/template/apps/qpqjs/services/test/service/src/smoke/harness/logic/smokeRun/askStartSmokeRun.ts +85 -0
  19. package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/smokeRun/index.ts +1 -0
  20. package/template/apps/qpqjs/services/test/service/src/smoke/harness/logic/smokeRun/listSmokeTests.ts +6 -0
  21. package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/smokeRun/summarizeSmokeRun.ts +5 -1
  22. package/template/apps/qpqjs/services/test/service/src/smoke/{models → harness/models}/SmokeTestRequestedQueueEvent.ts +1 -1
  23. package/template/apps/qpqjs/services/test/service/src/smoke/harness/models/index.ts +2 -0
  24. package/template/apps/qpqjs/services/test/service/src/smoke/harness/queue/index.ts +1 -0
  25. package/template/apps/qpqjs/services/test/service/src/smoke/harness/types/SmokeSuite.ts +13 -0
  26. package/template/apps/qpqjs/services/test/service/src/smoke/{tests → harness/types}/SmokeTestDefinition.ts +3 -0
  27. package/template/apps/qpqjs/services/test/service/src/smoke/harness/types/index.ts +2 -0
  28. package/template/apps/qpqjs/services/test/service/src/smoke/index.ts +2 -9
  29. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/config/defineEmailReceiveSmoke.ts +20 -0
  30. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/config/index.ts +1 -0
  31. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/constants/SMOKE_EMAIL_RECEIVER.ts +2 -0
  32. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/constants/index.ts +1 -0
  33. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/emailReceiveSmokeSuite.ts +15 -0
  34. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/entry/email/index.ts +1 -0
  35. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/entry/email/onSmokeEmailReceived.ts +33 -0
  36. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/entry/index.ts +1 -0
  37. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/index.ts +5 -0
  38. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/logic/askRunEmailReceiveTest.ts +41 -0
  39. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/logic/index.ts +2 -0
  40. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/logic/smokeEmailMarkerId.ts +4 -0
  41. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/config/defineEncryptedResourcesSmoke.ts +29 -0
  42. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/config/index.ts +1 -0
  43. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/constants/SMOKE_CRYPTO_KEY.ts +5 -0
  44. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/constants/SMOKE_ENCRYPTED_PROBE_DRIVE.ts +2 -0
  45. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/constants/SMOKE_ENCRYPTED_PROBE_STORE.ts +2 -0
  46. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/constants/index.ts +3 -0
  47. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/encryptedResourcesSmokeSuite.ts +9 -0
  48. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/index.ts +4 -0
  49. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/logic/askRunEncryptedResourcesTest.ts +61 -0
  50. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/logic/index.ts +1 -0
  51. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/config/defineEventBusSmoke.ts +21 -0
  52. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/config/index.ts +1 -0
  53. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/constants/SMOKE_PROBE_EVENT_BUS.ts +2 -0
  54. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/constants/SMOKE_PROBE_EVENT_QUEUE.ts +2 -0
  55. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/constants/SMOKE_PROBE_EVENT_TYPE.ts +2 -0
  56. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/constants/index.ts +3 -0
  57. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/entry/index.ts +1 -0
  58. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/entry/queue/index.ts +1 -0
  59. package/template/apps/qpqjs/services/test/service/src/smoke/{queue → suites/eventBus/entry/queue}/onSmokeProbeEvent.ts +1 -1
  60. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/eventBusSmokeSuite.ts +9 -0
  61. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/index.ts +6 -0
  62. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/logic/askRunEventBusTest.ts +31 -0
  63. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/models/index.ts +1 -0
  64. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/config/defineEventDocSmoke.ts +44 -0
  65. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/config/index.ts +1 -0
  66. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/constants/index.ts +1 -0
  67. package/template/apps/qpqjs/services/test/service/src/smoke/{constants → suites/eventDoc/constants}/smokeEventDoc.ts +1 -1
  68. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/entry/index.ts +1 -0
  69. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/entry/queue/index.ts +1 -0
  70. package/template/apps/qpqjs/services/test/service/src/smoke/{queue → suites/eventDoc/entry/queue}/onSmokeEventDocAppend.ts +3 -3
  71. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/eventDocSmokeSuite.ts +19 -0
  72. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/index.ts +7 -0
  73. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/askAssertContiguousEventIds.ts +1 -1
  74. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/askAssertSmokeProbeDocState.ts +2 -2
  75. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/askAwaitSmokeEventDocLog.ts +3 -2
  76. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/askRunEventDocConcurrentAppendTest.ts +5 -5
  77. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/askRunEventDocInterleavedBatchAppendTest.ts +4 -4
  78. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/models/index.ts +2 -0
  79. package/template/apps/qpqjs/services/test/service/src/smoke/suites/index.ts +17 -0
  80. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStore/index.ts +2 -0
  81. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStore/keyValueStoreSmokeSuite.ts +14 -0
  82. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/crossService → suites/keyValueStore/logic}/askRunCrossServiceKeyValueStoreTest.ts +1 -1
  83. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/keyValueStore → suites/keyValueStore/logic}/askRunKeyValueStoreTest.ts +1 -1
  84. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStore/logic/index.ts +2 -0
  85. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/config/defineKeyValueStoreStreamSmoke.ts +30 -0
  86. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/config/index.ts +1 -0
  87. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/constants/SMOKE_STREAM_PROBE_STORE.ts +2 -0
  88. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/constants/index.ts +1 -0
  89. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/entry/index.ts +1 -0
  90. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/entry/kvsStream/index.ts +1 -0
  91. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/entry/kvsStream/onSmokeStreamRecord.ts +33 -0
  92. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/index.ts +5 -0
  93. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/keyValueStoreStreamSmokeSuite.ts +11 -0
  94. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/logic/askRunKeyValueStoreStreamTest.ts +69 -0
  95. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/logic/index.ts +2 -0
  96. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/logic/smokeStreamMarkerId.ts +8 -0
  97. package/template/apps/qpqjs/services/test/service/src/smoke/suites/noop/index.ts +2 -0
  98. package/template/apps/qpqjs/services/test/service/src/smoke/suites/noop/noopSmokeSuite.ts +7 -0
  99. package/template/apps/qpqjs/services/test/service/src/smoke/suites/openApi/config/defineOpenApiSmoke.ts +13 -0
  100. package/template/apps/qpqjs/services/test/service/src/smoke/suites/openApi/config/index.ts +1 -0
  101. package/template/apps/qpqjs/services/test/service/src/smoke/suites/openApi/index.ts +4 -0
  102. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/openApi → suites/openApi/logic}/askRunEchoRoundTripTest.ts +1 -1
  103. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/openApi → suites/openApi/logic}/askRunOpenApiDocumentTest.ts +1 -1
  104. package/template/apps/qpqjs/services/test/service/src/smoke/suites/openApi/openApiSmokeSuite.ts +13 -0
  105. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/config/defineParameterSmoke.ts +11 -0
  106. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/config/index.ts +1 -0
  107. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/constants/SMOKE_PROBE_PARAMETER.ts +2 -0
  108. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/constants/SMOKE_PROBE_PARAMETER_VALUE.ts +2 -0
  109. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/constants/index.ts +2 -0
  110. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/index.ts +4 -0
  111. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/parameter → suites/parameter/logic}/askRunParameterTest.ts +3 -5
  112. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/parameterSmokeSuite.ts +9 -0
  113. package/template/apps/qpqjs/services/test/service/src/{tick/config/defineTick.ts → smoke/suites/schedule/config/defineScheduleSmoke.ts} +1 -1
  114. package/template/apps/qpqjs/services/test/service/src/smoke/suites/schedule/config/index.ts +1 -0
  115. package/template/apps/qpqjs/services/test/service/src/smoke/suites/schedule/entry/index.ts +2 -0
  116. package/template/apps/qpqjs/services/test/service/src/smoke/suites/schedule/index.ts +6 -0
  117. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/schedule → suites/schedule/logic}/askRunScheduleTest.ts +4 -4
  118. package/template/apps/qpqjs/services/test/service/src/smoke/suites/schedule/scheduleSmokeSuite.ts +9 -0
  119. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/config/defineScopedKeyValueStoreSmoke.ts +19 -0
  120. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/config/index.ts +1 -0
  121. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/constants/SMOKE_SCOPED_PROBE_STORE.ts +2 -0
  122. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/constants/index.ts +1 -0
  123. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/index.ts +4 -0
  124. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/logic/askRunScopedKeyValueStoreTest.ts +256 -0
  125. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/logic/index.ts +1 -0
  126. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/scopedKeyValueStoreSmokeSuite.ts +11 -0
  127. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/config/defineScopedStorageDriveSmoke.ts +12 -0
  128. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/config/index.ts +1 -0
  129. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/constants/SMOKE_SCOPED_PROBE_DRIVE.ts +2 -0
  130. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/constants/index.ts +1 -0
  131. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/index.ts +4 -0
  132. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/logic/askRunScopedStorageDriveTest.ts +116 -0
  133. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/logic/index.ts +1 -0
  134. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/scopedStorageDriveSmokeSuite.ts +9 -0
  135. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/config/defineSecretSmoke.ts +8 -0
  136. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/config/index.ts +1 -0
  137. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/constants/SMOKE_PROBE_SECRET.ts +2 -0
  138. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/constants/index.ts +1 -0
  139. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/index.ts +4 -0
  140. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/secret → suites/secret/logic}/askRunSecretTest.ts +2 -2
  141. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/secretSmokeSuite.ts +9 -0
  142. package/template/apps/qpqjs/services/test/service/src/smoke/suites/signingKey/config/defineSigningKeySmoke.ts +12 -0
  143. package/template/apps/qpqjs/services/test/service/src/smoke/suites/signingKey/config/index.ts +1 -0
  144. package/template/apps/qpqjs/services/test/service/src/smoke/suites/signingKey/index.ts +3 -0
  145. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/crossService → suites/signingKey/logic}/askRunCrossServiceSigningKeyTest.ts +1 -1
  146. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/signingKey → suites/signingKey/logic}/askRunSigningKeyTest.ts +1 -1
  147. package/template/apps/qpqjs/services/test/service/src/smoke/suites/signingKey/logic/index.ts +2 -0
  148. package/template/apps/qpqjs/services/test/service/src/smoke/suites/signingKey/signingKeySmokeSuite.ts +16 -0
  149. package/template/apps/qpqjs/services/test/service/src/smoke/suites/smokeSuites.ts +46 -0
  150. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDrive/index.ts +2 -0
  151. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/crossService → suites/storageDrive/logic}/askRunCrossServiceStorageDriveTest.ts +1 -1
  152. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/storageDrive → suites/storageDrive/logic}/askRunStorageDriveTest.ts +1 -1
  153. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDrive/logic/index.ts +2 -0
  154. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDrive/storageDriveSmokeSuite.ts +14 -0
  155. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/config/defineStorageDriveEventSmoke.ts +27 -0
  156. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/config/index.ts +1 -0
  157. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/constants/SMOKE_FILE_EVENT_DRIVE.ts +2 -0
  158. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/constants/SMOKE_SCOPED_FILE_EVENT_DRIVE.ts +2 -0
  159. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/constants/index.ts +2 -0
  160. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/entry/index.ts +1 -0
  161. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/entry/storageDrive/index.ts +1 -0
  162. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/entry/storageDrive/onSmokeFileEvent.ts +38 -0
  163. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/index.ts +5 -0
  164. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/logic/askRunStorageDriveEventTest.ts +78 -0
  165. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/logic/index.ts +2 -0
  166. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/logic/smokeFileEventMarkerId.ts +14 -0
  167. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/storageDriveEventSmokeSuite.ts +9 -0
  168. package/template/apps/qpqjs/services/testa/models/src/CrossServiceProbePayload.ts +1 -1
  169. package/template/apps/qpqjs/services/testa/service/src/infrastructure.ts +2 -2
  170. package/template/apps/qpqjs/services/testa/service/src/smoke/config/defineSmokeProbes.ts +16 -0
  171. package/template/apps/qpqjs/services/testa/service/src/smoke/config/index.ts +1 -0
  172. package/template/apps/qpqjs/services/{test/service/src/tick → testa/service/src/smoke}/index.ts +1 -0
  173. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/index.ts +3 -0
  174. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/keyValueStore/config/defineKeyValueStoreSmokeProbe.ts +33 -0
  175. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/keyValueStore/config/index.ts +1 -0
  176. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/keyValueStore/entry/serviceFunction/index.ts +1 -0
  177. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/keyValueStore/logic/index.ts +1 -0
  178. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/config/defineSigningKeySmokeProbe.ts +28 -0
  179. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/config/index.ts +1 -0
  180. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/entry/index.ts +1 -0
  181. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/entry/serviceFunction/index.ts +1 -0
  182. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/index.ts +3 -0
  183. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/logic/index.ts +1 -0
  184. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/config/defineStorageDriveSmokeProbe.ts +31 -0
  185. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/config/index.ts +1 -0
  186. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/entry/index.ts +1 -0
  187. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/entry/serviceFunction/index.ts +1 -0
  188. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/index.ts +3 -0
  189. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/logic/index.ts +1 -0
  190. package/template/docusaurus/docs/actions/core/file/ask-file-write-text-contents.md +1 -1
  191. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-delete.md +1 -1
  192. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-get-all.md +1 -1
  193. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-get.md +1 -1
  194. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-query.md +3 -1
  195. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-scan.md +1 -1
  196. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-update.md +1 -1
  197. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-upsert.md +1 -1
  198. package/template/docusaurus/docs/actions/core/platform/ask-platform-get-name.md +32 -0
  199. package/template/docusaurus/docs/actions/webserver/email/ask-email-parse.md +54 -0
  200. package/template/docusaurus/docs/config/config-aws/account-email-receiving.md +33 -0
  201. package/template/docusaurus/docs/config/core/crypto-key.md +3 -1
  202. package/template/docusaurus/docs/config/core/key-value-store.md +16 -5
  203. package/template/docusaurus/docs/config/core/storage-drive.md +5 -4
  204. package/template/docusaurus/docs/config/features/event-doc-routes.md +1 -0
  205. package/template/docusaurus/docs/config/features/event-doc.md +22 -1
  206. package/template/docusaurus/docs/config/features/tenant-stores.md +10 -5
  207. package/template/docusaurus/docs/config/features/tenant.md +36 -12
  208. package/template/docusaurus/docs/config/features/tenanted-email-receiver.md +79 -0
  209. package/template/docusaurus/docs/config/features/tenanted-event-doc.md +22 -7
  210. package/template/docusaurus/docs/config/webserver/email-receiver.md +65 -0
  211. package/template/docusaurus/docs/config/webserver/email-receiving-domain.md +41 -0
  212. package/template/scripts/smoke/runSmokeRun.mjs +1 -1
  213. package/template/apps/qpqjs/services/test/service/src/echo/config/defineEcho.ts +0 -9
  214. package/template/apps/qpqjs/services/test/service/src/smoke/constants/smokeProbe.ts +0 -14
  215. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/askStartSmokeRun.ts +0 -70
  216. package/template/apps/qpqjs/services/test/service/src/smoke/models/index.ts +0 -5
  217. package/template/apps/qpqjs/services/test/service/src/smoke/queue/index.ts +0 -3
  218. package/template/apps/qpqjs/services/test/service/src/smoke/tests/crossService/index.ts +0 -3
  219. package/template/apps/qpqjs/services/test/service/src/smoke/tests/eventBus/askRunEventBusTest.ts +0 -57
  220. package/template/apps/qpqjs/services/test/service/src/smoke/tests/index.ts +0 -13
  221. package/template/apps/qpqjs/services/test/service/src/smoke/tests/keyValueStore/index.ts +0 -1
  222. package/template/apps/qpqjs/services/test/service/src/smoke/tests/signingKey/index.ts +0 -1
  223. package/template/apps/qpqjs/services/test/service/src/smoke/tests/smokeTestRegistry.ts +0 -54
  224. package/template/apps/qpqjs/services/test/service/src/smoke/tests/storageDrive/index.ts +0 -1
  225. package/template/apps/qpqjs/services/test/service/src/tick/config/index.ts +0 -1
  226. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/config/defineCrossServiceProbe.ts +0 -68
  227. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/config/index.ts +0 -1
  228. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/entry/serviceFunction/index.ts +0 -3
  229. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/logic/index.ts +0 -3
  230. package/template/docusaurus/docs/config/config-aws/aws-kms-key.md +0 -100
  231. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests → harness/assert}/askSmokeAssert.ts +0 -0
  232. /package/template/apps/qpqjs/services/test/service/src/smoke/{constants → harness/constants}/SMOKE_RUNS_STORE.ts +0 -0
  233. /package/template/apps/qpqjs/services/test/service/src/smoke/{constants → harness/constants}/githubOidc.ts +0 -0
  234. /package/template/apps/qpqjs/services/test/service/src/smoke/{constants → harness/constants}/smokeRunQueue.ts +0 -0
  235. /package/template/apps/qpqjs/services/test/service/src/smoke/{controller → harness/controller}/askGetSmokeRun.ts +0 -0
  236. /package/template/apps/qpqjs/services/test/service/src/smoke/{controller → harness/controller}/askRunSmokeTests.ts +0 -0
  237. /package/template/apps/qpqjs/services/test/service/src/smoke/{controller → harness/controller}/index.ts +0 -0
  238. /package/template/apps/qpqjs/services/test/service/src/smoke/{data → harness/data}/askGetSmokeRunById.ts +0 -0
  239. /package/template/apps/qpqjs/services/test/service/src/smoke/{data → harness/data}/askRecordSmokeTestResult.ts +0 -0
  240. /package/template/apps/qpqjs/services/test/service/src/smoke/{data → harness/data}/askSaveSmokeRun.ts +0 -0
  241. /package/template/apps/qpqjs/services/test/service/src/smoke/{data → harness/data}/askSetSmokeRunOutcome.ts +0 -0
  242. /package/template/apps/qpqjs/services/test/service/src/smoke/{data → harness/data}/index.ts +0 -0
  243. /package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/github/index.ts +0 -0
  244. /package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/github/verifyGithubOidcToken.ts +0 -0
  245. /package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/index.ts +0 -0
  246. /package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/smokeRun/askFindSmokeRun.ts +0 -0
  247. /package/template/apps/qpqjs/services/test/service/src/smoke/{models → harness/models}/GithubOidcClaims.ts +0 -0
  248. /package/template/apps/qpqjs/services/test/service/src/smoke/{processors → harness/processors}/github/getGithubOidcAuthProcessors.ts +0 -0
  249. /package/template/apps/qpqjs/services/test/service/src/smoke/{processors → harness/processors}/github/index.ts +0 -0
  250. /package/template/apps/qpqjs/services/test/service/src/smoke/{processors → harness/processors}/index.ts +0 -0
  251. /package/template/apps/qpqjs/services/test/service/src/smoke/{queue → harness/queue}/onSmokeTestRequested.ts +0 -0
  252. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventBus → suites/eventBus/logic}/index.ts +0 -0
  253. /package/template/apps/qpqjs/services/test/service/src/smoke/{models → suites/eventBus/models}/SmokeProbeEventQueueEvent.ts +0 -0
  254. /package/template/apps/qpqjs/services/test/service/src/smoke/{eventDoc → suites/eventDoc/definition}/index.ts +0 -0
  255. /package/template/apps/qpqjs/services/test/service/src/smoke/{eventDoc → suites/eventDoc/definition}/smokeProbeDocDefinition.ts +0 -0
  256. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/index.ts +0 -0
  257. /package/template/apps/qpqjs/services/test/service/src/smoke/{models → suites/eventDoc/models}/SmokeEventDocAppendQueueEvent.ts +0 -0
  258. /package/template/apps/qpqjs/services/test/service/src/smoke/{models → suites/eventDoc/models}/SmokeEventDocMark.ts +0 -0
  259. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/noop → suites/noop/logic}/askRunNoopTest.ts +0 -0
  260. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/noop → suites/noop/logic}/index.ts +0 -0
  261. /package/template/apps/qpqjs/services/test/service/src/{echo → smoke/suites/openApi}/controller/echo.ts +0 -0
  262. /package/template/apps/qpqjs/services/test/service/src/{echo → smoke/suites/openApi}/controller/index.ts +0 -0
  263. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/openApi → suites/openApi/logic}/index.ts +0 -0
  264. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/parameter → suites/parameter/logic}/index.ts +0 -0
  265. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/constants/index.ts +0 -0
  266. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/constants/scheduleTickName.ts +0 -0
  267. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/constants/scheduleTickStore.ts +0 -0
  268. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/entry/kvsStream/index.ts +0 -0
  269. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/entry/kvsStream/onScheduleTickStream.ts +0 -0
  270. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/entry/schedule/index.ts +0 -0
  271. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/entry/schedule/onTick.ts +0 -0
  272. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/schedule → suites/schedule/logic}/index.ts +0 -0
  273. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/models/ScheduleTickRecord.ts +0 -0
  274. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/models/index.ts +0 -0
  275. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/secret → suites/secret/logic}/index.ts +0 -0
  276. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/keyValueStore}/entry/index.ts +0 -0
  277. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/keyValueStore}/entry/serviceFunction/smokeCrossServiceKeyValueStoreProbe.ts +0 -0
  278. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/keyValueStore}/index.ts +0 -0
  279. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/keyValueStore}/logic/askProbeForeignKeyValueStore.ts +0 -0
  280. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/signingKey}/entry/serviceFunction/smokeCrossServiceSigningKeyProbe.ts +0 -0
  281. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/signingKey}/logic/askProbeForeignSigningKey.ts +0 -0
  282. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/storageDrive}/entry/serviceFunction/smokeCrossServiceStorageDriveProbe.ts +0 -0
  283. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/storageDrive}/logic/askProbeForeignStorageDrive.ts +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-qpq-app",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
4
4
  "description": "Scaffold a new quidproquo app: npx create-qpq-app my-app",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/esm/index.js",
@@ -55,7 +55,7 @@
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/node": "^22.13.13",
58
- "quidproquo-tsconfig": "0.1.25"
58
+ "quidproquo-tsconfig": "0.1.27"
59
59
  },
60
60
  "bin": {
61
61
  "create-qpq-app": "./lib/commonjs/bin/createQpqApp.js"
@@ -103,3 +103,7 @@ npx qpq go # interactive aws deploy: pick app, services, stacks (inf
103
103
  1. Create its `config`, `models`, `x-models`, `shared-logic`, `x-logic`, `service-utils`, and `service` packages.
104
104
  2. Each lib gets a `package.json` with `"build": "tsc -b"` and the dist-pointing `main`, `types`, and `exports`; a `tsconfig.json` (extends the root base, **no paths**, references `./tsconfig.lib.json`); and a `tsconfig.lib.json` (`composite`, `outDir ./dist`, `rootDir .`, with `references` to its workspace deps' `tsconfig.lib.json`). There is no root-level list to touch, since `npm run build --workspaces` discovers the new lib automatically.
105
105
  3. `service/` gets a `package.json` (`@qpqjs/<svc>-service`, `private`, `"build": "tsc -p tsconfig.app.json"`) and a `tsconfig.app.json`. No rspack.config.ts and no bundle script, because `qpq go` bundles it by convention. `npm run build` then picks it up automatically.
106
+
107
+ ## Test
108
+
109
+ Adding a note to test build / deploy - this is a second test.
@@ -7,6 +7,7 @@ import { QPQConfig } from 'quidproquo';
7
7
  import {
8
8
  AwsDataStoreRemovalPolicy,
9
9
  defineAccountBudget,
10
+ defineAccountEmailReceiving,
10
11
  defineAccountGithubOidcProvider,
11
12
  defineAccountSecurityServices,
12
13
  defineAwsDataStoreRemovalPolicy,
@@ -21,6 +22,9 @@ export default (): QPQConfig => [
21
22
  // GitHub Actions OIDC provider, trusted by every app's deploy role in this account.
22
23
  defineAccountGithubOidcProvider(),
23
24
 
25
+ // The one active SES receipt rule set; every app's inbound-email rules live in it.
26
+ defineAccountEmailReceiving(),
27
+
24
28
  defineAccountSecurityServices({
25
29
  // GuardDuty is org-managed for this account
26
30
  // (delegated admin 816650600287 auto-enables detectors - a stack-created one
@@ -2,7 +2,12 @@
2
2
  // domain certificates. The identity plumbing (defineApplication +
3
3
  // defineAwsServiceAccountInfo) is provided by quidproquo-deploy-awscdk's
4
4
  // workspace CDK app; this fragment must not declare its own.
5
- import { defineApi, defineDns, QPQConfig } from 'quidproquo';
5
+ import {
6
+ defineApi,
7
+ defineDns,
8
+ defineEmailReceivingDomain,
9
+ QPQConfig,
10
+ } from 'quidproquo';
6
11
  import {
7
12
  defineAwsGithubDeployRole,
8
13
  defineBootstrapWaf,
@@ -17,8 +22,14 @@ import { QPQJS_DOMAINS, QpqjsServiceEnum } from '@qpqjs/constants';
17
22
  export default ({ region }: QpqAppDeployContext): QPQConfig => [
18
23
  defineDns(QPQJS_DOMAINS),
19
24
 
25
+ // inbox.<env>.<root>: verified with SES and MX-routed to it, for every defineEmailReceiver.
26
+ defineEmailReceivingDomain('inbox'),
27
+
20
28
  // The role the deploy workflow assumes (ids from `gh api repos/qpqjs/quidproquo`).
21
- defineAwsGithubDeployRole('qpqjs/quidproquo', { ownerId: 314167689, repositoryId: 571382961 }),
29
+ defineAwsGithubDeployRole('qpqjs/quidproquo', {
30
+ ownerId: 314167689,
31
+ repositoryId: 571382961,
32
+ }),
22
33
 
23
34
  defineBootstrapWaf({
24
35
  rateLimits: [{ name: 'all-traffic', limit: 2000 }],
@@ -6,6 +6,7 @@ import {
6
6
  defineCache,
7
7
  defineDefaultRouteOptions,
8
8
  defineDns,
9
+ defineEmailReceivingDomain,
9
10
  defineFrontendBundleOptions,
10
11
  QPQConfig,
11
12
  } from 'quidproquo';
@@ -59,6 +60,9 @@ export const defineQpqjsService = (
59
60
  ),
60
61
 
61
62
  defineDns(QPQJS_DOMAINS),
63
+ // Same domain bootstrap.qpq.ts declares: bootstrap owns the records, a service's
64
+ // defineEmailReceiver resolves its recipients from it.
65
+ defineEmailReceivingDomain('inbox'),
62
66
 
63
67
  defineAdminUserDirectory({
64
68
  owner: {
@@ -5,4 +5,16 @@ export type SmokeProbeRecord = {
5
5
  probeId: string;
6
6
  category: string;
7
7
  value: number;
8
+
9
+ // Set by the storage drive event and kvs stream handlers: what the event
10
+ // said its scope and path/key were, and (for file events) the ambient
11
+ // storage scope the handler ran under, so a test can prove both agree.
12
+ scope?: string;
13
+ ambientScope?: string;
14
+ path?: string;
15
+ // Set by the kvs stream handler: the attribute names on the record's image,
16
+ // so a test can prove no backend bookkeeping attribute reaches a handler.
17
+ imageAttributes?: string[];
18
+ // Set by the email handler: the provider's spf/dkim verdicts on the message.
19
+ authentication?: string;
8
20
  };
@@ -4,9 +4,16 @@ import { z } from 'zod/v4';
4
4
  // cannot drift from the entries themselves.
5
5
  export const SmokeRunSummarySchema = z.object({
6
6
  total: z.int().nonnegative().describe('Tests registered for the run'),
7
- completed: z.int().nonnegative().describe('Tests that have passed or failed'),
7
+ completed: z
8
+ .int()
9
+ .nonnegative()
10
+ .describe('Tests that have passed, failed or been skipped'),
8
11
  passed: z.int().nonnegative(),
9
12
  failed: z.int().nonnegative(),
13
+ skipped: z
14
+ .int()
15
+ .nonnegative()
16
+ .describe('Deployed-only tests not run on this platform'),
10
17
  });
11
18
 
12
19
  export type SmokeRunSummary = z.infer<typeof SmokeRunSummarySchema>;
@@ -3,4 +3,6 @@ export enum SmokeTestStatus {
3
3
  running = 'running',
4
4
  passed = 'passed',
5
5
  failed = 'failed',
6
+ // Deployed-only test on a platform with no equivalent; never queued, never counts either way.
7
+ skipped = 'skipped',
6
8
  }
@@ -3,9 +3,7 @@ import { defineDevServerOptions } from 'quidproquo-dev-server/config';
3
3
  import { QpqjsServiceEnum } from '@qpqjs/constants';
4
4
  import { defineQpqjsService } from '@qpqjs/service-utils';
5
5
 
6
- import { defineEcho } from './echo/config/defineEcho';
7
6
  import { defineSmoke } from './smoke/config/defineSmoke';
8
- import { defineTick } from './tick/config/defineTick';
9
7
 
10
8
  export default [
11
9
  defineDevServerOptions({ port: 3083 }),
@@ -18,8 +16,4 @@ export default [
18
16
  ),
19
17
 
20
18
  defineSmoke(),
21
-
22
- defineEcho(),
23
-
24
- defineTick(),
25
19
  ];
@@ -1,176 +1,10 @@
1
- import {
2
- defineEventBus,
3
- defineKeyValueStore,
4
- defineParameter,
5
- defineQueue,
6
- defineRoute,
7
- defineSecret,
8
- defineSigningKey,
9
- defineStorageDrive,
10
- QPQConfig,
11
- QpqFunctionRuntime,
12
- } from 'quidproquo';
13
- import { defineEventDoc } from 'quidproquo-features';
1
+ import { QPQConfig } from 'quidproquo';
14
2
 
15
- import { z } from 'zod/v4';
16
- import {
17
- SMOKE_PROBE_DRIVE,
18
- SMOKE_PROBE_SIGNING_KEY,
19
- SMOKE_PROBE_STORE,
20
- } from '@qpqjs/constants';
21
- import {
22
- SmokeProbeRecord,
23
- SmokeRunStartedSchema,
24
- SmokeRunWithSummarySchema,
25
- } from '@qpqjs/test-models';
3
+ import { defineSmokeHarness } from '../harness/config/defineSmokeHarness';
4
+ import { smokeSuites } from '../suites/smokeSuites';
26
5
 
27
- import { SMOKE_RUNS_STORE } from '../constants/SMOKE_RUNS_STORE';
28
- import {
29
- SMOKE_EVENT_DOC_APPEND_MESSAGE_TYPE,
30
- SMOKE_EVENT_DOC_APPEND_QUEUE,
31
- SMOKE_EVENT_DOC_BASE_PATH,
32
- } from '../constants/smokeEventDoc';
33
- import {
34
- SMOKE_PROBE_EVENT_BUS,
35
- SMOKE_PROBE_EVENT_QUEUE,
36
- SMOKE_PROBE_EVENT_TYPE,
37
- SMOKE_PROBE_PARAMETER,
38
- SMOKE_PROBE_PARAMETER_VALUE,
39
- SMOKE_PROBE_SECRET,
40
- } from '../constants/smokeProbe';
41
- import {
42
- SMOKE_RUN_QUEUE,
43
- SMOKE_TEST_REQUESTED_MESSAGE_TYPE,
44
- } from '../constants/smokeRunQueue';
45
- import { smokeProbeDocDefinition } from '../eventDoc/smokeProbeDocDefinition';
46
-
47
- // Everything the smoke feature needs: the run store, the queue runs execute
48
- // on, and the two routes. Runtimes are located relative to this file, so the
49
- // module can move as a unit.
50
- //
51
- // The routes look public (no user directory, no api keys) but carry a
52
- // per-runtime action processor override that swaps the route auth decode for
53
- // the GitHub OIDC validator - so ONLY a GitHub Actions run of our repo,
54
- // holding an OIDC token with the qpq-smoke audience and matching pinned
55
- // claims, gets past the preamble. Everything else 401s, tokenless included.
56
- export const defineSmoke = (): QPQConfig => {
57
- const githubOidcAuth: QpqFunctionRuntime[] = [
58
- {
59
- basePath: __dirname,
60
- relativePath: '../processors/github/getGithubOidcAuthProcessors',
61
- functionName: 'getGithubOidcAuthProcessors',
62
- },
63
- ];
64
-
65
- return [
66
- // One record per run, keyed by runId; the queue workers each write their
67
- // own test's entry as it completes and the GET route polls it.
68
- defineKeyValueStore(SMOKE_RUNS_STORE, 'runId'),
69
-
70
- // One message per test per run. Not FIFO and no concurrency cap, so the
71
- // tests of a run fan out and execute in parallel.
72
- defineQueue(SMOKE_RUN_QUEUE, {
73
- [SMOKE_TEST_REQUESTED_MESSAGE_TYPE]: {
74
- basePath: __dirname,
75
- relativePath: '../queue/onSmokeTestRequested',
76
- functionName: 'onSmokeTestRequested',
77
- },
78
- }),
79
-
80
- // Throwaway probe resources, one per kind of owned resource the tag-based
81
- // IAM grants cover. The store's `category` index is what the KVS test
82
- // queries through, proving the `table/*/index/*` half of the grant.
83
- defineKeyValueStore<SmokeProbeRecord>(SMOKE_PROBE_STORE, 'probeId', [], {
84
- indexes: ['category'],
85
- }),
86
- defineParameter(SMOKE_PROBE_PARAMETER, {
87
- value: SMOKE_PROBE_PARAMETER_VALUE,
88
- }),
89
- defineSecret(SMOKE_PROBE_SECRET),
90
- defineStorageDrive(SMOKE_PROBE_DRIVE),
91
- // An owned RSA signing key: kms:Sign + kms:GetPublicKey through the
92
- // alias-conditioned grant. testa declares the same key foreign (see
93
- // defineCrossServiceProbe) for the cross-service verify test.
94
- defineSigningKey(SMOKE_PROBE_SIGNING_KEY),
95
-
96
- // Event bus test path: publish to the bus, the subscribed queue's entry
97
- // writes a marker into the probe store, the test polls for it.
98
- defineEventBus(SMOKE_PROBE_EVENT_BUS),
99
- defineQueue(
100
- SMOKE_PROBE_EVENT_QUEUE,
101
- {
102
- [SMOKE_PROBE_EVENT_TYPE]: {
103
- basePath: __dirname,
104
- relativePath: '../queue/onSmokeProbeEvent',
105
- functionName: 'onSmokeProbeEvent',
106
- },
107
- },
108
- { eventBusSubscriptions: [SMOKE_PROBE_EVENT_BUS] }
109
- ),
110
-
111
- // The event-doc probe collection: a full registered collection (stores, stream
112
- // projector, dynamic functions, routes) so the smoke tests exercise event docs the
113
- // way a real service does. NOTE the routes mount with no auth - the test service
114
- // has no user directory - so the collection is world-writable; it holds nothing
115
- // but throwaway probe docs. The queue fans a test's writers out one invocation
116
- // each, so their appends race across lambdas.
117
- defineEventDoc(
118
- smokeProbeDocDefinition,
119
- {
120
- basePath: __dirname,
121
- relativePath: '../eventDoc/smokeProbeDocDefinition',
122
- functionName: 'smokeProbeDocDefinition',
123
- },
124
- { basePath: SMOKE_EVENT_DOC_BASE_PATH }
125
- ),
126
- defineQueue(SMOKE_EVENT_DOC_APPEND_QUEUE, {
127
- [SMOKE_EVENT_DOC_APPEND_MESSAGE_TYPE]: {
128
- basePath: __dirname,
129
- relativePath: '../queue/onSmokeEventDocAppend',
130
- functionName: 'onSmokeEventDocAppend',
131
- },
132
- }),
133
-
134
- // The zod models double as the routes' published contract, flattened to
135
- // JSON Schema here for the OpenAPI document at /v1/docs.
136
- defineRoute(
137
- 'POST',
138
- '/smoke/run',
139
- {
140
- basePath: __dirname,
141
- relativePath: '../controller/askRunSmokeTests',
142
- functionName: 'askRunSmokeTests',
143
- actionProcessors: githubOidcAuth,
144
- },
145
- {
146
- schema: {
147
- summary: 'Start a smoke run',
148
- description:
149
- 'Queues every registered smoke test and returns the run id to poll. Requires a GitHub Actions OIDC token for this repo.',
150
- tags: ['smoke'],
151
- responseJsonSchema: z.toJSONSchema(SmokeRunStartedSchema),
152
- },
153
- }
154
- ),
155
-
156
- defineRoute(
157
- 'GET',
158
- '/smoke/run/{runId}',
159
- {
160
- basePath: __dirname,
161
- relativePath: '../controller/askGetSmokeRun',
162
- functionName: 'askGetSmokeRun',
163
- actionProcessors: githubOidcAuth,
164
- },
165
- {
166
- schema: {
167
- summary: 'Get a smoke run',
168
- description:
169
- 'The stored run plus pass/fail counts. Poll until status leaves running.',
170
- tags: ['smoke'],
171
- responseJsonSchema: z.toJSONSchema(SmokeRunWithSummarySchema),
172
- },
173
- }
174
- ),
175
- ];
176
- };
6
+ /** The whole smoke feature: the harness plus the resources of every registered suite. */
7
+ export const defineSmoke = (): QPQConfig => [
8
+ defineSmokeHarness(),
9
+ smokeSuites.map((suite) => suite.defineConfig?.() ?? []),
10
+ ];
@@ -0,0 +1,44 @@
1
+ import {
2
+ askDelay,
3
+ askKeyValueStoreDelete,
4
+ askKeyValueStoreGet,
5
+ AskResponse,
6
+ Nullable,
7
+ } from 'quidproquo';
8
+
9
+ import { SMOKE_PROBE_STORE } from '@qpqjs/constants';
10
+ import { SmokeProbeRecord } from '@qpqjs/test-models';
11
+
12
+ import { askSmokeAssert } from './askSmokeAssert';
13
+
14
+ const POLL_ATTEMPTS = 15;
15
+ const POLL_INTERVAL_MS = 2000;
16
+
17
+ // Fan-in for every async probe: polls the probe store for the marker row an
18
+ // event handler writes, fails the test if it never arrives, and removes it
19
+ // so a rerun starts clean. The default wait covers the dev server's file
20
+ // watcher settle window and S3 / stream delivery latency; a slower path
21
+ // (mail delivery) asks for more attempts.
22
+ export function* askSmokePollForMarker(
23
+ markerId: string,
24
+ via: string,
25
+ attempts: number = POLL_ATTEMPTS
26
+ ): AskResponse<SmokeProbeRecord> {
27
+ let marker: Nullable<SmokeProbeRecord> = null;
28
+ for (let attempt = 0; attempt < attempts && !marker; attempt += 1) {
29
+ yield* askDelay(POLL_INTERVAL_MS);
30
+ marker = yield* askKeyValueStoreGet<SmokeProbeRecord>(
31
+ SMOKE_PROBE_STORE,
32
+ markerId
33
+ );
34
+ }
35
+
36
+ yield* askSmokeAssert(
37
+ !!marker,
38
+ `marker [${markerId}] never arrived via ${via}`
39
+ );
40
+
41
+ yield* askKeyValueStoreDelete(SMOKE_PROBE_STORE, markerId);
42
+
43
+ return marker!;
44
+ }
@@ -0,0 +1,2 @@
1
+ export * from './askSmokeAssert';
2
+ export * from './askSmokePollForMarker';
@@ -0,0 +1,115 @@
1
+ import {
2
+ defineKeyValueStore,
3
+ defineQueue,
4
+ defineRoute,
5
+ defineStorageDrive,
6
+ QPQConfig,
7
+ QpqFunctionRuntime,
8
+ } from 'quidproquo';
9
+
10
+ import { z } from 'zod/v4';
11
+ import { SMOKE_PROBE_DRIVE, SMOKE_PROBE_STORE } from '@qpqjs/constants';
12
+ import {
13
+ SmokeProbeRecord,
14
+ SmokeRunStartedSchema,
15
+ SmokeRunWithSummarySchema,
16
+ } from '@qpqjs/test-models';
17
+
18
+ import { SMOKE_RUNS_STORE } from '../constants/SMOKE_RUNS_STORE';
19
+ import {
20
+ SMOKE_RUN_QUEUE,
21
+ SMOKE_TEST_REQUESTED_MESSAGE_TYPE,
22
+ } from '../constants/smokeRunQueue';
23
+
24
+ /**
25
+ * The part of the smoke feature every suite relies on: the run store, the
26
+ * queue runs execute on, the shared probe store and drive, and the two
27
+ * routes. Knows nothing about individual suites; defineSmoke adds theirs
28
+ * alongside.
29
+ *
30
+ * The routes look public (no user directory, no api keys) but carry a
31
+ * per-runtime action processor override that swaps the route auth decode for
32
+ * the GitHub OIDC validator, so ONLY a GitHub Actions run of our repo holding
33
+ * an OIDC token with the qpq-smoke audience and matching pinned claims gets
34
+ * past the preamble. Everything else 401s, tokenless included.
35
+ */
36
+ export const defineSmokeHarness = (): QPQConfig => {
37
+ const githubOidcAuth: QpqFunctionRuntime[] = [
38
+ {
39
+ basePath: __dirname,
40
+ relativePath: '../processors/github/getGithubOidcAuthProcessors',
41
+ functionName: 'getGithubOidcAuthProcessors',
42
+ },
43
+ ];
44
+
45
+ return [
46
+ // One record per run, keyed by runId; the queue workers each write their
47
+ // own test's entry as it completes and the GET route polls it.
48
+ defineKeyValueStore(SMOKE_RUNS_STORE, 'runId'),
49
+
50
+ // One message per test per run. Not FIFO and no concurrency cap, so the
51
+ // tests of a run fan out and execute in parallel.
52
+ defineQueue(SMOKE_RUN_QUEUE, {
53
+ [SMOKE_TEST_REQUESTED_MESSAGE_TYPE]: {
54
+ basePath: __dirname,
55
+ relativePath: '../queue/onSmokeTestRequested',
56
+ functionName: 'onSmokeTestRequested',
57
+ },
58
+ }),
59
+
60
+ // Every async suite's handler writes its marker here for
61
+ // askSmokePollForMarker. The keyValueStore suite queries its `category`
62
+ // index, proving the `table/*/index/*` half of the tag-conditioned grant,
63
+ // and testa reaches it cross-service.
64
+ defineKeyValueStore<SmokeProbeRecord>(SMOKE_PROBE_STORE, 'probeId', [], {
65
+ indexes: ['category'],
66
+ }),
67
+
68
+ // The unscoped probe drive: the storageDrive suite's subject, testa's
69
+ // cross-service target, and the drive the scopedStorageDrive suite proves
70
+ // refuses a scope.
71
+ defineStorageDrive(SMOKE_PROBE_DRIVE),
72
+
73
+ // The zod models double as the routes' published contract, flattened to
74
+ // JSON Schema here for the OpenAPI document at /v1/docs.
75
+ defineRoute(
76
+ 'POST',
77
+ '/smoke/run',
78
+ {
79
+ basePath: __dirname,
80
+ relativePath: '../controller/askRunSmokeTests',
81
+ functionName: 'askRunSmokeTests',
82
+ actionProcessors: githubOidcAuth,
83
+ },
84
+ {
85
+ schema: {
86
+ summary: 'Start a smoke run',
87
+ description:
88
+ 'Queues every registered smoke test and returns the run id to poll. Requires a GitHub Actions OIDC token for this repo.',
89
+ tags: ['smoke'],
90
+ responseJsonSchema: z.toJSONSchema(SmokeRunStartedSchema),
91
+ },
92
+ }
93
+ ),
94
+
95
+ defineRoute(
96
+ 'GET',
97
+ '/smoke/run/{runId}',
98
+ {
99
+ basePath: __dirname,
100
+ relativePath: '../controller/askGetSmokeRun',
101
+ functionName: 'askGetSmokeRun',
102
+ actionProcessors: githubOidcAuth,
103
+ },
104
+ {
105
+ schema: {
106
+ summary: 'Get a smoke run',
107
+ description:
108
+ 'The stored run plus pass/fail counts. Poll until status leaves running.',
109
+ tags: ['smoke'],
110
+ responseJsonSchema: z.toJSONSchema(SmokeRunWithSummarySchema),
111
+ },
112
+ }
113
+ ),
114
+ ];
115
+ };
@@ -0,0 +1 @@
1
+ export * from './defineSmokeHarness';
@@ -1,5 +1,3 @@
1
1
  export * from './githubOidc';
2
2
  export * from './SMOKE_RUNS_STORE';
3
- export * from './smokeEventDoc';
4
- export * from './smokeProbe';
5
3
  export * from './smokeRunQueue';
@@ -0,0 +1,10 @@
1
+ export * from './assert';
2
+ export * from './config';
3
+ export * from './constants';
4
+ export * from './controller';
5
+ export * from './data';
6
+ export * from './logic';
7
+ export * from './models';
8
+ export * from './processors';
9
+ export * from './queue';
10
+ export * from './types';
@@ -16,8 +16,8 @@ import {
16
16
  import { askGetSmokeRunById } from '../../data/askGetSmokeRunById';
17
17
  import { askRecordSmokeTestResult } from '../../data/askRecordSmokeTestResult';
18
18
  import { askSetSmokeRunOutcome } from '../../data/askSetSmokeRunOutcome';
19
- import { SmokeTestDefinition } from '../../tests/SmokeTestDefinition';
20
- import { smokeTestRegistry } from '../../tests/smokeTestRegistry';
19
+ import { SmokeTestDefinition } from '../../types/SmokeTestDefinition';
20
+ import { listSmokeTests } from './listSmokeTests';
21
21
 
22
22
  // Runs one registered test, returning its completed result entry.
23
23
  function* askRunSmokeTest(
@@ -40,7 +40,8 @@ function* askRunSmokeTest(
40
40
 
41
41
  const isTerminal = (result: SmokeTestResult): boolean =>
42
42
  result.status === SmokeTestStatus.passed ||
43
- result.status === SmokeTestStatus.failed;
43
+ result.status === SmokeTestStatus.failed ||
44
+ result.status === SmokeTestStatus.skipped;
44
45
 
45
46
  // Executes one registered test for an existing run (created by
46
47
  // askStartSmokeRun) and records its result. Every test of a run executes
@@ -52,7 +53,7 @@ export function* askExecuteSmokeTest(
52
53
  runId: string,
53
54
  testName: string
54
55
  ): AskResponse<SmokeRun> {
55
- const test = smokeTestRegistry.find((t) => t.name === testName);
56
+ const test = listSmokeTests().find((t) => t.name === testName);
56
57
  if (!test) {
57
58
  return yield* askThrowError(
58
59
  ErrorTypeEnum.NotFound,
@@ -86,7 +87,7 @@ export function* askExecuteSmokeTest(
86
87
 
87
88
  const finishedAt = yield* askDateNow();
88
89
  const anyFailed = recorded.tests.some(
89
- (t) => t.status !== SmokeTestStatus.passed
90
+ (t) => t.status === SmokeTestStatus.failed
90
91
  );
91
92
 
92
93
  return yield* askSetSmokeRunOutcome(
@@ -0,0 +1,85 @@
1
+ import {
2
+ askDateNow,
3
+ askNewGuid,
4
+ askPlatformGetName,
5
+ askQueueSendMessages,
6
+ AskResponse,
7
+ QueueMessage,
8
+ } from 'quidproquo';
9
+
10
+ import {
11
+ SmokeRun,
12
+ SmokeRunStatus,
13
+ SmokeTestResult,
14
+ SmokeTestStatus,
15
+ } from '@qpqjs/test-models';
16
+
17
+ import {
18
+ SMOKE_RUN_QUEUE,
19
+ SMOKE_TEST_REQUESTED_MESSAGE_TYPE,
20
+ } from '../../constants/smokeRunQueue';
21
+ import { askSaveSmokeRun } from '../../data/askSaveSmokeRun';
22
+ import { SmokeTestRequestedPayload } from '../../models/SmokeTestRequestedQueueEvent';
23
+ import { SmokeTestDefinition } from '../../types/SmokeTestDefinition';
24
+ import { listSmokeTests } from './listSmokeTests';
25
+
26
+ const createInitialResult = (
27
+ test: SmokeTestDefinition,
28
+ index: number,
29
+ skip: boolean
30
+ ): SmokeTestResult => ({
31
+ id: index + 1,
32
+ name: test.name,
33
+ status: skip ? SmokeTestStatus.skipped : SmokeTestStatus.pending,
34
+ message: skip ? 'deployed only' : '',
35
+ startedAt: null,
36
+ finishedAt: null,
37
+ });
38
+
39
+ const createTestRequestedMessage = (
40
+ runId: string,
41
+ test: SmokeTestDefinition
42
+ ): QueueMessage<SmokeTestRequestedPayload> => ({
43
+ type: SMOKE_TEST_REQUESTED_MESSAGE_TYPE,
44
+ payload: { runId, testName: test.name },
45
+ });
46
+
47
+ // Creates the run record with every registered test pending (or skipped, for
48
+ // a deployed-only test on the dev server), then sends one queue message per
49
+ // pending test so they execute in parallel. The record exists before the
50
+ // messages are sent so a poll (or a worker) that races the queue still finds
51
+ // it. A run of nothing but skips never gets a worker, so it is finished here.
52
+ export function* askStartSmokeRun(): AskResponse<SmokeRun> {
53
+ const runId = yield* askNewGuid();
54
+ const startedAt = yield* askDateNow();
55
+ const platformName = yield* askPlatformGetName();
56
+
57
+ const shouldSkip = (test: SmokeTestDefinition): boolean =>
58
+ !!test.deployedOnly && platformName === 'devServer';
59
+
60
+ const smokeTests = listSmokeTests();
61
+ const queued = smokeTests.filter((test) => !shouldSkip(test));
62
+
63
+ const smokeRun: SmokeRun = {
64
+ runId,
65
+ status:
66
+ queued.length === 0 ? SmokeRunStatus.passed : SmokeRunStatus.running,
67
+ startedAt,
68
+ finishedAt: queued.length === 0 ? startedAt : null,
69
+ tests: smokeTests.map((test, index) =>
70
+ createInitialResult(test, index, shouldSkip(test))
71
+ ),
72
+ };
73
+
74
+ yield* askSaveSmokeRun(smokeRun);
75
+
76
+ const messages = queued.map((test) =>
77
+ createTestRequestedMessage(runId, test)
78
+ );
79
+
80
+ if (messages.length > 0) {
81
+ yield* askQueueSendMessages(SMOKE_RUN_QUEUE, ...messages);
82
+ }
83
+
84
+ return smokeRun;
85
+ }
@@ -1,4 +1,5 @@
1
1
  export * from './askExecuteSmokeTest';
2
2
  export * from './askFindSmokeRun';
3
3
  export * from './askStartSmokeRun';
4
+ export * from './listSmokeTests';
4
5
  export * from './summarizeSmokeRun';
@@ -0,0 +1,6 @@
1
+ import { smokeSuites } from '../../../suites/smokeSuites';
2
+ import { SmokeTestDefinition } from '../../types/SmokeTestDefinition';
3
+
4
+ /** Every registered test across all suites, in list order; a test's 1-based position is its run record id. */
5
+ export const listSmokeTests = (): SmokeTestDefinition[] =>
6
+ smokeSuites.flatMap((suite) => suite.tests);