create-qpq-app 0.1.26 → 0.1.28

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 (379) hide show
  1. package/README.md +4 -0
  2. package/lib/commonjs/cli/runCreateQpqApp.js +15 -1
  3. package/lib/commonjs/cli/runCreateQpqApp.js.map +1 -1
  4. package/lib/commonjs/lib/index.d.ts +1 -1
  5. package/lib/commonjs/lib/index.js +1 -1
  6. package/lib/commonjs/lib/index.js.map +1 -1
  7. package/lib/commonjs/lib/promptText.d.ts +1 -0
  8. package/lib/commonjs/lib/promptText.js +53 -0
  9. package/lib/commonjs/lib/promptText.js.map +1 -0
  10. package/lib/commonjs/steps/005_applyAppIdentity.js +6 -5
  11. package/lib/commonjs/steps/005_applyAppIdentity.js.map +1 -1
  12. package/lib/commonjs/steps/006_applyDomain.js +11 -6
  13. package/lib/commonjs/steps/006_applyDomain.js.map +1 -1
  14. package/lib/commonjs/steps/007_applyDockerHost.d.ts +2 -0
  15. package/lib/commonjs/steps/007_applyDockerHost.js +40 -0
  16. package/lib/commonjs/steps/007_applyDockerHost.js.map +1 -0
  17. package/lib/commonjs/steps/{007_pinRegistryVersions.js → 008_pinRegistryVersions.js} +1 -1
  18. package/lib/commonjs/steps/{007_pinRegistryVersions.js.map → 008_pinRegistryVersions.js.map} +1 -1
  19. package/lib/commonjs/steps/{008_transpileToJavaScript.js → 009_transpileToJavaScript.js} +1 -1
  20. package/lib/commonjs/steps/{008_transpileToJavaScript.js.map → 009_transpileToJavaScript.js.map} +1 -1
  21. package/lib/commonjs/steps/{009_restoreGitignore.js → 010_restoreGitignore.js} +1 -1
  22. package/lib/commonjs/steps/{009_restoreGitignore.js.map → 010_restoreGitignore.js.map} +1 -1
  23. package/lib/commonjs/steps/{010_gitInit.js → 011_gitInit.js} +1 -1
  24. package/lib/commonjs/steps/{010_gitInit.js.map → 011_gitInit.js.map} +1 -1
  25. package/lib/commonjs/steps/{011_npmInstall.js → 012_npmInstall.js} +1 -1
  26. package/lib/commonjs/steps/{011_npmInstall.js.map → 012_npmInstall.js.map} +1 -1
  27. package/lib/commonjs/steps/{012_buildWorkspaces.js → 013_buildWorkspaces.js} +1 -1
  28. package/lib/commonjs/steps/{012_buildWorkspaces.js.map → 013_buildWorkspaces.js.map} +1 -1
  29. package/lib/commonjs/steps/{013_printNextSteps.js → 014_printNextSteps.js} +6 -3
  30. package/lib/commonjs/steps/014_printNextSteps.js.map +1 -0
  31. package/lib/commonjs/steps/index.d.ts +9 -8
  32. package/lib/commonjs/steps/index.js +25 -22
  33. package/lib/commonjs/steps/index.js.map +1 -1
  34. package/lib/commonjs/types/CreateQpqAppAnswers.d.ts +2 -0
  35. package/lib/commonjs/types/CreateQpqAppAnswers.js.map +1 -1
  36. package/lib/esm/cli/runCreateQpqApp.js +15 -1
  37. package/lib/esm/cli/runCreateQpqApp.js.map +1 -1
  38. package/lib/esm/lib/index.d.ts +1 -1
  39. package/lib/esm/lib/index.js +1 -1
  40. package/lib/esm/lib/index.js.map +1 -1
  41. package/lib/esm/lib/promptText.d.ts +1 -0
  42. package/lib/esm/lib/promptText.js +7 -0
  43. package/lib/esm/lib/promptText.js.map +1 -0
  44. package/lib/esm/steps/005_applyAppIdentity.js +6 -5
  45. package/lib/esm/steps/005_applyAppIdentity.js.map +1 -1
  46. package/lib/esm/steps/006_applyDomain.js +11 -6
  47. package/lib/esm/steps/006_applyDomain.js.map +1 -1
  48. package/lib/esm/steps/007_applyDockerHost.d.ts +2 -0
  49. package/lib/esm/steps/007_applyDockerHost.js +30 -0
  50. package/lib/esm/steps/007_applyDockerHost.js.map +1 -0
  51. package/lib/esm/steps/{007_pinRegistryVersions.js → 008_pinRegistryVersions.js} +1 -1
  52. package/lib/esm/steps/{007_pinRegistryVersions.js.map → 008_pinRegistryVersions.js.map} +1 -1
  53. package/lib/esm/steps/{008_transpileToJavaScript.js → 009_transpileToJavaScript.js} +1 -1
  54. package/lib/esm/steps/{008_transpileToJavaScript.js.map → 009_transpileToJavaScript.js.map} +1 -1
  55. package/lib/esm/steps/{009_restoreGitignore.js → 010_restoreGitignore.js} +1 -1
  56. package/lib/esm/steps/{009_restoreGitignore.js.map → 010_restoreGitignore.js.map} +1 -1
  57. package/lib/esm/steps/{010_gitInit.js → 011_gitInit.js} +1 -1
  58. package/lib/esm/steps/{010_gitInit.js.map → 011_gitInit.js.map} +1 -1
  59. package/lib/esm/steps/{011_npmInstall.js → 012_npmInstall.js} +1 -1
  60. package/lib/esm/steps/{011_npmInstall.js.map → 012_npmInstall.js.map} +1 -1
  61. package/lib/esm/steps/{012_buildWorkspaces.js → 013_buildWorkspaces.js} +1 -1
  62. package/lib/esm/steps/{012_buildWorkspaces.js.map → 013_buildWorkspaces.js.map} +1 -1
  63. package/lib/esm/steps/014_printNextSteps.js +24 -0
  64. package/lib/esm/steps/014_printNextSteps.js.map +1 -0
  65. package/lib/esm/steps/index.d.ts +9 -8
  66. package/lib/esm/steps/index.js +10 -8
  67. package/lib/esm/steps/index.js.map +1 -1
  68. package/lib/esm/types/CreateQpqAppAnswers.d.ts +2 -0
  69. package/lib/esm/types/CreateQpqAppAnswers.js.map +1 -1
  70. package/package.json +2 -2
  71. package/template/README.md +4 -3
  72. package/template/apps/qpqjs/bootstrap.qpq.ts +3 -2
  73. package/template/apps/qpqjs/deploy.config.json +42 -9
  74. package/template/apps/qpqjs/devServer.config.ts +13 -0
  75. package/template/apps/qpqjs/packages/constants/src/index.ts +0 -1
  76. package/template/apps/qpqjs/packages/service-utils/src/defineQpqjsService.ts +12 -29
  77. package/template/apps/qpqjs/services/admin/service/src/infrastructure.ts +1 -1
  78. package/template/apps/qpqjs/services/admin/views/src/app/app.tsx +9 -19
  79. package/template/apps/qpqjs/services/design/service/src/infrastructure.ts +1 -1
  80. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/NavBar.tsx +2 -10
  81. package/template/apps/qpqjs/services/design/views/src/components/WelcomeScreen/WelcomeScreen.tsx +3 -11
  82. package/template/apps/qpqjs/services/shell/service/src/infrastructure.ts +5 -1
  83. package/template/apps/qpqjs/services/test/models/src/SmokeProbeRecord.ts +3 -0
  84. package/template/apps/qpqjs/services/test/service/src/infrastructure.ts +1 -7
  85. package/template/apps/qpqjs/services/test/service/src/smoke/config/defineSmoke.ts +8 -264
  86. package/template/apps/qpqjs/services/test/service/src/smoke/harness/assert/index.ts +2 -0
  87. package/template/apps/qpqjs/services/test/service/src/smoke/harness/config/defineSmokeHarness.ts +115 -0
  88. package/template/apps/qpqjs/services/test/service/src/smoke/harness/config/index.ts +1 -0
  89. package/template/apps/qpqjs/services/test/service/src/smoke/{constants → harness/constants}/index.ts +0 -2
  90. package/template/apps/qpqjs/services/test/service/src/smoke/harness/index.ts +10 -0
  91. package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/smokeRun/askExecuteSmokeTest.ts +3 -3
  92. package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/smokeRun/askStartSmokeRun.ts +5 -4
  93. package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/smokeRun/index.ts +1 -0
  94. package/template/apps/qpqjs/services/test/service/src/smoke/harness/logic/smokeRun/listSmokeTests.ts +6 -0
  95. package/template/apps/qpqjs/services/test/service/src/smoke/{models → harness/models}/SmokeTestRequestedQueueEvent.ts +1 -1
  96. package/template/apps/qpqjs/services/test/service/src/smoke/harness/models/index.ts +2 -0
  97. package/template/apps/qpqjs/services/test/service/src/smoke/harness/queue/index.ts +1 -0
  98. package/template/apps/qpqjs/services/test/service/src/smoke/harness/types/SmokeSuite.ts +13 -0
  99. package/template/apps/qpqjs/services/test/service/src/smoke/harness/types/index.ts +2 -0
  100. package/template/apps/qpqjs/services/test/service/src/smoke/index.ts +2 -12
  101. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/config/defineEmailReceiveSmoke.ts +20 -0
  102. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/config/index.ts +1 -0
  103. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/constants/SMOKE_EMAIL_RECEIVER.ts +2 -0
  104. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/constants/index.ts +1 -0
  105. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/emailReceiveSmokeSuite.ts +15 -0
  106. package/template/apps/qpqjs/services/test/service/src/smoke/{email → suites/emailReceive/entry/email}/index.ts +0 -1
  107. package/template/apps/qpqjs/services/test/service/src/smoke/{email → suites/emailReceive/entry/email}/onSmokeEmailReceived.ts +1 -1
  108. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/entry/index.ts +1 -0
  109. package/template/apps/qpqjs/services/test/service/src/smoke/suites/emailReceive/index.ts +5 -0
  110. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/emailReceive → suites/emailReceive/logic}/askRunEmailReceiveTest.ts +3 -3
  111. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/emailReceive → suites/emailReceive/logic}/index.ts +1 -0
  112. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/config/defineEncryptedResourcesSmoke.ts +29 -0
  113. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/config/index.ts +1 -0
  114. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/constants/SMOKE_CRYPTO_KEY.ts +5 -0
  115. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/constants/SMOKE_ENCRYPTED_PROBE_DRIVE.ts +2 -0
  116. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/constants/SMOKE_ENCRYPTED_PROBE_STORE.ts +2 -0
  117. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/constants/index.ts +3 -0
  118. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/encryptedResourcesSmokeSuite.ts +9 -0
  119. package/template/apps/qpqjs/services/test/service/src/smoke/suites/encryptedResources/index.ts +4 -0
  120. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/encryptedResources → suites/encryptedResources/logic}/askRunEncryptedResourcesTest.ts +3 -5
  121. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/config/defineEventBusSmoke.ts +21 -0
  122. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/config/index.ts +1 -0
  123. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/constants/SMOKE_PROBE_EVENT_BUS.ts +2 -0
  124. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/constants/SMOKE_PROBE_EVENT_QUEUE.ts +2 -0
  125. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/constants/SMOKE_PROBE_EVENT_TYPE.ts +2 -0
  126. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/constants/index.ts +3 -0
  127. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/entry/index.ts +1 -0
  128. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/entry/queue/index.ts +1 -0
  129. package/template/apps/qpqjs/services/test/service/src/smoke/{queue → suites/eventBus/entry/queue}/onSmokeProbeEvent.ts +1 -1
  130. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/eventBusSmokeSuite.ts +9 -0
  131. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/index.ts +6 -0
  132. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventBus → suites/eventBus/logic}/askRunEventBusTest.ts +4 -6
  133. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventBus/models/index.ts +1 -0
  134. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/config/defineEventDocSmoke.ts +44 -0
  135. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/config/index.ts +1 -0
  136. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/constants/index.ts +1 -0
  137. package/template/apps/qpqjs/services/test/service/src/smoke/{constants → suites/eventDoc/constants}/smokeEventDoc.ts +1 -1
  138. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/entry/index.ts +1 -0
  139. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/entry/queue/index.ts +1 -0
  140. package/template/apps/qpqjs/services/test/service/src/smoke/{queue → suites/eventDoc/entry/queue}/onSmokeEventDocAppend.ts +3 -3
  141. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/eventDocSmokeSuite.ts +19 -0
  142. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/index.ts +7 -0
  143. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/askAssertContiguousEventIds.ts +1 -1
  144. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/askAssertSmokeProbeDocState.ts +2 -2
  145. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/askAwaitSmokeEventDocLog.ts +1 -1
  146. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/askRunEventDocConcurrentAppendTest.ts +5 -5
  147. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/askRunEventDocInterleavedBatchAppendTest.ts +4 -4
  148. package/template/apps/qpqjs/services/test/service/src/smoke/suites/eventDoc/models/index.ts +2 -0
  149. package/template/apps/qpqjs/services/test/service/src/smoke/{tests → suites}/index.ts +4 -5
  150. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStore/index.ts +2 -0
  151. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStore/keyValueStoreSmokeSuite.ts +14 -0
  152. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/crossService → suites/keyValueStore/logic}/askRunCrossServiceKeyValueStoreTest.ts +1 -1
  153. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/keyValueStore → suites/keyValueStore/logic}/askRunKeyValueStoreTest.ts +1 -1
  154. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStore/logic/index.ts +2 -0
  155. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/config/defineKeyValueStoreStreamSmoke.ts +30 -0
  156. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/config/index.ts +1 -0
  157. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/constants/SMOKE_STREAM_PROBE_STORE.ts +2 -0
  158. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/constants/index.ts +1 -0
  159. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/entry/index.ts +1 -0
  160. package/template/apps/qpqjs/services/test/service/src/smoke/{kvsStream → suites/keyValueStoreStream/entry/kvsStream}/index.ts +0 -1
  161. package/template/apps/qpqjs/services/test/service/src/smoke/{kvsStream → suites/keyValueStoreStream/entry/kvsStream}/onSmokeStreamRecord.ts +6 -4
  162. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/index.ts +5 -0
  163. package/template/apps/qpqjs/services/test/service/src/smoke/suites/keyValueStoreStream/keyValueStoreStreamSmokeSuite.ts +11 -0
  164. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/keyValueStoreStream → suites/keyValueStoreStream/logic}/askRunKeyValueStoreStreamTest.ts +15 -6
  165. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/keyValueStoreStream → suites/keyValueStoreStream/logic}/index.ts +1 -0
  166. package/template/apps/qpqjs/services/test/service/src/smoke/suites/noop/index.ts +2 -0
  167. package/template/apps/qpqjs/services/test/service/src/smoke/suites/noop/noopSmokeSuite.ts +7 -0
  168. package/template/apps/qpqjs/services/test/service/src/smoke/suites/openApi/config/defineOpenApiSmoke.ts +13 -0
  169. package/template/apps/qpqjs/services/test/service/src/smoke/suites/openApi/config/index.ts +1 -0
  170. package/template/apps/qpqjs/services/test/service/src/smoke/suites/openApi/index.ts +4 -0
  171. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/openApi → suites/openApi/logic}/askRunEchoRoundTripTest.ts +1 -1
  172. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/openApi → suites/openApi/logic}/askRunOpenApiDocumentTest.ts +1 -1
  173. package/template/apps/qpqjs/services/test/service/src/smoke/suites/openApi/openApiSmokeSuite.ts +13 -0
  174. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/config/defineParameterSmoke.ts +11 -0
  175. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/config/index.ts +1 -0
  176. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/constants/SMOKE_PROBE_PARAMETER.ts +2 -0
  177. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/constants/SMOKE_PROBE_PARAMETER_VALUE.ts +2 -0
  178. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/constants/index.ts +2 -0
  179. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/index.ts +4 -0
  180. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/parameter → suites/parameter/logic}/askRunParameterTest.ts +3 -5
  181. package/template/apps/qpqjs/services/test/service/src/smoke/suites/parameter/parameterSmokeSuite.ts +9 -0
  182. package/template/apps/qpqjs/services/test/service/src/{tick/config/defineTick.ts → smoke/suites/schedule/config/defineScheduleSmoke.ts} +1 -1
  183. package/template/apps/qpqjs/services/test/service/src/smoke/suites/schedule/config/index.ts +1 -0
  184. package/template/apps/qpqjs/services/test/service/src/smoke/suites/schedule/entry/index.ts +2 -0
  185. package/template/apps/qpqjs/services/test/service/src/smoke/suites/schedule/index.ts +6 -0
  186. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/schedule → suites/schedule/logic}/askRunScheduleTest.ts +4 -4
  187. package/template/apps/qpqjs/services/test/service/src/smoke/suites/schedule/scheduleSmokeSuite.ts +9 -0
  188. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/config/defineScopedKeyValueStoreSmoke.ts +19 -0
  189. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/config/index.ts +1 -0
  190. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/constants/SMOKE_SCOPED_PROBE_STORE.ts +2 -0
  191. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/constants/index.ts +1 -0
  192. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/index.ts +4 -0
  193. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/logic/askRunScopedKeyValueStoreTest.ts +256 -0
  194. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedKeyValueStore/scopedKeyValueStoreSmokeSuite.ts +11 -0
  195. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/config/defineScopedStorageDriveSmoke.ts +12 -0
  196. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/config/index.ts +1 -0
  197. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/constants/SMOKE_SCOPED_PROBE_DRIVE.ts +2 -0
  198. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/constants/index.ts +1 -0
  199. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/index.ts +4 -0
  200. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/scopedStorageDrive → suites/scopedStorageDrive/logic}/askRunScopedStorageDriveTest.ts +2 -2
  201. package/template/apps/qpqjs/services/test/service/src/smoke/suites/scopedStorageDrive/scopedStorageDriveSmokeSuite.ts +9 -0
  202. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/config/defineSecretSmoke.ts +8 -0
  203. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/config/index.ts +1 -0
  204. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/constants/SMOKE_PROBE_SECRET.ts +2 -0
  205. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/constants/index.ts +1 -0
  206. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/index.ts +4 -0
  207. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/secret → suites/secret/logic}/askRunSecretTest.ts +2 -2
  208. package/template/apps/qpqjs/services/test/service/src/smoke/suites/secret/secretSmokeSuite.ts +9 -0
  209. package/template/apps/qpqjs/services/test/service/src/smoke/suites/signingKey/config/defineSigningKeySmoke.ts +12 -0
  210. package/template/apps/qpqjs/services/test/service/src/smoke/suites/signingKey/config/index.ts +1 -0
  211. package/template/apps/qpqjs/services/test/service/src/smoke/suites/signingKey/index.ts +3 -0
  212. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/crossService → suites/signingKey/logic}/askRunCrossServiceSigningKeyTest.ts +1 -1
  213. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/signingKey → suites/signingKey/logic}/askRunSigningKeyTest.ts +1 -1
  214. package/template/apps/qpqjs/services/test/service/src/smoke/suites/signingKey/logic/index.ts +2 -0
  215. package/template/apps/qpqjs/services/test/service/src/smoke/suites/signingKey/signingKeySmokeSuite.ts +16 -0
  216. package/template/apps/qpqjs/services/test/service/src/smoke/suites/smokeSuites.ts +46 -0
  217. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDrive/index.ts +2 -0
  218. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/crossService → suites/storageDrive/logic}/askRunCrossServiceStorageDriveTest.ts +1 -1
  219. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/storageDrive → suites/storageDrive/logic}/askRunStorageDriveTest.ts +1 -1
  220. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDrive/logic/index.ts +2 -0
  221. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDrive/storageDriveSmokeSuite.ts +14 -0
  222. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/config/defineStorageDriveEventSmoke.ts +27 -0
  223. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/config/index.ts +1 -0
  224. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/constants/SMOKE_FILE_EVENT_DRIVE.ts +2 -0
  225. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/constants/SMOKE_SCOPED_FILE_EVENT_DRIVE.ts +2 -0
  226. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/constants/index.ts +2 -0
  227. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/entry/index.ts +1 -0
  228. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/entry/storageDrive/index.ts +1 -0
  229. package/template/apps/qpqjs/services/test/service/src/smoke/{storageDrive → suites/storageDriveEvent/entry/storageDrive}/onSmokeFileEvent.ts +1 -1
  230. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/index.ts +5 -0
  231. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/storageDriveEvent → suites/storageDriveEvent/logic}/askRunStorageDriveEventTest.ts +7 -9
  232. package/template/apps/qpqjs/services/test/service/src/smoke/{tests/storageDriveEvent → suites/storageDriveEvent/logic}/index.ts +1 -0
  233. package/template/apps/qpqjs/services/test/service/src/smoke/suites/storageDriveEvent/storageDriveEventSmokeSuite.ts +9 -0
  234. package/template/apps/qpqjs/services/testa/models/src/CrossServiceProbePayload.ts +1 -1
  235. package/template/apps/qpqjs/services/testa/service/src/infrastructure.ts +3 -3
  236. package/template/apps/qpqjs/services/testa/service/src/smoke/config/defineSmokeProbes.ts +16 -0
  237. package/template/apps/qpqjs/services/testa/service/src/smoke/config/index.ts +1 -0
  238. package/template/apps/qpqjs/services/{test/service/src/tick → testa/service/src/smoke}/index.ts +1 -0
  239. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/index.ts +3 -0
  240. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/keyValueStore/config/defineKeyValueStoreSmokeProbe.ts +33 -0
  241. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/keyValueStore/config/index.ts +1 -0
  242. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/keyValueStore/entry/serviceFunction/index.ts +1 -0
  243. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/keyValueStore/logic/index.ts +1 -0
  244. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/config/defineSigningKeySmokeProbe.ts +28 -0
  245. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/config/index.ts +1 -0
  246. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/entry/index.ts +1 -0
  247. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/entry/serviceFunction/index.ts +1 -0
  248. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/index.ts +3 -0
  249. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/signingKey/logic/index.ts +1 -0
  250. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/config/defineStorageDriveSmokeProbe.ts +31 -0
  251. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/config/index.ts +1 -0
  252. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/entry/index.ts +1 -0
  253. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/entry/serviceFunction/index.ts +1 -0
  254. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/index.ts +3 -0
  255. package/template/apps/qpqjs/services/testa/service/src/smoke/suites/storageDrive/logic/index.ts +1 -0
  256. package/template/apps/todo/deploy.config.json +13 -4
  257. package/template/apps/todo/packages/constants/src/index.ts +0 -1
  258. package/template/apps/todo/packages/service-utils/src/defineTodoService.ts +9 -7
  259. package/template/apps/todo/services/admin/service/src/infrastructure.ts +1 -1
  260. package/template/apps/todo/services/admin/views/src/app/app.tsx +9 -19
  261. package/template/apps/todo/services/auth/service/src/infrastructure.ts +1 -1
  262. package/template/apps/todo/services/design/service/src/infrastructure.ts +1 -1
  263. package/template/apps/todo/services/shell/service/src/infrastructure.ts +1 -1
  264. package/template/apps/todo/services/todo/service/src/infrastructure.ts +1 -1
  265. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-delete.md +1 -1
  266. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-get-all.md +1 -1
  267. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-get.md +1 -1
  268. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-query.md +3 -1
  269. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-scan.md +1 -1
  270. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-update.md +1 -1
  271. package/template/docusaurus/docs/actions/core/key-value-store/ask-key-value-store-upsert.md +1 -1
  272. package/template/docusaurus/docs/config/core/key-value-store.md +12 -2
  273. package/template/docusaurus/docs/config/features/event-doc.md +22 -1
  274. package/template/docusaurus/docs/getting-started.md +5 -5
  275. package/template/scripts/deployedSmoke.mjs +27 -22
  276. package/template/scripts/localSmoke.mjs +7 -7
  277. package/lib/commonjs/lib/replaceInFileExact.d.ts +0 -1
  278. package/lib/commonjs/lib/replaceInFileExact.js +0 -18
  279. package/lib/commonjs/lib/replaceInFileExact.js.map +0 -1
  280. package/lib/commonjs/steps/013_printNextSteps.js.map +0 -1
  281. package/lib/esm/lib/replaceInFileExact.d.ts +0 -1
  282. package/lib/esm/lib/replaceInFileExact.js +0 -11
  283. package/lib/esm/lib/replaceInFileExact.js.map +0 -1
  284. package/lib/esm/steps/013_printNextSteps.js +0 -21
  285. package/lib/esm/steps/013_printNextSteps.js.map +0 -1
  286. package/template/apps/qpqjs/packages/constants/src/domain.ts +0 -3
  287. package/template/apps/qpqjs/services/test/service/src/echo/config/defineEcho.ts +0 -9
  288. package/template/apps/qpqjs/services/test/service/src/smoke/constants/smokeProbe.ts +0 -39
  289. package/template/apps/qpqjs/services/test/service/src/smoke/models/index.ts +0 -5
  290. package/template/apps/qpqjs/services/test/service/src/smoke/queue/index.ts +0 -3
  291. package/template/apps/qpqjs/services/test/service/src/smoke/storageDrive/index.ts +0 -4
  292. package/template/apps/qpqjs/services/test/service/src/smoke/tests/crossService/index.ts +0 -3
  293. package/template/apps/qpqjs/services/test/service/src/smoke/tests/keyValueStore/index.ts +0 -1
  294. package/template/apps/qpqjs/services/test/service/src/smoke/tests/scopedKeyValueStore/askRunScopedKeyValueStoreTest.ts +0 -102
  295. package/template/apps/qpqjs/services/test/service/src/smoke/tests/signingKey/index.ts +0 -1
  296. package/template/apps/qpqjs/services/test/service/src/smoke/tests/smokeTestRegistry.ts +0 -66
  297. package/template/apps/qpqjs/services/test/service/src/smoke/tests/storageDrive/index.ts +0 -1
  298. package/template/apps/qpqjs/services/test/service/src/tick/config/index.ts +0 -1
  299. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/config/defineCrossServiceProbe.ts +0 -68
  300. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/config/index.ts +0 -1
  301. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/entry/serviceFunction/index.ts +0 -3
  302. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/logic/index.ts +0 -3
  303. package/template/apps/todo/packages/constants/src/domain.ts +0 -2
  304. /package/lib/commonjs/steps/{007_pinRegistryVersions.d.ts → 008_pinRegistryVersions.d.ts} +0 -0
  305. /package/lib/commonjs/steps/{008_transpileToJavaScript.d.ts → 009_transpileToJavaScript.d.ts} +0 -0
  306. /package/lib/commonjs/steps/{009_restoreGitignore.d.ts → 010_restoreGitignore.d.ts} +0 -0
  307. /package/lib/commonjs/steps/{010_gitInit.d.ts → 011_gitInit.d.ts} +0 -0
  308. /package/lib/commonjs/steps/{011_npmInstall.d.ts → 012_npmInstall.d.ts} +0 -0
  309. /package/lib/commonjs/steps/{012_buildWorkspaces.d.ts → 013_buildWorkspaces.d.ts} +0 -0
  310. /package/lib/commonjs/steps/{013_printNextSteps.d.ts → 014_printNextSteps.d.ts} +0 -0
  311. /package/lib/esm/steps/{007_pinRegistryVersions.d.ts → 008_pinRegistryVersions.d.ts} +0 -0
  312. /package/lib/esm/steps/{008_transpileToJavaScript.d.ts → 009_transpileToJavaScript.d.ts} +0 -0
  313. /package/lib/esm/steps/{009_restoreGitignore.d.ts → 010_restoreGitignore.d.ts} +0 -0
  314. /package/lib/esm/steps/{010_gitInit.d.ts → 011_gitInit.d.ts} +0 -0
  315. /package/lib/esm/steps/{011_npmInstall.d.ts → 012_npmInstall.d.ts} +0 -0
  316. /package/lib/esm/steps/{012_buildWorkspaces.d.ts → 013_buildWorkspaces.d.ts} +0 -0
  317. /package/lib/esm/steps/{013_printNextSteps.d.ts → 014_printNextSteps.d.ts} +0 -0
  318. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests → harness/assert}/askSmokeAssert.ts +0 -0
  319. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests → harness/assert}/askSmokePollForMarker.ts +0 -0
  320. /package/template/apps/qpqjs/services/test/service/src/smoke/{constants → harness/constants}/SMOKE_RUNS_STORE.ts +0 -0
  321. /package/template/apps/qpqjs/services/test/service/src/smoke/{constants → harness/constants}/githubOidc.ts +0 -0
  322. /package/template/apps/qpqjs/services/test/service/src/smoke/{constants → harness/constants}/smokeRunQueue.ts +0 -0
  323. /package/template/apps/qpqjs/services/test/service/src/smoke/{controller → harness/controller}/askGetSmokeRun.ts +0 -0
  324. /package/template/apps/qpqjs/services/test/service/src/smoke/{controller → harness/controller}/askRunSmokeTests.ts +0 -0
  325. /package/template/apps/qpqjs/services/test/service/src/smoke/{controller → harness/controller}/index.ts +0 -0
  326. /package/template/apps/qpqjs/services/test/service/src/smoke/{data → harness/data}/askGetSmokeRunById.ts +0 -0
  327. /package/template/apps/qpqjs/services/test/service/src/smoke/{data → harness/data}/askRecordSmokeTestResult.ts +0 -0
  328. /package/template/apps/qpqjs/services/test/service/src/smoke/{data → harness/data}/askSaveSmokeRun.ts +0 -0
  329. /package/template/apps/qpqjs/services/test/service/src/smoke/{data → harness/data}/askSetSmokeRunOutcome.ts +0 -0
  330. /package/template/apps/qpqjs/services/test/service/src/smoke/{data → harness/data}/index.ts +0 -0
  331. /package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/github/index.ts +0 -0
  332. /package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/github/verifyGithubOidcToken.ts +0 -0
  333. /package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/index.ts +0 -0
  334. /package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/smokeRun/askFindSmokeRun.ts +0 -0
  335. /package/template/apps/qpqjs/services/test/service/src/smoke/{logic → harness/logic}/smokeRun/summarizeSmokeRun.ts +0 -0
  336. /package/template/apps/qpqjs/services/test/service/src/smoke/{models → harness/models}/GithubOidcClaims.ts +0 -0
  337. /package/template/apps/qpqjs/services/test/service/src/smoke/{processors → harness/processors}/github/getGithubOidcAuthProcessors.ts +0 -0
  338. /package/template/apps/qpqjs/services/test/service/src/smoke/{processors → harness/processors}/github/index.ts +0 -0
  339. /package/template/apps/qpqjs/services/test/service/src/smoke/{processors → harness/processors}/index.ts +0 -0
  340. /package/template/apps/qpqjs/services/test/service/src/smoke/{queue → harness/queue}/onSmokeTestRequested.ts +0 -0
  341. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests → harness/types}/SmokeTestDefinition.ts +0 -0
  342. /package/template/apps/qpqjs/services/test/service/src/smoke/{email → suites/emailReceive/logic}/smokeEmailMarkerId.ts +0 -0
  343. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/encryptedResources → suites/encryptedResources/logic}/index.ts +0 -0
  344. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventBus → suites/eventBus/logic}/index.ts +0 -0
  345. /package/template/apps/qpqjs/services/test/service/src/smoke/{models → suites/eventBus/models}/SmokeProbeEventQueueEvent.ts +0 -0
  346. /package/template/apps/qpqjs/services/test/service/src/smoke/{eventDoc → suites/eventDoc/definition}/index.ts +0 -0
  347. /package/template/apps/qpqjs/services/test/service/src/smoke/{eventDoc → suites/eventDoc/definition}/smokeProbeDocDefinition.ts +0 -0
  348. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/eventDoc → suites/eventDoc/logic}/index.ts +0 -0
  349. /package/template/apps/qpqjs/services/test/service/src/smoke/{models → suites/eventDoc/models}/SmokeEventDocAppendQueueEvent.ts +0 -0
  350. /package/template/apps/qpqjs/services/test/service/src/smoke/{models → suites/eventDoc/models}/SmokeEventDocMark.ts +0 -0
  351. /package/template/apps/qpqjs/services/test/service/src/smoke/{kvsStream → suites/keyValueStoreStream/logic}/smokeStreamMarkerId.ts +0 -0
  352. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/noop → suites/noop/logic}/askRunNoopTest.ts +0 -0
  353. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/noop → suites/noop/logic}/index.ts +0 -0
  354. /package/template/apps/qpqjs/services/test/service/src/{echo → smoke/suites/openApi}/controller/echo.ts +0 -0
  355. /package/template/apps/qpqjs/services/test/service/src/{echo → smoke/suites/openApi}/controller/index.ts +0 -0
  356. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/openApi → suites/openApi/logic}/index.ts +0 -0
  357. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/parameter → suites/parameter/logic}/index.ts +0 -0
  358. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/constants/index.ts +0 -0
  359. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/constants/scheduleTickName.ts +0 -0
  360. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/constants/scheduleTickStore.ts +0 -0
  361. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/entry/kvsStream/index.ts +0 -0
  362. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/entry/kvsStream/onScheduleTickStream.ts +0 -0
  363. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/entry/schedule/index.ts +0 -0
  364. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/entry/schedule/onTick.ts +0 -0
  365. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/schedule → suites/schedule/logic}/index.ts +0 -0
  366. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/models/ScheduleTickRecord.ts +0 -0
  367. /package/template/apps/qpqjs/services/test/service/src/{tick → smoke/suites/schedule}/models/index.ts +0 -0
  368. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/scopedKeyValueStore → suites/scopedKeyValueStore/logic}/index.ts +0 -0
  369. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/scopedStorageDrive → suites/scopedStorageDrive/logic}/index.ts +0 -0
  370. /package/template/apps/qpqjs/services/test/service/src/smoke/{tests/secret → suites/secret/logic}/index.ts +0 -0
  371. /package/template/apps/qpqjs/services/test/service/src/smoke/{storageDrive → suites/storageDriveEvent/logic}/smokeFileEventMarkerId.ts +0 -0
  372. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/keyValueStore}/entry/index.ts +0 -0
  373. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/keyValueStore}/entry/serviceFunction/smokeCrossServiceKeyValueStoreProbe.ts +0 -0
  374. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/keyValueStore}/index.ts +0 -0
  375. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/keyValueStore}/logic/askProbeForeignKeyValueStore.ts +0 -0
  376. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/signingKey}/entry/serviceFunction/smokeCrossServiceSigningKeyProbe.ts +0 -0
  377. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/signingKey}/logic/askProbeForeignSigningKey.ts +0 -0
  378. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/storageDrive}/entry/serviceFunction/smokeCrossServiceStorageDriveProbe.ts +0 -0
  379. /package/template/apps/qpqjs/services/testa/service/src/{crossServiceProbe → smoke/suites/storageDrive}/logic/askProbeForeignStorageDrive.ts +0 -0
@@ -52,6 +52,7 @@ function* askKeyValueStoreQuery<KvsItem>(
52
52
  | Property | Type | Default | Description |
53
53
  | --- | --- | --- | --- |
54
54
  | `filter` | `KvsQueryOperation` | – | An extra condition applied to non-key attributes **after** the key match. Filtered-out rows still count against `limit`. |
55
+ | `indexName` | `string` | – | Force the query onto the [index](../../../config/core/key-value-store.md#indexes-gsis) declared with this name, read in its sort order. Without it, the table serves the query if its keys cover the key condition, otherwise the first declared index whose keys do — so an index sharing the table's keys is only reached by naming it here. An undeclared name throws `IndexNotFound`. |
55
56
  | `sortAscending` | `boolean` | `true` | Order results by the sort key. `false` returns the newest/highest first. |
56
57
  | `limit` | `number` | – | Maximum number of records to return in this page. |
57
58
  | `nextPageKey` | `string` | – | Opaque cursor from a previous page's `nextPageKey`; pass it to fetch the following page. |
@@ -118,8 +119,9 @@ When `nextPageKey` is set, pass it back as `options.nextPageKey` to fetch the ne
118
119
  | --- | --- |
119
120
  | `KeyValueStoreQueryErrorTypeEnum.ServiceUnavailable` | DynamoDB internal error or throttling. |
120
121
  | `KeyValueStoreQueryErrorTypeEnum.ResourceNotFound` | The underlying table does not exist. |
121
- | `KeyValueStoreQueryErrorTypeEnum.InvalidScope` | The `scope` option is malformed (empty, `.`, over 128 characters, or containing path separators, `..`, `@`, or null bytes), the store's partition key is not string-typed, a scoped query's key condition does not constrain the partition key (or constrains it with an operator that cannot be scoped), or a partition-key condition value contains the reserved `@@QPQSCOPE@@` delimiter (reserved on string-pk stores, so unscoped queries reject it too). |
122
+ | `KeyValueStoreQueryErrorTypeEnum.InvalidScope` | The `scope` option is malformed (empty, `.`, over 128 characters, or containing path separators, `..`, `@`, or null bytes), the store's partition key is not string-typed, a scoped query's key condition does not constrain the partition key or an [index](../../../config/core/key-value-store.md#indexes-gsis) partition key (or constrains one with an operator that cannot be scoped: an index partition key only takes `=`), a condition names an attribute containing `@@QPQ`, an index partition-key condition value doesn't match that index's declared type, or a partition-key condition value contains the reserved `@@QPQ` marker (reserved on string-pk stores, so unscoped queries reject it too). |
122
123
  | `KeyValueStoreQueryErrorTypeEnum.StoreNotFound` | The key value store is not declared in the qpq config (misconfiguration, e.g. a wrong name or a missing `defineKeyValueStore`). |
124
+ | `KeyValueStoreQueryErrorTypeEnum.IndexNotFound` | The `indexName` option names an index the store doesn't declare. |
123
125
 
124
126
  Catch errors with `askCatch` — it returns `{ success: true, result }` or `{ success: false, error }`.
125
127
 
@@ -70,7 +70,7 @@ When `nextPageKey` is set, pass it back as the third argument to fetch the next
70
70
  | --- | --- |
71
71
  | `KeyValueStoreScanErrorTypeEnum.ServiceUnavailable` | DynamoDB internal error or throttling. |
72
72
  | `KeyValueStoreScanErrorTypeEnum.ResourceNotFound` | The underlying table does not exist. |
73
- | `KeyValueStoreScanErrorTypeEnum.InvalidScope` | The `scope` option is malformed (empty, `.`, over 128 characters, or containing path separators, `..`, `@`, or null bytes), the store's partition key is not string-typed, or a scoped call's partition-key value contains the reserved `@@QPQSCOPE@@` delimiter. |
73
+ | `KeyValueStoreScanErrorTypeEnum.InvalidScope` | The `scope` option is malformed (empty, `.`, over 128 characters, or containing path separators, `..`, `@`, or null bytes), the store's partition key is not string-typed, a scoped call's partition-key value contains the reserved `@@QPQ` marker, a scoped call's `filterCondition` names an attribute containing `@@QPQ`, or a scoped `filterCondition`'s partition-key comparison uses an operator that cannot be scoped. |
74
74
  | `KeyValueStoreScanErrorTypeEnum.StoreNotFound` | The key value store is not declared in the qpq config (misconfiguration, e.g. a wrong name or a missing `defineKeyValueStore`). |
75
75
 
76
76
  Catch errors with `askCatch` — it returns `{ success: true, result }` or `{ success: false, error }`.
@@ -101,7 +101,7 @@ Each `path` is a `KvsAttributePath` — either a top-level attribute name (`'bal
101
101
  | --- | --- |
102
102
  | `KeyValueStoreUpdateErrorTypeEnum.ServiceUnavailable` | DynamoDB internal error or throttling. |
103
103
  | `KeyValueStoreUpdateErrorTypeEnum.ResourceNotFound` | The underlying table does not exist. |
104
- | `KeyValueStoreUpdateErrorTypeEnum.InvalidScope` | The `scope` option is malformed (empty, `.`, over 128 characters, or containing path separators, `..`, `@`, or null bytes), the store's partition key is not string-typed, or the partition-key value contains the reserved `@@QPQSCOPE@@` delimiter (reserved on string-pk stores, so unscoped calls reject it too). |
104
+ | `KeyValueStoreUpdateErrorTypeEnum.InvalidScope` | The `scope` option is malformed (empty, `.`, over 128 characters, or containing path separators, `..`, `@`, or null bytes), the store's partition key is not string-typed, the partition-key value contains the reserved `@@QPQ` marker (reserved on string-pk stores, so unscoped calls reject it too), a scoped update names an attribute containing `@@QPQ`, or a scoped update targets an [index](../../../config/core/key-value-store.md#indexes-gsis) partition key with anything other than a whole-value `Set`/`SetIfNotExists`/`Remove` of the declared type (`Increment`, `Add`, `Delete`, and nested paths are refused). |
105
105
  | `KeyValueStoreUpdateErrorTypeEnum.StoreNotFound` | The key value store is not declared in the qpq config (misconfiguration, e.g. a wrong name or a missing `defineKeyValueStore`). |
106
106
 
107
107
  Catch errors with `askCatch` — it returns `{ success: true, result }` or `{ success: false, error }`.
@@ -61,7 +61,7 @@ function* askKeyValueStoreUpsert<KvsItem>(
61
61
  | `KeyValueStoreUpsertErrorTypeEnum.ResourceNotFound` | The underlying table does not exist. |
62
62
  | `KeyValueStoreUpsertErrorTypeEnum.Conflict` | A conditional (`ifNotExists`) write lost to an existing item — final, the slot is taken. Namespaced — not the generic `ErrorTypeEnum.Conflict` — so retry logic can target the write race specifically without also catching domain-level conflicts. |
63
63
  | `KeyValueStoreUpsertErrorTypeEnum.WriteContention` | A conditional (`ifNotExists`) write lost to another write (a transaction) holding the item right now — transient, the item may still be absent once it settles. |
64
- | `KeyValueStoreUpsertErrorTypeEnum.InvalidScope` | The `scope` option is malformed (empty, `.`, over 128 characters, or containing path separators, `..`, `@`, or null bytes), the store's partition key is not string-typed, or the partition-key value contains the reserved `@@QPQSCOPE@@` delimiter (reserved on string-pk stores, so unscoped calls reject it too). |
64
+ | `KeyValueStoreUpsertErrorTypeEnum.InvalidScope` | The `scope` option is malformed (empty, `.`, over 128 characters, or containing path separators, `..`, `@`, or null bytes), the store's partition key is not string-typed, the partition-key value contains the reserved `@@QPQ` marker (reserved on string-pk stores, so unscoped calls reject it too), a scoped item has an attribute name containing `@@QPQ`, or a scoped item's [index](../../../config/core/key-value-store.md#indexes-gsis) partition-key value doesn't match that index's declared type. |
65
65
  | `KeyValueStoreUpsertErrorTypeEnum.StoreNotFound` | The key value store is not declared in the qpq config (misconfiguration, e.g. a wrong name or a missing `defineKeyValueStore`). |
66
66
 
67
67
  Catch errors with `askCatch` — it returns `{ success: true, result }` or `{ success: false, error }`.
@@ -83,7 +83,7 @@ defineKeyValueStore('events', kvsKey('deviceId'), [kvsKey('timestamp', 'number')
83
83
 
84
84
  ## Indexes (GSIs)
85
85
 
86
- Each entry in `options.indexes` is a `CompositeKvsIndex<T>` — either a bare attribute name (a partition-key-only index) or an object with a `partitionKey` and optional `sortKey`:
86
+ Each entry in `options.indexes` is a `CompositeKvsIndex<T>` — either a bare attribute name (a partition-key-only index) or an object with a `partitionKey`, optional `sortKey`, and optional `name`:
87
87
 
88
88
  ```typescript
89
89
  import { defineKeyValueStore, kvsKey } from 'quidproquo-core';
@@ -94,11 +94,21 @@ defineKeyValueStore('orders', 'orderId', [], {
94
94
  { partitionKey: 'customerId', sortKey: kvsKey('createdAt', 'number') },
95
95
  // Query orders by status (partition-only index)
96
96
  'status',
97
+ // Two indexes on the same partition key need an explicit name
98
+ { name: 'byStatusAndTotal', partitionKey: 'status', sortKey: kvsKey('total', 'number') },
97
99
  ],
98
100
  });
99
101
  ```
100
102
 
101
- On AWS each index becomes a Global Secondary Index whose name is the index's partition-key attribute (`customerId`, `status` above).
103
+ `name` defaults to the partition-key attribute (`customerId`, `status` above) and is what [askKeyValueStoreQuery](../../actions/core/key-value-store/ask-key-value-store-query.md)'s `indexName` option targets; `defineKeyValueStore` throws if two indexes resolve to the same name. On AWS each index becomes a Global Secondary Index deployed under this name.
104
+
105
+ A query without `indexName` runs against the table if its keys cover every attribute in the key condition, otherwise the first declared index whose keys do.
106
+
107
+ ### Indexes on a scoped store
108
+
109
+ A store with `scoped: true` (see [`scoped`](#options--qpqconfigadvancedkeyvaluestoresettingst-optional)) can still declare `indexes`. On AWS, an index whose partition key isn't the table's partition key is keyed on a hidden `@@QPQGSI_<attribute>@@` attribute holding the scope-composed value; the index keeps its declared name and sort key, and stories never see the hidden attribute. A scoped store's index partition key must be a `'string'` or `'number'` key, since a scope can't be composed onto a `'binary'` key — `defineKeyValueStore` throws at config time otherwise.
110
+
111
+ Adding or removing an index on an already-deployed scoped store needs two deploys: remove the index and deploy, then re-add it and deploy. CloudFormation can't change a GSI's key schema in place, and rows written before the new index exists only appear in it once they're rewritten.
102
112
 
103
113
  ## Change data capture (`onStream`)
104
114
 
@@ -25,7 +25,7 @@ export default [
25
25
 
26
26
  ## Registering a collection's functions
27
27
 
28
- `functions` is an `EventDocFunctions` object: `{ storeName, type, foldSnapshotViews, foldDocumentState, collectReferences, collectReferencesFromState, validateEvent, render? }`. The object `createEventDocDefinition` returns — given `storeName`/`type` in its config — satisfies this shape directly, so a collection with no service-only render can register its definition verbatim. A collection that needs a render step only service code can perform (resolving linked docs, reading blob-drive assets) layers it on with `extendEventDocFunctions(definition, { render })`, which returns a new object and never mutates the definition itself.
28
+ `functions` is an `EventDocFunctions` object: `{ storeName, type, getSnapshotCacheKey, foldSnapshotViews, foldDocumentState, collectReferences, collectReferencesFromState, validateEvent, render? }`. The object `createEventDocDefinition` returns — given `storeName`/`type` in its config — satisfies this shape directly, so a collection with no service-only render can register its definition verbatim. A collection that needs a render step only service code can perform (resolving linked docs, reading blob-drive assets) layers it on with `extendEventDocFunctions(definition, { render })`, which returns a new object and never mutates the definition itself.
29
29
 
30
30
  `runtime` is a [`QpqFunctionRuntime`](../core/dynamic-functions.md#runtime--qpqfunctionruntime-required) path to that SAME export — the dynamic-functions pattern: identity is read off the object here at config time, behaviour is loaded from the path by the processors at request time. Both must point at the exact object being registered, or the registration and the runtime will disagree about what the collection can do.
31
31
 
@@ -55,6 +55,7 @@ The collection's callable surface, read for its identity (`storeName`, `type`) a
55
55
  | --- | --- | --- | --- |
56
56
  | `storeName` | `string` | yes | Name of the summary store to create and serve. Also derives the events table and asset bucket names. |
57
57
  | `type` | `string` | yes | The document type this collection holds — the store's partition value, so one store can (via the split helpers) hold several types. |
58
+ | `getSnapshotCacheKey` | `() => string` | yes | The key this collection's snapshots are filed under (see [Snapshot cache key](#snapshot-cache-key)). `''` is the legacy layout. A member rather than a value because the data layer reaches a definition only through dynamic functions. |
58
59
  | `foldSnapshotViews` | `(events, seedViews?) => Nullable<EventDocSnapshotViews>` | yes | Every view of a log prefix, era-pinned — what a snapshot stores. Invoked by the event store's stream projector (which also writes the summary row from the fold's `summary` view). |
59
60
  | `foldDocumentState` | `(events, seedState?) => unknown` | yes | The document view at one point, LATEST-shaped, resumable from a stored snapshot's era-pinned document state. The read side's fold: render, references, as-of reads, and the append hooks' state derivation all go through it. |
60
61
  | `collectReferences` | `(events) => EventDocLink[]` | yes | The `EventDocLink`s this doc's whole HISTORY depends on; `[]` for a leaf doc type. Invoked by the transfer manifest walk (it exports the whole history). |
@@ -62,6 +63,26 @@ The collection's callable surface, read for its identity (`storeName`, `type`) a
62
63
  | `validateEvent` | `(event, state) => Nullable<string> \| AskResponse<Nullable<string>>` | yes | The append pre-write gate: checked against the state the event will land on, before the write (see [askEventDocEventAppend](../../actions/features/event-doc/ask-event-doc-event-append.md)). Return a rejection reason string to refuse the append, `null` to allow it. A collection with no domain rules can pass `() => null`. |
63
64
  | `render` | `(input: EventDocRenderInput) => EventDocRenderResult \| AskResponse<EventDocRenderResult>` | no | Render the resolved, already-folded document state (`input.state`, resolved snapshot-seeded by the route). Omit and `GET {basePath}/{id}/render` 404s as "no renderer configured". Plain function or story — the dynamic-functions processor runs either. |
64
65
 
66
+ #### Snapshot cache key
67
+
68
+ A snapshot is a memo of "fold these events with this seed and reducer". The events are immutable, so the memo stays valid until the fold code changes. A change to the MEANING of existing events is a schema version bump with a migration. An additive change — a new defaulted field in a version's seed, a new event type, a new reducer case — needs no migration, but every stored snapshot is now the output of code you no longer run, and a reader resuming from one would see the old shape (a `undefined` where the new field should be).
69
+
70
+ `snapshotCacheKey` on `createEventDocDefinition` names the fold code. It is part of the snapshot row's partition key (`docId#viewName#key`) and the offloaded blob's path, so after you change it every reader finds no snapshot, refolds the whole log from the seed, and the stream projector files a fresh snapshot under the new key on the document's next append. The bootstrap base handed to the editor carries the key too, so a workspace snapshot held in the browser across a deploy is refetched rather than trusted. Rows under an old key are left to persist.
71
+
72
+ ```typescript
73
+ export const contentItemEventDoc = createEventDocDefinition({
74
+ storeName: CONTENT_STORE,
75
+ type: 'content',
76
+ schemaVersion: 1,
77
+ versions: [contentItemV1],
78
+ // Bump when v1's seed or reducer changes in place; every stored snapshot is then refolded.
79
+ snapshotCacheKey: '2026-09-23-image-assets',
80
+ api,
81
+ });
82
+ ```
83
+
84
+ Refolding is lazy: a document pays one whole-log fold per reader until its next append reprojects it. To pay that up front, an admin job can walk each collection's documents (inside each storage scope) and call `askEventDocReprojectHead(docId)`, which re-runs the projector at the log head under the current key.
85
+
65
86
  ### `runtime` — `QpqFunctionRuntime` (required)
66
87
 
67
88
  A reference to the module exporting `functions`, usually a relative path string of the form `'/path/to/file::exportedObjectName'` — see [defineDynamicFunctions](../core/dynamic-functions.md#runtime--qpqfunctionruntime-required). Must resolve to the SAME object passed as `functions`.
@@ -45,9 +45,9 @@ curl http://localhost:8080/api/shell/v1/health
45
45
  myapp/
46
46
  ├── package.json # workspace root — run all commands from here
47
47
  └── apps/myapp/
48
- ├── deploy.config.json # environments: development + production (docker)
48
+ ├── deploy.config.json # deployments: development + production (docker)
49
49
  ├── packages/
50
- │ ├── constants/ # domain, service enum, user directory name
50
+ │ ├── constants/ # service enum, user directory name
51
51
  │ ├── config/
52
52
  │ └── service-utils/ # the shared config every service starts from
53
53
  └── services/
@@ -106,14 +106,14 @@ itself.
106
106
 
107
107
  ## Deploy it
108
108
 
109
- Both scaffolded environments deploy as a single docker image — the whole
109
+ Both scaffolded deployments build a single docker image — the whole
110
110
  app, one container:
111
111
 
112
112
  ```bash
113
113
  npm run go
114
114
  ```
115
115
 
116
- Pick an environment when prompted (or pass `--env development`), and the
116
+ Pick a deployment when prompted (or pass `--deployment development`), and the
117
117
  build prints the `docker run` command when the image is ready:
118
118
 
119
119
  ```bash
@@ -122,7 +122,7 @@ docker run --rm -p 80:8080 -p 8080:8080 -p 8888:8888 -p 3001:3001 \
122
122
  qpq-myapp:development
123
123
  ```
124
124
 
125
- Then open [http://localhost](http://localhost). Environments live in
125
+ Then open [http://localhost](http://localhost). Deployments live in
126
126
  `apps/myapp/deploy.config.json` — an app can move platforms (docker → AWS)
127
127
  with a config change, not a rewrite.
128
128
 
@@ -11,13 +11,14 @@
11
11
  // ACTIONS_ID_TOKEN_REQUEST_TOKEN provided by Actions when the job has id-token: write
12
12
  // SMOKE_ROOTS optional comma list to run a subset of the roots
13
13
  //
14
- // Urls are derived, not configured: the roots come from the app's constants
15
- // package (the same list every service's defineDns reads), hosts follow the
16
- // app's default domain shape (see getRootHosts), and the api gateway maps each
17
- // service under its own base path:
14
+ // Urls are derived, not configured: the roots come from the deployment's
15
+ // ROOT_DOMAINS setting in apps/qpqjs/deploy.config.json (the same list every
16
+ // service's defineDns reads; the deployment is named after the environment),
17
+ // hosts follow the app's default domain shape (see getRootHosts), and the api
18
+ // gateway maps each service under its own base path:
18
19
  // https://api.<environment>.<root>/<service>
19
20
 
20
- import { createRequire } from 'node:module';
21
+ import { readFileSync } from 'node:fs';
21
22
  import { dirname, join } from 'node:path';
22
23
  import { fileURLToPath } from 'node:url';
23
24
 
@@ -25,10 +26,9 @@ import { getRootHosts, runEdgeChecks } from './smoke/runEdgeChecks.mjs';
25
26
  import { runSmokeRun } from './smoke/runSmokeRun.mjs';
26
27
 
27
28
  const SERVICE_NAME = 'test';
28
- // The built constants package: the deploy job builds the app before this runs.
29
- const DOMAIN_CONSTANTS_PATH = join(
29
+ const DEPLOY_CONFIG_PATH = join(
30
30
  dirname(fileURLToPath(import.meta.url)),
31
- '../apps/qpqjs/packages/constants/dist/src/domain.js'
31
+ '../apps/qpqjs/deploy.config.json'
32
32
  );
33
33
 
34
34
  const log = (message) => console.log(`deployed-smoke: ${message}`);
@@ -46,24 +46,29 @@ const requireEnv = (name) => {
46
46
  return value;
47
47
  };
48
48
 
49
- const getRoots = () => {
50
- const { QPQJS_DOMAINS } = createRequire(import.meta.url)(
51
- DOMAIN_CONSTANTS_PATH
52
- );
53
- if (!QPQJS_DOMAINS?.length) {
54
- fail(`no QPQJS_DOMAINS in ${DOMAIN_CONSTANTS_PATH}; build the app first`);
49
+ const splitList = (value) =>
50
+ (value ?? '')
51
+ .split(',')
52
+ .map((item) => item.trim())
53
+ .filter(Boolean);
54
+
55
+ const getRoots = (environment) => {
56
+ const { deployments } = JSON.parse(readFileSync(DEPLOY_CONFIG_PATH, 'utf8'));
57
+ const allRoots = splitList(deployments[environment]?.settings?.ROOT_DOMAINS);
58
+ if (!allRoots.length) {
59
+ fail(
60
+ `deployment '${environment}' in ${DEPLOY_CONFIG_PATH} has no ROOT_DOMAINS setting`
61
+ );
55
62
  }
56
63
 
57
- const subset = process.env.SMOKE_ROOTS?.split(',')
58
- .map((root) => root.trim())
59
- .filter(Boolean);
60
- if (!subset?.length) {
61
- return QPQJS_DOMAINS;
64
+ const subset = splitList(process.env.SMOKE_ROOTS);
65
+ if (!subset.length) {
66
+ return allRoots;
62
67
  }
63
68
 
64
- const unknown = subset.filter((root) => !QPQJS_DOMAINS.includes(root));
69
+ const unknown = subset.filter((root) => !allRoots.includes(root));
65
70
  if (unknown.length > 0) {
66
- fail(`SMOKE_ROOTS names roots not in QPQJS_DOMAINS: ${unknown.join(', ')}`);
71
+ fail(`SMOKE_ROOTS names roots not in ROOT_DOMAINS: ${unknown.join(', ')}`);
67
72
  }
68
73
  return subset;
69
74
  };
@@ -101,7 +106,7 @@ const smokeRoot = async (hosts, allHosts) => {
101
106
  };
102
107
 
103
108
  const environment = requireEnv('SMOKE_ENVIRONMENT');
104
- const roots = getRoots();
109
+ const roots = getRoots(environment);
105
110
  const allHosts = roots.map((root) => getRootHosts(root, environment));
106
111
 
107
112
  log(`environment=${environment} roots=${roots.join(', ')}`);
@@ -30,10 +30,11 @@ import { fileURLToPath } from 'node:url';
30
30
 
31
31
  import { runSmokeRun } from './smoke/runSmokeRun.mjs';
32
32
 
33
- // The dev server defaults to this anyway; set explicitly so a CI runner that
34
- // already has ENVIRONMENT set (the deploy workflow does) cannot change what
35
- // the smoke routes expect from the token. Must match the job's `environment:`.
36
- const ENVIRONMENT = 'development';
33
+ // The deployment (an entry in apps/qpqjs/deploy.config.json) the dev server
34
+ // runs as. There are several, so it has to be named or a headless cli exits.
35
+ // Its environment must match what the smoke routes expect from the token, i.e.
36
+ // the job's `environment:`.
37
+ const DEPLOYMENT = 'development';
37
38
 
38
39
  // There is more than one app under apps/, so the app has to be named: without
39
40
  // it the cli exits with the app list rather than picking one.
@@ -134,7 +135,7 @@ const stopServer = (server) =>
134
135
  });
135
136
 
136
137
  const main = async () => {
137
- log(`starting dev server (app=${APP_NAME} env=${ENVIRONMENT})`);
138
+ log(`starting dev server (app=${APP_NAME} deployment=${DEPLOYMENT})`);
138
139
 
139
140
  // node on the cli directly, NOT `npx qpq`: npx is another process in front
140
141
  // of the one we need to signal, and SIGTERM stops at it. The cli would never
@@ -143,11 +144,10 @@ const main = async () => {
143
144
  // the handler is.
144
145
  const server = spawn(
145
146
  process.execPath,
146
- [QPQ_BIN, 'go:dev:api', '--app', APP_NAME],
147
+ [QPQ_BIN, 'go:dev:api', '--app', APP_NAME, '--deployment', DEPLOYMENT],
147
148
  {
148
149
  cwd: APP_ROOT,
149
150
  stdio: 'inherit',
150
- env: { ...process.env, ENVIRONMENT },
151
151
  }
152
152
  );
153
153
 
@@ -1 +0,0 @@
1
- export declare const replaceInFileExact: (filePath: string, from: string, to: string) => void;
@@ -1,18 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.replaceInFileExact = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- // Replace an exact string in one file, throwing if it isn't there. Targeted
9
- // edits should fail loudly when the template drifts.
10
- const replaceInFileExact = (filePath, from, to) => {
11
- const original = fs_1.default.readFileSync(filePath, 'utf8');
12
- if (!original.includes(from)) {
13
- throw new Error(`Expected to find "${from}" in ${filePath}. Has the template changed?`);
14
- }
15
- fs_1.default.writeFileSync(filePath, original.split(from).join(to));
16
- };
17
- exports.replaceInFileExact = replaceInFileExact;
18
- //# sourceMappingURL=replaceInFileExact.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"replaceInFileExact.js","sourceRoot":"","sources":["../../../src/lib/replaceInFileExact.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AAEpB,4EAA4E;AAC5E,qDAAqD;AAC9C,MAAM,kBAAkB,GAAG,CAAC,QAAgB,EAAE,IAAY,EAAE,EAAU,EAAQ,EAAE;IACrF,MAAM,QAAQ,GAAG,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,QAAQ,QAAQ,6BAA6B,CAAC,CAAC;IAC1F,CAAC;IACD,YAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5D,CAAC,CAAC;AANW,QAAA,kBAAkB,sBAM7B","sourcesContent":["import fs from 'fs';\n\n// Replace an exact string in one file, throwing if it isn't there. Targeted\n// edits should fail loudly when the template drifts.\nexport const replaceInFileExact = (filePath: string, from: string, to: string): void => {\n const original = fs.readFileSync(filePath, 'utf8');\n if (!original.includes(from)) {\n throw new Error(`Expected to find \"${from}\" in ${filePath}. Has the template changed?`);\n }\n fs.writeFileSync(filePath, original.split(from).join(to));\n};\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"013_printNextSteps.js","sourceRoot":"","sources":["../../../src/steps/013_printNextSteps.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEa,QAAA,cAAc,GAAqB;IAC9C,IAAI,EAAE,MAAM;IAEZ,GAAG,EAAE,KAAoB,EAAE,4CAAf,EAAE,OAAO,EAAE;QACrB,MAAM,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kCAAkC,CAAC;QAEtF,OAAO,CAAC,GAAG,CAAC;UACN,OAAO,CAAC,OAAO;;;;;;;OAOlB,OAAO,CAAC,OAAO;EACpB,OAAO;;;8BAGqB,OAAO,CAAC,OAAO,oCAAoC,OAAO,CAAC,MAAM;CAC9F,CAAC,CAAC;IACD,CAAC,CAAA;CACF,CAAC","sourcesContent":["import { CreateQpqAppStep } from '../types';\n\nexport const printNextSteps: CreateQpqAppStep = {\n name: 'Done',\n\n run: async ({ answers }) => {\n const install = answers.installDependencies ? '' : ' npm install\\n npm run build\\n';\n\n console.log(`\nCreated ${answers.appName}!\n\nYour app has five services (admin, auth, design, shell and todo) and\ndeploys as a single docker image.\n\nNext steps:\n\n cd ${answers.appName}\n${install} npm run dev # api on http://localhost:8080, web on http://localhost:3080\n npm run deploy # build the docker image (then run the printed docker command)\n\nDeploy config lives in apps/${answers.appName}/deploy.config.json; the domain (${answers.domain}) lives in the app's constants package.\n`);\n },\n};\n"]}
@@ -1 +0,0 @@
1
- export declare const replaceInFileExact: (filePath: string, from: string, to: string) => void;
@@ -1,11 +0,0 @@
1
- import fs from 'fs';
2
- // Replace an exact string in one file, throwing if it isn't there. Targeted
3
- // edits should fail loudly when the template drifts.
4
- export const replaceInFileExact = (filePath, from, to) => {
5
- const original = fs.readFileSync(filePath, 'utf8');
6
- if (!original.includes(from)) {
7
- throw new Error(`Expected to find "${from}" in ${filePath}. Has the template changed?`);
8
- }
9
- fs.writeFileSync(filePath, original.split(from).join(to));
10
- };
11
- //# sourceMappingURL=replaceInFileExact.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"replaceInFileExact.js","sourceRoot":"","sources":["../../../src/lib/replaceInFileExact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,4EAA4E;AAC5E,qDAAqD;AACrD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAAgB,EAAE,IAAY,EAAE,EAAU,EAAQ,EAAE;IACrF,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,QAAQ,QAAQ,6BAA6B,CAAC,CAAC;IAC1F,CAAC;IACD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5D,CAAC,CAAC","sourcesContent":["import fs from 'fs';\n\n// Replace an exact string in one file, throwing if it isn't there. Targeted\n// edits should fail loudly when the template drifts.\nexport const replaceInFileExact = (filePath: string, from: string, to: string): void => {\n const original = fs.readFileSync(filePath, 'utf8');\n if (!original.includes(from)) {\n throw new Error(`Expected to find \"${from}\" in ${filePath}. Has the template changed?`);\n }\n fs.writeFileSync(filePath, original.split(from).join(to));\n};\n"]}
@@ -1,21 +0,0 @@
1
- export const printNextSteps = {
2
- name: 'Done',
3
- run: async ({ answers }) => {
4
- const install = answers.installDependencies ? '' : ' npm install\n npm run build\n';
5
- console.log(`
6
- Created ${answers.appName}!
7
-
8
- Your app has five services (admin, auth, design, shell and todo) and
9
- deploys as a single docker image.
10
-
11
- Next steps:
12
-
13
- cd ${answers.appName}
14
- ${install} npm run dev # api on http://localhost:8080, web on http://localhost:3080
15
- npm run deploy # build the docker image (then run the printed docker command)
16
-
17
- Deploy config lives in apps/${answers.appName}/deploy.config.json; the domain (${answers.domain}) lives in the app's constants package.
18
- `);
19
- },
20
- };
21
- //# sourceMappingURL=013_printNextSteps.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"013_printNextSteps.js","sourceRoot":"","sources":["../../../src/steps/013_printNextSteps.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAqB;IAC9C,IAAI,EAAE,MAAM;IAEZ,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACzB,MAAM,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kCAAkC,CAAC;QAEtF,OAAO,CAAC,GAAG,CAAC;UACN,OAAO,CAAC,OAAO;;;;;;;OAOlB,OAAO,CAAC,OAAO;EACpB,OAAO;;;8BAGqB,OAAO,CAAC,OAAO,oCAAoC,OAAO,CAAC,MAAM;CAC9F,CAAC,CAAC;IACD,CAAC;CACF,CAAC","sourcesContent":["import { CreateQpqAppStep } from '../types';\n\nexport const printNextSteps: CreateQpqAppStep = {\n name: 'Done',\n\n run: async ({ answers }) => {\n const install = answers.installDependencies ? '' : ' npm install\\n npm run build\\n';\n\n console.log(`\nCreated ${answers.appName}!\n\nYour app has five services (admin, auth, design, shell and todo) and\ndeploys as a single docker image.\n\nNext steps:\n\n cd ${answers.appName}\n${install} npm run dev # api on http://localhost:8080, web on http://localhost:3080\n npm run deploy # build the docker image (then run the printed docker command)\n\nDeploy config lives in apps/${answers.appName}/deploy.config.json; the domain (${answers.domain}) lives in the app's constants package.\n`);\n },\n};\n"]}
@@ -1,3 +0,0 @@
1
- // Root domains the app is served on, primary first. Every api, web entry and
2
- // websocket is created on each of them; absolute URLs bake to the primary.
3
- export const QPQJS_DOMAINS = ['quidproquojs.com', 'qpqjs.com'];
@@ -1,9 +0,0 @@
1
- import { QPQConfig } from 'quidproquo';
2
- import { defineDynamicRoutes } from 'quidproquo-features';
3
-
4
- import * as controllers from '../controller';
5
-
6
- // The echo routes carry their own method/path/schema on the handler; this just
7
- // registers the controller module under the service's src root.
8
- export const defineEcho = (): QPQConfig =>
9
- defineDynamicRoutes(controllers, '/echo/controller');
@@ -1,39 +0,0 @@
1
- // Throwaway resources the smoke tests exercise, one per kind of owned
2
- // resource the service role is granted by tag / name convention (see the
3
- // tag-based IAM grants in quidproquo-deploy-awscdk). Nothing else uses them.
4
- // The store and drive names live in @qpqjs/constants because testa reaches
5
- // them cross-service.
6
- export const SMOKE_PROBE_PARAMETER = 'smokeProbe';
7
- export const SMOKE_PROBE_PARAMETER_VALUE = 'smoke-probe-parameter';
8
- export const SMOKE_PROBE_SECRET = 'smokeProbe';
9
- export const SMOKE_PROBE_EVENT_BUS = 'smokeProbe';
10
-
11
- // The queue subscribed to the probe event bus, and the message type that
12
- // flows bus -> queue -> store marker for the event bus test.
13
- export const SMOKE_PROBE_EVENT_QUEUE = 'smokeProbeEvents';
14
- export const SMOKE_PROBE_EVENT_TYPE = 'smokeProbeEvent';
15
-
16
- // Scoped probe resources: every call must carry a scope, an unscoped one is
17
- // refused. Only the test service uses them, so they stay service-level.
18
- export const SMOKE_SCOPED_PROBE_STORE = 'smokeScopedProbe';
19
- export const SMOKE_SCOPED_PROBE_DRIVE = 'smoke-scoped-probe';
20
-
21
- // The file event drives: an unscoped and a scoped one, both with create and
22
- // delete handlers that write a marker row the file event test polls for.
23
- export const SMOKE_FILE_EVENT_DRIVE = 'smoke-file-event';
24
-
25
- // A scoped store with a change stream; the handler writes a marker row the
26
- // kvs stream test polls for.
27
- export const SMOKE_STREAM_PROBE_STORE = 'smokeStreamProbe';
28
-
29
- // The crypto key the encrypted probe drive and store name: proves the
30
- // alias-conditioned KMS grant lets the service role write and read data
31
- // encrypted with a defineCryptoKey. Not 'smokeProbe': the signing key of that
32
- // name is a KMS alias too, and the two would collide.
33
- export const SMOKE_CRYPTO_KEY = 'smokeCrypto';
34
- export const SMOKE_ENCRYPTED_PROBE_STORE = 'smokeEncryptedProbe';
35
- export const SMOKE_ENCRYPTED_PROBE_DRIVE = 'smoke-encrypted-probe';
36
-
37
- // Inbound email: the receiver's onEmail writes a marker the email test polls for.
38
- // Deployed only.
39
- export const SMOKE_EMAIL_RECEIVER = 'smoke';
@@ -1,5 +0,0 @@
1
- export * from './GithubOidcClaims';
2
- export * from './SmokeEventDocAppendQueueEvent';
3
- export * from './SmokeEventDocMark';
4
- export * from './SmokeProbeEventQueueEvent';
5
- export * from './SmokeTestRequestedQueueEvent';
@@ -1,3 +0,0 @@
1
- export * from './onSmokeEventDocAppend';
2
- export * from './onSmokeProbeEvent';
3
- export * from './onSmokeTestRequested';
@@ -1,4 +0,0 @@
1
- export * from './onSmokeEmailReceived';
2
- export * from './onSmokeFileEvent';
3
- export * from './smokeEmailMarkerId';
4
- export * from './smokeFileEventMarkerId';
@@ -1,3 +0,0 @@
1
- export * from './askRunCrossServiceKeyValueStoreTest';
2
- export * from './askRunCrossServiceSigningKeyTest';
3
- export * from './askRunCrossServiceStorageDriveTest';
@@ -1 +0,0 @@
1
- export * from './askRunKeyValueStoreTest';
@@ -1,102 +0,0 @@
1
- import {
2
- askCatch,
3
- askKeyValueStoreDelete,
4
- askKeyValueStoreGet,
5
- askKeyValueStoreGetBase,
6
- askKeyValueStoreQuery,
7
- askKeyValueStoreUpsert,
8
- askKeyValueStoreUpsertBase,
9
- askNewGuid,
10
- AskResponse,
11
- kvsEqual,
12
- } from 'quidproquo';
13
-
14
- import { SMOKE_PROBE_STORE } from '@qpqjs/constants';
15
- import { SmokeProbeRecord } from '@qpqjs/test-models';
16
-
17
- import { SMOKE_SCOPED_PROBE_STORE } from '../../constants/smokeProbe';
18
- import { askSmokeAssert } from '../askSmokeAssert';
19
-
20
- // The scope gate on a store, on whichever backend is running: a scoped store
21
- // serves scoped calls (including a query) and keeps two scopes apart,
22
- // refuses an unscoped call, and an unscoped store refuses a scoped one. On
23
- // dynamo the scope is composed into the partition key, so the read-back also
24
- // proves the composed form never leaks to the caller.
25
- export function* askRunScopedKeyValueStoreTest(): AskResponse<void> {
26
- const probeId = yield* askNewGuid();
27
- const scopeA = `smoke-a-${probeId}`;
28
- const scopeB = `smoke-b-${probeId}`;
29
- const category = `scoped-kvs-${probeId}`;
30
-
31
- const record: SmokeProbeRecord = { probeId, category, value: 1 };
32
- yield* askKeyValueStoreUpsert<SmokeProbeRecord>(
33
- SMOKE_SCOPED_PROBE_STORE,
34
- record,
35
- { scope: scopeA }
36
- );
37
-
38
- const written = yield* askKeyValueStoreGet<SmokeProbeRecord>(
39
- SMOKE_SCOPED_PROBE_STORE,
40
- probeId,
41
- { scope: scopeA }
42
- );
43
- yield* askSmokeAssert(
44
- written?.probeId === probeId && written.value === 1,
45
- 'scoped get did not return the record with its raw key'
46
- );
47
-
48
- // A scoped query must constrain the partition key (the scope is composed
49
- // into it on dynamo), so the query is on probeId, not the category index.
50
- const byKey = yield* askKeyValueStoreQuery<SmokeProbeRecord>(
51
- SMOKE_SCOPED_PROBE_STORE,
52
- kvsEqual('probeId', probeId),
53
- { scope: scopeA }
54
- );
55
- yield* askSmokeAssert(
56
- byKey.items.some((item) => item.category === category),
57
- 'scoped query by partition key did not return the record'
58
- );
59
-
60
- const fromB = yield* askKeyValueStoreGet<SmokeProbeRecord>(
61
- SMOKE_SCOPED_PROBE_STORE,
62
- probeId,
63
- { scope: scopeB }
64
- );
65
- yield* askSmokeAssert(
66
- !fromB,
67
- 'record written under scope A is visible from scope B'
68
- );
69
-
70
- const unscopedGet = yield* askCatch(
71
- askKeyValueStoreGet<SmokeProbeRecord>(SMOKE_SCOPED_PROBE_STORE, probeId)
72
- );
73
- yield* askSmokeAssert(
74
- !unscopedGet.success &&
75
- unscopedGet.error.errorType ===
76
- askKeyValueStoreGetBase.errorType.InvalidScope,
77
- 'unscoped get on the scoped store was not refused with InvalidScope'
78
- );
79
-
80
- const scopedUpsertOnUnscopedStore = yield* askCatch(
81
- askKeyValueStoreUpsert<SmokeProbeRecord>(SMOKE_PROBE_STORE, record, {
82
- scope: scopeA,
83
- })
84
- );
85
- yield* askSmokeAssert(
86
- !scopedUpsertOnUnscopedStore.success &&
87
- scopedUpsertOnUnscopedStore.error.errorType ===
88
- askKeyValueStoreUpsertBase.errorType.InvalidScope,
89
- 'scoped upsert on the unscoped store was not refused with InvalidScope'
90
- );
91
-
92
- yield* askKeyValueStoreDelete(SMOKE_SCOPED_PROBE_STORE, probeId, undefined, {
93
- scope: scopeA,
94
- });
95
-
96
- const deleted = yield* askKeyValueStoreGet<SmokeProbeRecord>(
97
- SMOKE_SCOPED_PROBE_STORE,
98
- probeId,
99
- { scope: scopeA }
100
- );
101
- yield* askSmokeAssert(!deleted, 'scoped record still present after delete');
102
- }
@@ -1 +0,0 @@
1
- export * from './askRunSigningKeyTest';