create-qpq-app 0.1.16 → 0.1.18

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 (160) hide show
  1. package/README.md +28 -10
  2. package/package.json +9 -6
  3. package/template/README.md +55 -103
  4. package/template/apps/qpqjs/packages/constants/src/QpqjsServiceEnum.ts +2 -0
  5. package/template/apps/qpqjs/packages/constants/src/index.ts +1 -0
  6. package/template/apps/qpqjs/packages/constants/src/smokeProbe.ts +13 -0
  7. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/LandingPage.tsx +8 -6
  8. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Actions.tsx +53 -0
  9. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/CodeWindow.tsx +4 -4
  10. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Footer.tsx +18 -29
  11. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Hero.tsx +23 -32
  12. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Infrastructure.tsx +130 -0
  13. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/NavBar.tsx +24 -7
  14. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Replay.tsx +221 -0
  15. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Testing.tsx +123 -0
  16. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/YieldLoop.tsx +15 -13
  17. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/landing.css +652 -721
  18. package/template/apps/qpqjs/services/shell/views/src/index.html +2 -2
  19. package/template/apps/qpqjs/services/test/config/package.json +22 -0
  20. package/template/apps/qpqjs/services/test/config/src/index.ts +2 -0
  21. package/template/apps/qpqjs/services/test/config/tsconfig.json +18 -0
  22. package/template/apps/qpqjs/services/test/config/tsconfig.lib.json +19 -0
  23. package/template/apps/qpqjs/services/test/models/package.json +22 -0
  24. package/template/apps/qpqjs/services/test/models/src/SmokeProbeRecord.ts +8 -0
  25. package/template/apps/qpqjs/services/test/models/src/SmokeRun.ts +14 -0
  26. package/template/apps/qpqjs/services/test/models/src/SmokeRunStatus.ts +5 -0
  27. package/template/apps/qpqjs/services/test/models/src/SmokeRunSummary.ts +8 -0
  28. package/template/apps/qpqjs/services/test/models/src/SmokeRunWithSummary.ts +7 -0
  29. package/template/apps/qpqjs/services/test/models/src/SmokeTestResult.ts +15 -0
  30. package/template/apps/qpqjs/services/test/models/src/SmokeTestStatus.ts +6 -0
  31. package/template/apps/qpqjs/services/test/models/src/index.ts +7 -0
  32. package/template/apps/qpqjs/services/test/models/tsconfig.json +18 -0
  33. package/template/apps/qpqjs/services/test/models/tsconfig.lib.json +19 -0
  34. package/template/apps/qpqjs/services/test/service/package.json +9 -0
  35. package/template/apps/qpqjs/services/test/service/src/infrastructure.ts +19 -0
  36. package/template/apps/qpqjs/services/test/service/src/smoke/config/defineSmoke.ts +102 -0
  37. package/template/apps/qpqjs/services/test/service/src/smoke/config/index.ts +1 -0
  38. package/template/apps/qpqjs/services/test/service/src/smoke/constants/SMOKE_RUNS_STORE.ts +2 -0
  39. package/template/apps/qpqjs/services/test/service/src/smoke/constants/githubOidc.ts +19 -0
  40. package/template/apps/qpqjs/services/test/service/src/smoke/constants/index.ts +4 -0
  41. package/template/apps/qpqjs/services/test/service/src/smoke/constants/smokeProbe.ts +14 -0
  42. package/template/apps/qpqjs/services/test/service/src/smoke/constants/smokeRunQueue.ts +6 -0
  43. package/template/apps/qpqjs/services/test/service/src/smoke/controller/askGetSmokeRun.ts +27 -0
  44. package/template/apps/qpqjs/services/test/service/src/smoke/controller/askRunSmokeTests.ts +19 -0
  45. package/template/apps/qpqjs/services/test/service/src/smoke/controller/index.ts +2 -0
  46. package/template/apps/qpqjs/services/test/service/src/smoke/data/askGetSmokeRunById.ts +16 -0
  47. package/template/apps/qpqjs/services/test/service/src/smoke/data/askSaveSmokeRun.ts +9 -0
  48. package/template/apps/qpqjs/services/test/service/src/smoke/data/index.ts +2 -0
  49. package/template/apps/qpqjs/services/test/service/src/smoke/index.ts +9 -0
  50. package/template/apps/qpqjs/services/test/service/src/smoke/logic/github/index.ts +1 -0
  51. package/template/apps/qpqjs/services/test/service/src/smoke/logic/github/verifyGithubOidcToken.ts +105 -0
  52. package/template/apps/qpqjs/services/test/service/src/smoke/logic/index.ts +2 -0
  53. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/askExecuteSmokeRun.ts +81 -0
  54. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/askFindSmokeRun.ts +11 -0
  55. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/askStartSmokeRun.ts +62 -0
  56. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/index.ts +4 -0
  57. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/summarizeSmokeRun.ts +25 -0
  58. package/template/apps/qpqjs/services/test/service/src/smoke/models/GithubOidcClaims.ts +11 -0
  59. package/template/apps/qpqjs/services/test/service/src/smoke/models/SmokeProbeEventQueueEvent.ts +9 -0
  60. package/template/apps/qpqjs/services/test/service/src/smoke/models/SmokeRunRequestedQueueEvent.ts +9 -0
  61. package/template/apps/qpqjs/services/test/service/src/smoke/models/index.ts +3 -0
  62. package/template/apps/qpqjs/services/test/service/src/smoke/processors/github/getGithubOidcAuthProcessors.ts +67 -0
  63. package/template/apps/qpqjs/services/test/service/src/smoke/processors/github/index.ts +1 -0
  64. package/template/apps/qpqjs/services/test/service/src/smoke/processors/index.ts +1 -0
  65. package/template/apps/qpqjs/services/test/service/src/smoke/queue/index.ts +2 -0
  66. package/template/apps/qpqjs/services/test/service/src/smoke/queue/onSmokeProbeEvent.ts +27 -0
  67. package/template/apps/qpqjs/services/test/service/src/smoke/queue/onSmokeRunRequested.ts +15 -0
  68. package/template/apps/qpqjs/services/test/service/src/smoke/tests/SmokeTestDefinition.ts +8 -0
  69. package/template/apps/qpqjs/services/test/service/src/smoke/tests/askSmokeAssert.ts +12 -0
  70. package/template/apps/qpqjs/services/test/service/src/smoke/tests/crossService/askRunCrossServiceKeyValueStoreTest.ts +47 -0
  71. package/template/apps/qpqjs/services/test/service/src/smoke/tests/crossService/askRunCrossServiceStorageDriveTest.ts +46 -0
  72. package/template/apps/qpqjs/services/test/service/src/smoke/tests/crossService/index.ts +2 -0
  73. package/template/apps/qpqjs/services/test/service/src/smoke/tests/eventBus/askRunEventBusTest.ts +57 -0
  74. package/template/apps/qpqjs/services/test/service/src/smoke/tests/eventBus/index.ts +1 -0
  75. package/template/apps/qpqjs/services/test/service/src/smoke/tests/index.ts +10 -0
  76. package/template/apps/qpqjs/services/test/service/src/smoke/tests/keyValueStore/askRunKeyValueStoreTest.ts +71 -0
  77. package/template/apps/qpqjs/services/test/service/src/smoke/tests/keyValueStore/index.ts +1 -0
  78. package/template/apps/qpqjs/services/test/service/src/smoke/tests/noop/askRunNoopTest.ts +7 -0
  79. package/template/apps/qpqjs/services/test/service/src/smoke/tests/noop/index.ts +1 -0
  80. package/template/apps/qpqjs/services/test/service/src/smoke/tests/parameter/askRunParameterTest.ts +27 -0
  81. package/template/apps/qpqjs/services/test/service/src/smoke/tests/parameter/index.ts +1 -0
  82. package/template/apps/qpqjs/services/test/service/src/smoke/tests/secret/askRunSecretTest.ts +16 -0
  83. package/template/apps/qpqjs/services/test/service/src/smoke/tests/secret/index.ts +1 -0
  84. package/template/apps/qpqjs/services/test/service/src/smoke/tests/smokeTestRegistry.ts +29 -0
  85. package/template/apps/qpqjs/services/test/service/src/smoke/tests/storageDrive/askRunStorageDriveTest.ts +46 -0
  86. package/template/apps/qpqjs/services/test/service/src/smoke/tests/storageDrive/index.ts +1 -0
  87. package/template/apps/qpqjs/services/test/service/tsconfig.app.json +17 -0
  88. package/template/apps/qpqjs/services/test/service/tsconfig.json +8 -0
  89. package/template/apps/qpqjs/services/test/service-utils/package.json +22 -0
  90. package/template/apps/qpqjs/services/test/service-utils/src/index.ts +2 -0
  91. package/template/apps/qpqjs/services/test/service-utils/tsconfig.json +18 -0
  92. package/template/apps/qpqjs/services/test/service-utils/tsconfig.lib.json +19 -0
  93. package/template/apps/qpqjs/services/test/shared-logic/package.json +22 -0
  94. package/template/apps/qpqjs/services/test/shared-logic/src/index.ts +2 -0
  95. package/template/apps/qpqjs/services/test/shared-logic/tsconfig.json +18 -0
  96. package/template/apps/qpqjs/services/test/shared-logic/tsconfig.lib.json +19 -0
  97. package/template/apps/qpqjs/services/test/x-logic/package.json +22 -0
  98. package/template/apps/qpqjs/services/test/x-logic/src/index.ts +2 -0
  99. package/template/apps/qpqjs/services/test/x-logic/tsconfig.json +18 -0
  100. package/template/apps/qpqjs/services/test/x-logic/tsconfig.lib.json +19 -0
  101. package/template/apps/qpqjs/services/test/x-models/package.json +22 -0
  102. package/template/apps/qpqjs/services/test/x-models/src/index.ts +2 -0
  103. package/template/apps/qpqjs/services/test/x-models/tsconfig.json +18 -0
  104. package/template/apps/qpqjs/services/test/x-models/tsconfig.lib.json +19 -0
  105. package/template/apps/qpqjs/services/testa/config/package.json +22 -0
  106. package/template/apps/qpqjs/services/testa/config/src/index.ts +2 -0
  107. package/template/apps/qpqjs/services/testa/config/tsconfig.json +18 -0
  108. package/template/apps/qpqjs/services/testa/config/tsconfig.lib.json +19 -0
  109. package/template/apps/qpqjs/services/testa/models/package.json +22 -0
  110. package/template/apps/qpqjs/services/testa/models/src/CrossServiceKeyValueStoreProbeResult.ts +5 -0
  111. package/template/apps/qpqjs/services/testa/models/src/CrossServiceProbePayload.ts +4 -0
  112. package/template/apps/qpqjs/services/testa/models/src/CrossServiceStorageDriveProbeResult.ts +6 -0
  113. package/template/apps/qpqjs/services/testa/models/src/index.ts +3 -0
  114. package/template/apps/qpqjs/services/testa/models/tsconfig.json +18 -0
  115. package/template/apps/qpqjs/services/testa/models/tsconfig.lib.json +19 -0
  116. package/template/apps/qpqjs/services/testa/service/package.json +9 -0
  117. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/config/defineCrossServiceProbe.ts +52 -0
  118. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/config/index.ts +1 -0
  119. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/entry/index.ts +1 -0
  120. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/entry/serviceFunction/index.ts +2 -0
  121. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/entry/serviceFunction/smokeCrossServiceKeyValueStoreProbe.ts +16 -0
  122. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/entry/serviceFunction/smokeCrossServiceStorageDriveProbe.ts +16 -0
  123. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/index.ts +3 -0
  124. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/logic/askProbeForeignKeyValueStore.ts +39 -0
  125. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/logic/askProbeForeignStorageDrive.ts +30 -0
  126. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/logic/index.ts +2 -0
  127. package/template/apps/qpqjs/services/testa/service/src/infrastructure.ts +22 -0
  128. package/template/apps/qpqjs/services/testa/service/tsconfig.app.json +17 -0
  129. package/template/apps/qpqjs/services/testa/service/tsconfig.json +8 -0
  130. package/template/apps/qpqjs/services/testa/service-utils/package.json +22 -0
  131. package/template/apps/qpqjs/services/testa/service-utils/src/index.ts +2 -0
  132. package/template/apps/qpqjs/services/testa/service-utils/tsconfig.json +18 -0
  133. package/template/apps/qpqjs/services/testa/service-utils/tsconfig.lib.json +19 -0
  134. package/template/apps/qpqjs/services/testa/shared-logic/package.json +22 -0
  135. package/template/apps/qpqjs/services/testa/shared-logic/src/index.ts +2 -0
  136. package/template/apps/qpqjs/services/testa/shared-logic/tsconfig.json +18 -0
  137. package/template/apps/qpqjs/services/testa/shared-logic/tsconfig.lib.json +19 -0
  138. package/template/apps/qpqjs/services/testa/x-logic/package.json +22 -0
  139. package/template/apps/qpqjs/services/testa/x-logic/src/index.ts +2 -0
  140. package/template/apps/qpqjs/services/testa/x-logic/tsconfig.json +18 -0
  141. package/template/apps/qpqjs/services/testa/x-logic/tsconfig.lib.json +19 -0
  142. package/template/apps/qpqjs/services/testa/x-models/package.json +22 -0
  143. package/template/apps/qpqjs/services/testa/x-models/src/index.ts +2 -0
  144. package/template/apps/qpqjs/services/testa/x-models/tsconfig.json +18 -0
  145. package/template/apps/qpqjs/services/testa/x-models/tsconfig.lib.json +19 -0
  146. package/template/docusaurus/DOCUMENTATION_CHECKLIST.md +0 -7
  147. package/template/docusaurus/docs/actions/core/config/ask-config-get-secret.md +15 -9
  148. package/template/docusaurus/docs/actions/core/network/ask-network-request.md +2 -1
  149. package/template/docusaurus/docs/actions/core/system/ask-batch.md +1 -0
  150. package/template/docusaurus/docs/actions/webserver/route-auth-validation/ask-route-auth-validation-decode.md +21 -10
  151. package/template/docusaurus/docs/index.md +2 -2
  152. package/template/docusaurus/docusaurus.config.ts +4 -4
  153. package/template/scripts/deployedSmoke.mjs +134 -0
  154. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Features.tsx +0 -83
  155. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Packages.tsx +0 -62
  156. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Pipeline.tsx +0 -58
  157. package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/TronGrid.tsx +0 -587
  158. package/template/docusaurus/docs/actions/core/claude-ai/_category_.json +0 -7
  159. package/template/docusaurus/docs/actions/core/claude-ai/ask-claude-ai-messages-api.md +0 -70
  160. package/template/docusaurus/docs/config/core/claude-ai.md +0 -52
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # create-qpq-app
2
2
 
3
- Scaffold a new [quidproquo](https://github.com/joe-coady/quidproquo) app:
3
+ Scaffold a new [quidproquo](https://github.com/qpqjs/quidproquo) app:
4
4
 
5
5
  ```bash
6
6
  npx create-qpq-app my-app
@@ -8,9 +8,16 @@ cd my-app
8
8
  npm run dev
9
9
  ```
10
10
 
11
- You get a full QPQ workspace with five services (`admin`, `auth`, `design`,
12
- `shell` and `todo`) that builds, runs locally on the QPQ dev server, and
13
- deploys as a single docker image with `npm run deploy`.
11
+ You get a full workspace with five services (`admin`, `auth`, `design`, `shell` and `todo`) that builds, runs locally on the qpq dev server, and deploys as a single docker image with `npm run deploy`.
12
+
13
+ The api comes up on `http://localhost:8080` and the web on `http://localhost:3080`:
14
+
15
+ ```bash
16
+ curl http://localhost:8080/api/shell/v1/health
17
+ # {"status":"healthy","service":"shell","checkedAt":"..."}
18
+ ```
19
+
20
+ Node.js 24 or newer is required. Docker is only needed to deploy.
14
21
 
15
22
  ## Options
16
23
 
@@ -23,11 +30,22 @@ npx create-qpq-app <app-name> [options]
23
30
  --no-install skip npm install
24
31
  ```
25
32
 
33
+ Pass `--language javascript` and you get the same app with type annotations stripped and JSX preserved, running on the same toolchain.
34
+
26
35
  ## How it works
27
36
 
28
- The template is a snapshot of quidproquojs.com a real, continuously-built
29
- QPQ workspace — captured into this package at publish time. Scaffolding runs
30
- a pipeline of self-contained steps (prune the docs site, prune the website
31
- app, apply your app's identity/domain, pin quidproquo versions, git init,
32
- install). The generated app pins the `quidproquo-*` versions this package was
33
- published with; the whole family releases in lockstep.
37
+ The template is a snapshot of quidproquojs.com, a real and continuously built qpq workspace, captured into this package at publish time. Scaffolding runs a pipeline of self-contained steps: prune the docs site, prune the website app, apply your app's identity and domain, pin the quidproquo versions, git init, install.
38
+
39
+ The generated app pins the `quidproquo-*` versions this package was published with. The whole family releases in lockstep, so those versions are always a set that was built and tested together.
40
+
41
+ ## Status
42
+
43
+ Pre-1.0 and under active development. The generated app changes shape between releases.
44
+
45
+ ## Documentation
46
+
47
+ [docs.quidproquojs.com](https://docs.quidproquojs.com)
48
+
49
+ ## License
50
+
51
+ MIT. See [LICENSE](https://github.com/qpqjs/quidproquo/blob/main/LICENSE).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-qpq-app",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
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",
@@ -13,6 +13,9 @@
13
13
  "lib/**/*",
14
14
  "template"
15
15
  ],
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
16
19
  "scripts": {
17
20
  "test": "vitest run",
18
21
  "test:watch": "vitest",
@@ -23,7 +26,7 @@
23
26
  "build:esm": "tsc -p tsconfig.esm.json",
24
27
  "build:bin-perms": "node -e \"require('fs').chmodSync('lib/commonjs/bin/createQpqApp.js', 0o755)\"",
25
28
  "snapshot-template": "node ./scripts/snapshotTemplate.mjs",
26
- "smoke-test": "node ./scripts/smokeTest.mjs",
29
+ "scaffold-test": "node ./scripts/scaffoldTest.mjs",
27
30
  "prepack": "npm run snapshot-template",
28
31
  "lint": "npx eslint .",
29
32
  "lint:fix": "npx eslint . --fix",
@@ -31,7 +34,7 @@
31
34
  },
32
35
  "repository": {
33
36
  "type": "git",
34
- "url": "git+https://github.com/joe-coady/quidproquo.git"
37
+ "url": "git+https://github.com/qpqjs/quidproquo.git"
35
38
  },
36
39
  "keywords": [
37
40
  "quidproquo",
@@ -42,9 +45,9 @@
42
45
  "author": "",
43
46
  "license": "MIT",
44
47
  "bugs": {
45
- "url": "https://github.com/joe-coady/quidproquo/issues"
48
+ "url": "https://github.com/qpqjs/quidproquo/issues"
46
49
  },
47
- "homepage": "https://github.com/joe-coady/quidproquo#readme",
50
+ "homepage": "https://github.com/qpqjs/quidproquo#readme",
48
51
  "dependencies": {
49
52
  "@inquirer/prompts": "^8.5.2",
50
53
  "prettier": "^3.2.5",
@@ -52,7 +55,7 @@
52
55
  },
53
56
  "devDependencies": {
54
57
  "@types/node": "^22.13.13",
55
- "quidproquo-tsconfig": "0.1.16"
58
+ "quidproquo-tsconfig": "0.1.18"
56
59
  },
57
60
  "bin": {
58
61
  "create-qpq-app": "./lib/commonjs/bin/createQpqApp.js"
@@ -1,150 +1,102 @@
1
1
  # quidproquojs.com
2
2
 
3
- The QPQ framework's own website (app **qpqjs**), built with QPQ itself:
4
- TypeScript npm workspaces, AWS Lambda service backends bundled with Rspack,
5
- React microfrontend views built with Rspack + Module Federation, deployed with
6
- AWS CDK.
3
+ The quidproquo framework's own website (app **qpqjs**), built with quidproquo itself: TypeScript npm workspaces, AWS Lambda service backends bundled with Rspack, React microfrontend views built with Rspack and Module Federation, deployed with AWS CDK.
7
4
 
8
- This folder lives inside the quidproquo monorepo but is **not** one of its
9
- workspaces — it is a self-contained consumer app. All `quidproquo-*`
10
- dependencies are `file:../<pkg>` refs to the sibling packages, so the site
11
- always runs against the in-repo HEAD. Build the framework first
12
- (`npm install && npm run build` at the repo root) before installing here.
5
+ This folder lives inside the quidproquo monorepo but is **not** one of its workspaces. It is a self-contained consumer app. All `quidproquo-*` dependencies are `file:../<pkg>` refs to the sibling packages, so the site always runs against the in-repo HEAD. Build the framework first (`npm install && npm run build` at the repo root) before installing here.
6
+
7
+ It doubles as the `create-qpq-app` template: the scaffolder snapshots this workspace at publish time, so anything broken here is broken in every new app.
13
8
 
14
9
  ## Getting started
15
10
 
16
- > **Requires the repo's pinned Node version (see `.nvmrc` currently 24.x).**
17
- > Run `nvm use` **before** `npm install` — on an older Node, `npm install`
18
- > refuses to run (`engines` + `engine-strict`).
11
+ > Requires the repo's pinned Node version (see `.nvmrc`, currently 24.x). Run `nvm use` **before** `npm install`. On an older Node, `npm install` refuses to run (`engines` plus `engine-strict`).
19
12
 
20
13
  ```bash
21
- nvm use # ALWAYS FIRST switches to the Node version in .nvmrc
22
- npm install # installs deps + symlinks the sibling quidproquo-* packages (file: refs)
23
- npm run build # build every workspace (libs -> tsc -b to dist; services -> type-check)
24
- npm run go:dev # full local dev stack: api dev server (:8080) + all views dev servers
14
+ nvm use # always first: switches to the Node version in .nvmrc
15
+ npm install # deps, plus symlinks to the sibling quidproquo-* packages (file: refs)
16
+ npm run build # build every workspace (libs: tsc -b to dist; services: type-check)
17
+ npm run dev # full local dev stack: api dev server (:8080) and all views dev servers
25
18
  ```
26
19
 
27
- Smoke test once `go:dev` is up:
20
+ Smoke test once the dev server is up:
28
21
 
29
22
  ```bash
30
23
  curl -H "Host: qpqjs.development.localhost" http://localhost:8080/api/shell/v1/health
31
- # -> healthy response from the shell service
24
+ # healthy response from the shell service
32
25
  ```
33
26
 
34
27
  ## Layout
35
28
 
36
29
  ```
37
30
  apps/<app>/ # qpqjs
38
- deploy.config.json # { "prefix", "domain" } DNS config for deploy
39
- tsconfig.federated.json # GENERATED by `npm run prep` cross-view type aliases
31
+ deploy.config.json # { "prefix", "domain" }: dns config for deploy
32
+ tsconfig.federated.json # generated by `npm run prep`: cross-view type aliases
40
33
  packages/ # app-wide libs (config, constants, service-utils)
41
34
  services/<svc>/
42
- config, models, x-models, # per-service libs each builds to its own dist/
35
+ config, models, x-models, # per-service libs, each builds to its own dist/
43
36
  shared-logic, x-logic,
44
37
  service-utils
45
- service/ # Lambda backend (rspack bundle, built at deploy time)
46
- views/ # React microfrontend (Rspack + Module Federation)
47
- docusaurus/ # docs site (docs.quidproquojs.com) built first
38
+ service/ # lambda backend (rspack bundle, built at deploy time)
39
+ views/ # react microfrontend (rspack + module federation)
40
+ docusaurus/ # docs site (docs.quidproquojs.com), built first
48
41
  # (listed first in workspaces); the shell's 'docs'
49
42
  # web entry auto-uploads docusaurus/build at deploy
50
43
  ```
51
44
 
52
- There is no tools/ directory: all build/dev/deploy orchestration ships in the
53
- `quidproquo-cli` package (the `qpq` bin — the root npm scripts are thin
54
- aliases), with the rspack config builders in `quidproquo-deploy-rspack` and the
55
- generic CDK app in `quidproquo-deploy-awscdk`.
45
+ There is no tools/ directory. All build, dev, and deploy orchestration ships in the `quidproquo-cli` package (the `qpq` bin, which the root npm scripts alias), with the rspack config builders in `quidproquo-deploy-rspack` and the generic CDK app in `quidproquo-deploy-awscdk`.
56
46
 
57
47
  ## How it fits together
58
48
 
59
- - **Libraries** build to their own `dist/` with `tsc -b` (TypeScript project
60
- references, so only what changed rebuilds). Each lib's `package.json`
61
- `main`/`types`/`exports` point at `dist/src`, and npm workspaces symlink it
62
- into `node_modules/@qpqjs/*`, so imports
63
- resolve like any npm package. Libs build before services because the root
64
- `workspaces` array lists all lib globs ahead of `apps/*/services/*/service`.
65
- - **Service backends** are bundled to AWS Lambda by Rspack, programmatically
66
- at deploy time (`qpq go` calls `getServiceRspackConfig` from
67
- `quidproquo-deploy-rspack`) — there are no per-service `rspack.config.ts`
68
- files or `bundle` scripts. A service's `build` script only type-checks.
69
- - **Views** are microfrontends built by Rspack + `@module-federation/enhanced`.
70
- There are no per-view federation config files: exposes are computed at build
71
- time from `// federated.export` markers, and remotes are discovered from
72
- sibling views packages (dev port from each service's
73
- `defineDevServerOptions({ port })` in its `infrastructure.ts`). The
74
- only generated artifact is `apps/<app>/tsconfig.federated.json` — regenerate
75
- with `npm run prep` after adding or removing a marker.
76
- - **The dev server** (`qpq go:dev:api`, powered by `quidproquo-dev-server`) loads each service's
77
- `infrastructure.ts` directly — no synth needed, just built libs. Its bundle
78
- externalizes `node_modules` (an externals function in its rspack config) so native modules like
79
- `sqlite3` load at runtime from their install location.
80
- - **The `admin` service** owns the QPQ log/admin backbone: every service's
81
- config references `defineAdminSettings(Admin, …)` + `logServiceName: Admin`,
82
- so the dev server resolves log globals from the `admin` module. Running a
83
- single service without `admin` spams `Global config qpq-log-retention-days
84
- not found`.
49
+ - **Libraries** build to their own `dist/` with `tsc -b` (TypeScript project references, so only what changed rebuilds). Each lib's `package.json` `main`, `types`, and `exports` point at `dist/src`, and npm workspaces symlink it into `node_modules/@qpqjs/*`, so imports resolve like any npm package. Libs build before services because the root `workspaces` array lists all lib globs ahead of `apps/*/services/*/service`.
50
+ - **Service backends** are bundled to AWS Lambda by Rspack, programmatically at deploy time (`qpq go` calls `getServiceRspackConfig` from `quidproquo-deploy-rspack`). There are no per-service `rspack.config.ts` files or `bundle` scripts, and a service's `build` script only type-checks.
51
+ - **Views** are microfrontends built by Rspack and `@module-federation/enhanced`. There are no per-view federation config files: exposes are computed at build time from `// federated.export` markers, and remotes are discovered from sibling views packages (dev port from each service's `defineDevServerOptions({ port })` in its `infrastructure.ts`). The only generated artifact is `apps/<app>/tsconfig.federated.json`, regenerated with `npm run prep` after adding or removing a marker.
52
+ - **The dev server** (`npx qpq go:dev:api`, powered by `quidproquo-dev-server`) loads each service's `infrastructure.ts` directly, so no synth is needed, just built libs. Its bundle externalizes `node_modules` (an externals function in its rspack config) so native modules like `sqlite3` load at runtime from their install location.
53
+ - **The `admin` service** owns the log and admin backbone. Every service's config references `defineAdminSettings(Admin, …)` and `logServiceName: Admin`, so the dev server resolves log globals from the `admin` module. Running a single service without `admin` spams `Global config qpq-log-retention-days not found`.
85
54
 
86
55
  ## Commands
87
56
 
57
+ The root scripts are `build`, `validate-ts`, `lint`, `lint:fix`, `dev`, `deploy`, and `prep`. Anything else is a direct `npx qpq` call.
58
+
88
59
  ```bash
89
- npm run build # build only the libs (services/views are bundled, not built); scope with --workspace=@qpqjs/constants
90
- npm run validate-ts # TS check: build libs, then tsc-typecheck every service + views
91
- npm run prep # regenerate tsconfig.federated.json from // federated.export markers
92
- npm run go:dev # api + web dev servers in one process (one ctrl+c stops the lot)
93
- npm run go:dev:api # backend dev server only, on :8080, every service at /api/<svc>
94
- npm run go:dev:web # boot ALL views Rspack dev servers (host shell :3080 + remotes on their
95
- # ports); remotes resolve dynamically at runtime via mf-manifest.json.
96
- # Subset: npm run go:dev:web -- --only host,shell,design
60
+ npm run build # build only the libs (services and views are bundled, not built)
61
+ # scope with --workspace=@qpqjs/constants
62
+ npm run validate-ts # ts check: build libs, then typecheck every service and views
63
+ npm run prep # regenerate tsconfig.federated.json from // federated.export markers
64
+ npm run dev # api and web dev servers in one process (one ctrl+c stops the lot)
65
+
66
+ npx qpq go:dev:api # backend dev server only, on :8080, every service at /api/<svc>
67
+ npx qpq go:dev:web # all views rspack dev servers (host shell :3080, remotes on their
68
+ # ports); remotes resolve at runtime via mf-manifest.json
69
+ # subset: npx qpq go:dev:web --only host,shell,design
97
70
  ```
98
71
 
99
72
  ### App selection (multi-app)
100
73
 
101
- Every app-facing script (`prep`, `synth`, `go`, `go:docker`, `go:dev`,
102
- `go:dev:api`, `go:dev:web`) resolves its target app the same way:
74
+ Every app-facing command (`prep`, `synth`, `go`, `go:docker`, `go:dev`, `go:dev:api`, `go:dev:web`) resolves its target app the same way:
103
75
 
104
- 1. `--app <name>` **must come after `--`**: `npm run go:dev -- --app qpqjs`
105
- (this npm silently swallows flags before `--`)
106
- 2. the script's env var (`QPQ_DEV_APP` for dev, `DEPLOY_APP_NAME` for synth/deploy)
107
- 3. exactly one app under `apps/` auto-selected
108
- 4. interactive prompt (TTY)
76
+ 1. `--app <name>`. Through an npm script it **must come after `--`**: `npm run dev -- --app qpqjs`, because npm silently swallows flags before `--`
77
+ 2. the command's env var (`QPQ_DEV_APP` for dev, `DEPLOY_APP_NAME` for synth and deploy)
78
+ 3. exactly one app under `apps/`, which is then auto-selected
79
+ 4. interactive prompt, when attached to a TTY
109
80
  5. otherwise it prints the valid app list and exits 1
110
81
 
111
- `prep` and `synth` also accept `--app all`. `synth <service>` (bare positional)
112
- still infers the owning app. Unknown names print the valid list and exit 1.
82
+ `prep` and `synth` also accept `--app all`. A bare `qpq synth <service>` still infers the owning app. Unknown names print the valid list and exit 1.
113
83
 
114
84
  ## Deployment
115
85
 
116
86
  ```bash
117
- npm run synth # writes dist/apps/<app>/infrastructure/<svc>-config.json (for CDK deploy)
118
- npm run go # interactive AWS deploy: pick app -> services -> stacks (inf/api/web/views).
119
- # Bundles (rspack production) + cdk deploy + s3 sync per phase.
87
+ npm run deploy # docker deploy (qpq go:docker)
88
+ npx qpq synth # writes dist/apps/<app>/infrastructure/<svc>-config.json for cdk
89
+ npx qpq go # interactive aws deploy: pick app, services, stacks (inf/api/web/views)
90
+ # bundles (rspack production), cdk deploy, and s3 sync per phase
120
91
  ```
121
92
 
122
- `go` needs AWS credentials plus a deploy identity: either an
123
- `"environments"` map in `apps/<app>/deploy.config.json`
124
- (`{ "prefix", "domain", "environments": { "<env>": { "accountId", "region" } } }`,
125
- selected with `--env <name>`) or the legacy `ENVIRONMENT`/`AWS_DEFAULT_*` env
126
- vars. App-specific bootstrap/account extras live in `apps/<app>/bootstrap.qpq.ts`
127
- and `apps/<app>/account.qpq.ts` (config fragments; the identity plumbing is
128
- provided by the generic CDK app in `quidproquo-deploy-awscdk`).
129
-
130
- - Production views bundles get prod remote URLs
131
- (`https://views.<feature>.<env>.<domain>/<svc>`) derived from
132
- `deploy.config.json` + the service's QPQ config; dev bundles use localhost
133
- ports.
134
- - `cdk.context.json` at the repo root is CDK's regenerable Route53 lookup
135
- cache (written on first deploy; check it in so later synths need no live
136
- AWS lookups).
137
-
138
- ## Adding a service (pattern from `mini`)
139
-
140
- 1. Create its `config/models/x-models/shared-logic/x-logic/service-utils` + `service`.
141
- 2. Each lib: `package.json` with `"build": "tsc -b"` (+ the dist-pointing
142
- `main`/`types`/`exports`); `tsconfig.json` (extends root base, **no paths**,
143
- references `./tsconfig.lib.json`) + `tsconfig.lib.json` (`composite`,
144
- `outDir ./dist`, `rootDir .`, `references` to its workspace deps'
145
- `tsconfig.lib.json`). No root-level list to touch — `npm run build --workspaces`
146
- discovers the new lib automatically.
147
- 3. `service/`: add a `package.json` (`@qpqjs/<svc>-service`, `private`,
148
- `"build": "tsc -p tsconfig.app.json"`) and a `tsconfig.app.json`.
149
- No rspack.config.ts, no bundle script — `qpq go` bundles it by convention.
150
- `npm run build` then picks it up automatically.
93
+ `qpq go` needs AWS credentials plus a deploy identity: either an `"environments"` map in `apps/<app>/deploy.config.json` (`{ "prefix", "domain", "environments": { "<env>": { "accountId", "region" } } }`, selected with `--env <name>`) or the legacy `ENVIRONMENT` and `AWS_DEFAULT_*` env vars. App-specific bootstrap and account extras live in `apps/<app>/bootstrap.qpq.ts` and `apps/<app>/account.qpq.ts` as config fragments; the identity plumbing is provided by the generic CDK app in `quidproquo-deploy-awscdk`.
94
+
95
+ - Production views bundles get prod remote URLs (`https://views.<feature>.<env>.<domain>/<svc>`) derived from `deploy.config.json` plus the service's qpq config. Dev bundles use localhost ports.
96
+ - `cdk.context.json` at the repo root is CDK's regenerable Route53 lookup cache. It is written on the first deploy, and checking it in means later synths need no live AWS lookups.
97
+
98
+ ## Adding a service
99
+
100
+ 1. Create its `config`, `models`, `x-models`, `shared-logic`, `x-logic`, `service-utils`, and `service` packages.
101
+ 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.
102
+ 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.
@@ -3,6 +3,8 @@ export enum QpqjsServiceEnum {
3
3
  Auth = 'auth',
4
4
  Design = 'design',
5
5
  Shell = 'shell',
6
+ Test = 'test',
7
+ TestA = 'testa',
6
8
  }
7
9
 
8
10
  export type QpqjsServiceEnumValues = `${QpqjsServiceEnum}`;
@@ -1,3 +1,4 @@
1
1
  export * from './domain';
2
2
  export * from './QpqjsServiceEnum';
3
+ export * from './smokeProbe';
3
4
  export * from './userDirectory';
@@ -0,0 +1,13 @@
1
+ // Smoke probe resources owned by the test service and reached cross-service
2
+ // by testa (which declares them with owner: { module: test }). App-level
3
+ // because both services must agree on the names.
4
+ export const SMOKE_PROBE_STORE = 'smokeProbe';
5
+ // Lowercase with a hyphen: this becomes an S3 bucket name, which must be lowercase.
6
+ export const SMOKE_PROBE_DRIVE = 'smoke-probe';
7
+
8
+ // The testa service functions the cross-service smoke tests invoke, one per
9
+ // foreign grant (the store and the drive are separate IAM statements).
10
+ export const SMOKE_CROSS_SERVICE_KEY_VALUE_STORE_PROBE_FUNCTION_NAME =
11
+ 'crossKvsProbe';
12
+ export const SMOKE_CROSS_SERVICE_STORAGE_DRIVE_PROBE_FUNCTION_NAME =
13
+ 'crossDriveProbe';
@@ -1,20 +1,22 @@
1
1
  // federated.export: This file will be exported using module federation
2
2
 
3
- import { Features } from './components/Features';
3
+ import { Actions } from './components/Actions';
4
4
  import { Footer } from './components/Footer';
5
5
  import { Hero } from './components/Hero';
6
- import { Packages } from './components/Packages';
7
- import { Pipeline } from './components/Pipeline';
6
+ import { Infrastructure } from './components/Infrastructure';
7
+ import { Replay } from './components/Replay';
8
+ import { Testing } from './components/Testing';
8
9
  import { YieldLoop } from './components/YieldLoop';
9
10
  import './landing.css';
10
11
 
11
12
  export const LandingPage = () => (
12
13
  <main>
13
14
  <Hero />
14
- <Features />
15
15
  <YieldLoop />
16
- <Pipeline />
17
- <Packages />
16
+ <Replay />
17
+ <Testing />
18
+ <Infrastructure />
19
+ <Actions />
18
20
  <Footer />
19
21
  </main>
20
22
  );
@@ -0,0 +1,53 @@
1
+ type ActionDomain = {
2
+ domain: string;
3
+ requester: string;
4
+ };
5
+
6
+ // A sample, not the catalogue: enough to show the shape and the reach without
7
+ // turning the section into a reference page.
8
+ const DOMAINS: ActionDomain[] = [
9
+ { domain: 'key value store', requester: 'askKeyValueStoreGet' },
10
+ { domain: 'file', requester: 'askFileWriteTextContents' },
11
+ { domain: 'queue', requester: 'askQueueSendMessages' },
12
+ { domain: 'event bus', requester: 'askEventBusSendMessages' },
13
+ { domain: 'user directory', requester: 'askUserDirectoryCreateUser' },
14
+ { domain: 'websocket', requester: 'askWebsocketSendMessage' },
15
+ { domain: 'network', requester: 'askNetworkRequest' },
16
+ { domain: 'ai', requester: 'askAiPrompt' },
17
+ {
18
+ domain: 'graph database',
19
+ requester: 'askGraphDatabaseExecuteOpenCypherQuery',
20
+ },
21
+ { domain: 'crypto', requester: 'askCryptoEncrypt' },
22
+ { domain: 'metric', requester: 'askMetricPut' },
23
+ { domain: 'config', requester: 'askConfigGetSecret' },
24
+ ];
25
+
26
+ export function Actions() {
27
+ return (
28
+ <section className="section" id="actions">
29
+ <div className="section__head">
30
+ <p className="section__kicker">the surface</p>
31
+ <h2 className="section__title">What a story can ask for</h2>
32
+ <p className="section__sub">
33
+ Every capability is an action with a typed payload and a typed result.
34
+ Each platform supplies its own processor, so the story stays the same
35
+ wherever it runs.
36
+ </p>
37
+ </div>
38
+
39
+ <div className="action-grid">
40
+ {DOMAINS.map((entry) => (
41
+ <div key={entry.domain} className="action-cell">
42
+ <span className="action-cell__domain">{entry.domain}</span>
43
+ <code className="action-cell__requester">{entry.requester}</code>
44
+ </div>
45
+ ))}
46
+ </div>
47
+
48
+ <p className="action-note">
49
+ 25 domains · 91 action types · and your own, when you need one
50
+ </p>
51
+ </section>
52
+ );
53
+ }
@@ -8,7 +8,7 @@ const cm = (text: string) => <span className="tok-cm">{text}</span>;
8
8
  const pr = (text: string) => <span className="tok-pr">{text}</span>;
9
9
 
10
10
  const LINES: ReactNode[] = [
11
- <>{cm('// pure business logic no infrastructure')}</>,
11
+ <>{cm('// no SDK imports, no platform APIs')}</>,
12
12
  <>
13
13
  {kw('export function')}* {fn('askSendWelcomeEmail')}(
14
14
  </>,
@@ -23,7 +23,7 @@ const LINES: ReactNode[] = [
23
23
  <>&nbsp;</>,
24
24
  <>
25
25
  {' '}
26
- {kw('yield')}* {fn('askQueueSendMessage')}({str("'email'")}, {'{'}
26
+ {kw('yield')}* {fn('askQueueSendMessages')}({str("'email'")}, {'{'}
27
27
  </>,
28
28
  <>
29
29
  {' '}
@@ -37,7 +37,7 @@ const LINES: ReactNode[] = [
37
37
  <>&nbsp;</>,
38
38
  <>
39
39
  {' '}
40
- {kw('yield')}* {fn('askEventBusPublish')}({str("'welcomed'")}, {'{'} userId {'}'});
40
+ {kw('yield')}* {fn('askEventBusSendMessages')}({'{'} userId {'}'});
41
41
  </>,
42
42
  <>&nbsp;</>,
43
43
  <>
@@ -59,7 +59,7 @@ export function CodeWindow() {
59
59
  <pre className="code-window__body">
60
60
  <code>
61
61
  {LINES.map((line, index) => (
62
- <span className="code-line" key={index}>
62
+ <span key={index} className="code-line">
63
63
  <span className="code-line__num">{index + 1}</span>
64
64
  <span className="code-line__text">{line}</span>
65
65
  </span>
@@ -1,40 +1,29 @@
1
- import { useRef } from 'react';
2
-
3
1
  import { InstallChip } from './InstallChip';
4
- import { TronGrid } from './TronGrid';
5
2
 
6
3
  export function Footer() {
7
- const panelRef = useRef<HTMLDivElement>(null);
8
-
9
4
  return (
10
5
  <footer className="footer">
11
6
  <div className="footer__cta">
12
- <TronGrid avoidRefs={[panelRef]} />
13
- <div ref={panelRef} className="footer__cta-content">
14
- <p className="section__kicker">get started</p>
15
- <h2 className="footer__cta-title">
16
- Ready to write
17
- <br />
18
- <span className="hero__title-glow">your first story?</span>
19
- </h2>
20
- <p className="footer__cta-sub">
21
- One command scaffolds a full app — five services, a local dev
22
- server, a one-image docker deploy. Yield an action; the runtime
23
- handles the rest.
24
- </p>
25
- <div className="footer__cta-actions">
26
- <InstallChip />
27
- <a
28
- className="btn btn--ghost"
29
- href="https://github.com/joe-coady/quidproquo"
30
- rel="noreferrer"
31
- target="_blank"
32
- >
33
- Star on GitHub
34
- </a>
35
- </div>
7
+ <p className="section__kicker">get started</p>
8
+ <h2 className="footer__cta-title">Write your first story</h2>
9
+ <p className="footer__cta-sub">
10
+ One command scaffolds a full app: five services, a local dev server
11
+ and a one-image docker deploy. Yield an action, and the runtime takes
12
+ it from there.
13
+ </p>
14
+ <div className="footer__cta-actions">
15
+ <InstallChip />
16
+ <a
17
+ className="btn btn--ghost"
18
+ href="https://github.com/qpqjs/quidproquo"
19
+ rel="noreferrer"
20
+ target="_blank"
21
+ >
22
+ Star on GitHub
23
+ </a>
36
24
  </div>
37
25
  </div>
26
+
38
27
  <div className="footer__base">
39
28
  <div className="footer__base-inner">
40
29
  <span>quidproquo · MIT license</span>
@@ -1,60 +1,51 @@
1
- import { useRef } from 'react';
2
-
3
1
  import { CodeWindow } from './CodeWindow';
4
2
  import { InstallChip } from './InstallChip';
5
3
  import { NavBar } from './NavBar';
6
- import { TronGrid } from './TronGrid';
7
4
 
8
5
  export function Hero() {
9
- const copyRef = useRef<HTMLDivElement>(null);
10
- const panelRef = useRef<HTMLDivElement>(null);
11
-
12
6
  return (
13
- <section className="hero" id="top">
14
- <TronGrid avoidRefs={[copyRef, panelRef]} />
7
+ <>
15
8
  <NavBar />
16
9
 
17
- <div className="hero__inner">
18
- <div ref={copyRef} className="hero__copy">
19
- <span className="hero__badge">
20
- <span className="hero__badge-pulse" />
21
- functional · action-based · typescript
22
- </span>
10
+ <section className="hero" id="top">
11
+ <div aria-hidden="true" className="hero__grid" />
12
+ <div aria-hidden="true" className="hero__glow" />
13
+
14
+ <div className="hero__inner">
15
+ <p className="hero__kicker">functional · action-based · typescript</p>
23
16
 
24
17
  <h1 className="hero__title">
25
- Write pure stories.
18
+ Pure business logic.
26
19
  <br />
27
- <span className="hero__title-glow">Run them anywhere.</span>
20
+ <span className="hero__title-dim">Platform agnostic.</span>
28
21
  </h1>
29
22
 
30
23
  <p className="hero__sub">
31
- quidproquo is an action-based framework where business logic is a
32
- generator function a <em>story</em> that yields typed actions. The
33
- runtime decides how each action executes: AWS Lambda in production,
34
- Node on your machine, the browser in your app.
24
+ Your logic is a generator function (a <em>story</em>) that yields
25
+ typed actions, never a platform API. A processor per platform
26
+ decides how each action actually runs: Lambda, a container, the
27
+ browser.
35
28
  </p>
36
29
 
37
30
  <div className="hero__cta">
38
- <a className="btn btn--primary" href="#stories">
39
- Get started
31
+ <InstallChip />
32
+ <a className="btn btn--ghost" href="#loop">
33
+ See how it works
40
34
  <span className="btn__arrow">→</span>
41
35
  </a>
42
- <InstallChip />
43
36
  </div>
44
37
 
45
- <div className="hero__meta">
38
+ <p className="hero__meta">
46
39
  <span>MIT licensed</span>
47
- <span>zero side effects</span>
48
- <span>deploys itself with CDK</span>
49
- </div>
40
+ <span>zero side effects in your logic</span>
41
+ <span>infrastructure from config</span>
42
+ </p>
50
43
  </div>
51
44
 
52
- <div ref={panelRef} className="hero__panel">
45
+ <div className="hero__panel">
53
46
  <CodeWindow />
54
47
  </div>
55
- </div>
56
-
57
- <div aria-hidden="true" className="hero__fade" />
58
- </section>
48
+ </section>
49
+ </>
59
50
  );
60
51
  }