@qpqjs/cli 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. package/lib/commonjs/cli/commandMenu.js +5 -4
  2. package/lib/commonjs/cli/commandMenu.js.map +1 -1
  3. package/lib/commonjs/cli/runCli.js +15 -7
  4. package/lib/commonjs/cli/runCli.js.map +1 -1
  5. package/lib/commonjs/commands/checkCircular.js +15 -7
  6. package/lib/commonjs/commands/checkCircular.js.map +1 -1
  7. package/lib/commonjs/commands/clearResources.js +8 -14
  8. package/lib/commonjs/commands/clearResources.js.map +1 -1
  9. package/lib/commonjs/commands/go.js +3 -7
  10. package/lib/commonjs/commands/go.js.map +1 -1
  11. package/lib/commonjs/commands/goDev.js +4 -2
  12. package/lib/commonjs/commands/goDev.js.map +1 -1
  13. package/lib/commonjs/commands/goDevApi.js +27 -23
  14. package/lib/commonjs/commands/goDevApi.js.map +1 -1
  15. package/lib/commonjs/commands/goDevWeb.js +14 -9
  16. package/lib/commonjs/commands/goDevWeb.js.map +1 -1
  17. package/lib/commonjs/commands/goDocker.js +10 -13
  18. package/lib/commonjs/commands/goDocker.js.map +1 -1
  19. package/lib/commonjs/commands/hooks.js +4 -2
  20. package/lib/commonjs/commands/hooks.js.map +1 -1
  21. package/lib/commonjs/commands/migrate.js +11 -9
  22. package/lib/commonjs/commands/migrate.js.map +1 -1
  23. package/lib/commonjs/commands/prep.js +4 -2
  24. package/lib/commonjs/commands/prep.js.map +1 -1
  25. package/lib/commonjs/commands/publish.js +4 -7
  26. package/lib/commonjs/commands/publish.js.map +1 -1
  27. package/lib/commonjs/commands/scriptBuild.js +7 -5
  28. package/lib/commonjs/commands/scriptBuild.js.map +1 -1
  29. package/lib/commonjs/commands/scriptBuilderLayer.js +6 -4
  30. package/lib/commonjs/commands/scriptBuilderLayer.js.map +1 -1
  31. package/lib/commonjs/commands/scriptNew.js +7 -5
  32. package/lib/commonjs/commands/scriptNew.js.map +1 -1
  33. package/lib/commonjs/commands/setup.js +14 -22
  34. package/lib/commonjs/commands/setup.js.map +1 -1
  35. package/lib/commonjs/commands/synth.js +16 -20
  36. package/lib/commonjs/commands/synth.js.map +1 -1
  37. package/lib/commonjs/commands/teardown.js +8 -14
  38. package/lib/commonjs/commands/teardown.js.map +1 -1
  39. package/lib/commonjs/lib/CliError.d.ts +4 -0
  40. package/lib/commonjs/lib/CliError.js +14 -0
  41. package/lib/commonjs/lib/CliError.js.map +1 -0
  42. package/lib/commonjs/lib/Output.d.ts +12 -0
  43. package/lib/commonjs/lib/Output.js +3 -0
  44. package/lib/commonjs/lib/Output.js.map +1 -0
  45. package/lib/commonjs/lib/circularImports.d.ts +0 -1
  46. package/lib/commonjs/lib/circularImports.js +5 -6
  47. package/lib/commonjs/lib/circularImports.js.map +1 -1
  48. package/lib/commonjs/lib/clearResourcesPlan.d.ts +0 -1
  49. package/lib/commonjs/lib/clearResourcesPlan.js +12 -13
  50. package/lib/commonjs/lib/clearResourcesPlan.js.map +1 -1
  51. package/lib/commonjs/lib/createOutput.d.ts +2 -0
  52. package/lib/commonjs/lib/createOutput.js +39 -0
  53. package/lib/commonjs/lib/createOutput.js.map +1 -0
  54. package/lib/commonjs/lib/deployPrompts.d.ts +2 -1
  55. package/lib/commonjs/lib/deployPrompts.js +16 -16
  56. package/lib/commonjs/lib/deployPrompts.js.map +1 -1
  57. package/lib/commonjs/lib/devServerEntry.js +5 -4
  58. package/lib/commonjs/lib/devServerEntry.js.map +1 -1
  59. package/lib/commonjs/lib/devServerPorts.js +2 -4
  60. package/lib/commonjs/lib/devServerPorts.js.map +1 -1
  61. package/lib/commonjs/lib/discovery.d.ts +0 -2
  62. package/lib/commonjs/lib/discovery.js +11 -44
  63. package/lib/commonjs/lib/discovery.js.map +1 -1
  64. package/lib/commonjs/lib/hooks.js +5 -3
  65. package/lib/commonjs/lib/hooks.js.map +1 -1
  66. package/lib/commonjs/lib/killChildWithEscalation.js +3 -1
  67. package/lib/commonjs/lib/killChildWithEscalation.js.map +1 -1
  68. package/lib/commonjs/lib/killStaleListeners.js +24 -37
  69. package/lib/commonjs/lib/killStaleListeners.js.map +1 -1
  70. package/lib/commonjs/lib/prompts.d.ts +1 -0
  71. package/lib/commonjs/lib/prompts.js +15 -2
  72. package/lib/commonjs/lib/prompts.js.map +1 -1
  73. package/lib/commonjs/lib/qpqConfigs.d.ts +1 -0
  74. package/lib/commonjs/lib/qpqConfigs.js +11 -6
  75. package/lib/commonjs/lib/qpqConfigs.js.map +1 -1
  76. package/lib/commonjs/lib/requireDriverCapability.d.ts +7 -0
  77. package/lib/commonjs/lib/requireDriverCapability.js +17 -0
  78. package/lib/commonjs/lib/requireDriverCapability.js.map +1 -0
  79. package/lib/commonjs/lib/resolveAppSelection.d.ts +1 -0
  80. package/lib/commonjs/lib/resolveAppSelection.js +19 -12
  81. package/lib/commonjs/lib/resolveAppSelection.js.map +1 -1
  82. package/lib/commonjs/lib/resolveCommandContext.d.ts +12 -0
  83. package/lib/commonjs/lib/resolveCommandContext.js +26 -0
  84. package/lib/commonjs/lib/resolveCommandContext.js.map +1 -0
  85. package/lib/commonjs/lib/resolveDeployment.d.ts +0 -1
  86. package/lib/commonjs/lib/resolveDeployment.js +15 -10
  87. package/lib/commonjs/lib/resolveDeployment.js.map +1 -1
  88. package/lib/commonjs/lib/runCommand.d.ts +20 -0
  89. package/lib/commonjs/lib/runCommand.js +64 -34
  90. package/lib/commonjs/lib/runCommand.js.map +1 -1
  91. package/lib/commonjs/lib/runTasks.js +8 -4
  92. package/lib/commonjs/lib/runTasks.js.map +1 -1
  93. package/lib/commonjs/lib/timing.js +5 -3
  94. package/lib/commonjs/lib/timing.js.map +1 -1
  95. package/lib/commonjs/lib/typeWatcher.d.ts +2 -1
  96. package/lib/commonjs/lib/typeWatcher.js +6 -13
  97. package/lib/commonjs/lib/typeWatcher.js.map +1 -1
  98. package/lib/commonjs/lib/userScriptBuilderLayer.d.ts +0 -2
  99. package/lib/commonjs/lib/userScriptBuilderLayer.js +7 -8
  100. package/lib/commonjs/lib/userScriptBuilderLayer.js.map +1 -1
  101. package/lib/commonjs/lib/views.js +3 -2
  102. package/lib/commonjs/lib/views.js.map +1 -1
  103. package/lib/commonjs/lib/webAddressingEnv.d.ts +0 -2
  104. package/lib/commonjs/lib/webAddressingEnv.js +4 -4
  105. package/lib/commonjs/lib/webAddressingEnv.js.map +1 -1
  106. package/lib/commonjs/platforms/aws/awsCredentials.js +3 -1
  107. package/lib/commonjs/platforms/aws/awsCredentials.js.map +1 -1
  108. package/lib/commonjs/platforms/aws/cdkApp.js +1 -1
  109. package/lib/commonjs/platforms/aws/cdkApp.js.map +1 -1
  110. package/lib/commonjs/platforms/aws/clearResources.js +17 -26
  111. package/lib/commonjs/platforms/aws/clearResources.js.map +1 -1
  112. package/lib/commonjs/platforms/aws/getDeployEnv.d.ts +1 -0
  113. package/lib/commonjs/platforms/aws/getDeployEnv.js +12 -0
  114. package/lib/commonjs/platforms/aws/getDeployEnv.js.map +1 -0
  115. package/lib/commonjs/platforms/aws/go.js +17 -15
  116. package/lib/commonjs/platforms/aws/go.js.map +1 -1
  117. package/lib/commonjs/platforms/aws/goDocker.js +29 -26
  118. package/lib/commonjs/platforms/aws/goDocker.js.map +1 -1
  119. package/lib/commonjs/platforms/aws/goDockerManifest.js +6 -1
  120. package/lib/commonjs/platforms/aws/goDockerManifest.js.map +1 -1
  121. package/lib/commonjs/platforms/aws/publish.js +13 -11
  122. package/lib/commonjs/platforms/aws/publish.js.map +1 -1
  123. package/lib/commonjs/platforms/aws/remote.js +8 -7
  124. package/lib/commonjs/platforms/aws/remote.js.map +1 -1
  125. package/lib/commonjs/platforms/aws/setup/buildBucketNamesStep.js +4 -4
  126. package/lib/commonjs/platforms/aws/setup/buildBucketNamesStep.js.map +1 -1
  127. package/lib/commonjs/platforms/aws/setup/buildGithubDeployRoleStep.js +4 -3
  128. package/lib/commonjs/platforms/aws/setup/buildGithubDeployRoleStep.js.map +1 -1
  129. package/lib/commonjs/platforms/aws/stacks.d.ts +0 -1
  130. package/lib/commonjs/platforms/aws/stacks.js +17 -33
  131. package/lib/commonjs/platforms/aws/stacks.js.map +1 -1
  132. package/lib/commonjs/platforms/aws/teardown.js +9 -7
  133. package/lib/commonjs/platforms/aws/teardown.js.map +1 -1
  134. package/lib/commonjs/platforms/aws/viewsSync.js +23 -11
  135. package/lib/commonjs/platforms/aws/viewsSync.js.map +1 -1
  136. package/lib/commonjs/platforms/docker/go.js +20 -18
  137. package/lib/commonjs/platforms/docker/go.js.map +1 -1
  138. package/lib/commonjs/platforms/docker/index.js +5 -4
  139. package/lib/commonjs/platforms/docker/index.js.map +1 -1
  140. package/lib/commonjs/platforms/docker/parseMounts.js +3 -2
  141. package/lib/commonjs/platforms/docker/parseMounts.js.map +1 -1
  142. package/lib/commonjs/platforms/index.js +4 -2
  143. package/lib/commonjs/platforms/index.js.map +1 -1
  144. package/lib/commonjs/platforms/types.d.ts +2 -2
  145. package/lib/commonjs/platforms/types.js.map +1 -1
  146. package/lib/esm/cli/commandMenu.js +5 -4
  147. package/lib/esm/cli/commandMenu.js.map +1 -1
  148. package/lib/esm/cli/runCli.js +15 -7
  149. package/lib/esm/cli/runCli.js.map +1 -1
  150. package/lib/esm/commands/checkCircular.js +15 -7
  151. package/lib/esm/commands/checkCircular.js.map +1 -1
  152. package/lib/esm/commands/clearResources.js +8 -14
  153. package/lib/esm/commands/clearResources.js.map +1 -1
  154. package/lib/esm/commands/go.js +3 -7
  155. package/lib/esm/commands/go.js.map +1 -1
  156. package/lib/esm/commands/goDev.js +4 -2
  157. package/lib/esm/commands/goDev.js.map +1 -1
  158. package/lib/esm/commands/goDevApi.js +24 -21
  159. package/lib/esm/commands/goDevApi.js.map +1 -1
  160. package/lib/esm/commands/goDevWeb.js +13 -9
  161. package/lib/esm/commands/goDevWeb.js.map +1 -1
  162. package/lib/esm/commands/goDocker.js +10 -13
  163. package/lib/esm/commands/goDocker.js.map +1 -1
  164. package/lib/esm/commands/hooks.js +4 -2
  165. package/lib/esm/commands/hooks.js.map +1 -1
  166. package/lib/esm/commands/migrate.js +9 -7
  167. package/lib/esm/commands/migrate.js.map +1 -1
  168. package/lib/esm/commands/prep.js +4 -2
  169. package/lib/esm/commands/prep.js.map +1 -1
  170. package/lib/esm/commands/publish.js +4 -7
  171. package/lib/esm/commands/publish.js.map +1 -1
  172. package/lib/esm/commands/scriptBuild.js +7 -5
  173. package/lib/esm/commands/scriptBuild.js.map +1 -1
  174. package/lib/esm/commands/scriptBuilderLayer.js +6 -4
  175. package/lib/esm/commands/scriptBuilderLayer.js.map +1 -1
  176. package/lib/esm/commands/scriptNew.js +7 -5
  177. package/lib/esm/commands/scriptNew.js.map +1 -1
  178. package/lib/esm/commands/setup.js +14 -22
  179. package/lib/esm/commands/setup.js.map +1 -1
  180. package/lib/esm/commands/synth.js +18 -22
  181. package/lib/esm/commands/synth.js.map +1 -1
  182. package/lib/esm/commands/teardown.js +8 -14
  183. package/lib/esm/commands/teardown.js.map +1 -1
  184. package/lib/esm/lib/CliError.d.ts +4 -0
  185. package/lib/esm/lib/CliError.js +11 -0
  186. package/lib/esm/lib/CliError.js.map +1 -0
  187. package/lib/esm/lib/Output.d.ts +12 -0
  188. package/lib/esm/lib/Output.js +2 -0
  189. package/lib/esm/lib/Output.js.map +1 -0
  190. package/lib/esm/lib/circularImports.d.ts +0 -1
  191. package/lib/esm/lib/circularImports.js +4 -4
  192. package/lib/esm/lib/circularImports.js.map +1 -1
  193. package/lib/esm/lib/clearResourcesPlan.d.ts +0 -1
  194. package/lib/esm/lib/clearResourcesPlan.js +12 -12
  195. package/lib/esm/lib/clearResourcesPlan.js.map +1 -1
  196. package/lib/esm/lib/createOutput.d.ts +2 -0
  197. package/lib/esm/lib/createOutput.js +35 -0
  198. package/lib/esm/lib/createOutput.js.map +1 -0
  199. package/lib/esm/lib/deployPrompts.d.ts +2 -1
  200. package/lib/esm/lib/deployPrompts.js +17 -17
  201. package/lib/esm/lib/deployPrompts.js.map +1 -1
  202. package/lib/esm/lib/devServerEntry.js +5 -4
  203. package/lib/esm/lib/devServerEntry.js.map +1 -1
  204. package/lib/esm/lib/devServerPorts.js +2 -3
  205. package/lib/esm/lib/devServerPorts.js.map +1 -1
  206. package/lib/esm/lib/discovery.d.ts +0 -2
  207. package/lib/esm/lib/discovery.js +10 -38
  208. package/lib/esm/lib/discovery.js.map +1 -1
  209. package/lib/esm/lib/hooks.js +5 -3
  210. package/lib/esm/lib/hooks.js.map +1 -1
  211. package/lib/esm/lib/killChildWithEscalation.js +3 -1
  212. package/lib/esm/lib/killChildWithEscalation.js.map +1 -1
  213. package/lib/esm/lib/killStaleListeners.js +24 -37
  214. package/lib/esm/lib/killStaleListeners.js.map +1 -1
  215. package/lib/esm/lib/prompts.d.ts +1 -0
  216. package/lib/esm/lib/prompts.js +13 -1
  217. package/lib/esm/lib/prompts.js.map +1 -1
  218. package/lib/esm/lib/qpqConfigs.d.ts +1 -0
  219. package/lib/esm/lib/qpqConfigs.js +9 -5
  220. package/lib/esm/lib/qpqConfigs.js.map +1 -1
  221. package/lib/esm/lib/requireDriverCapability.d.ts +7 -0
  222. package/lib/esm/lib/requireDriverCapability.js +13 -0
  223. package/lib/esm/lib/requireDriverCapability.js.map +1 -0
  224. package/lib/esm/lib/resolveAppSelection.d.ts +1 -0
  225. package/lib/esm/lib/resolveAppSelection.js +17 -11
  226. package/lib/esm/lib/resolveAppSelection.js.map +1 -1
  227. package/lib/esm/lib/resolveCommandContext.d.ts +12 -0
  228. package/lib/esm/lib/resolveCommandContext.js +12 -0
  229. package/lib/esm/lib/resolveCommandContext.js.map +1 -0
  230. package/lib/esm/lib/resolveDeployment.d.ts +0 -1
  231. package/lib/esm/lib/resolveDeployment.js +13 -8
  232. package/lib/esm/lib/resolveDeployment.js.map +1 -1
  233. package/lib/esm/lib/runCommand.d.ts +20 -0
  234. package/lib/esm/lib/runCommand.js +52 -31
  235. package/lib/esm/lib/runCommand.js.map +1 -1
  236. package/lib/esm/lib/runTasks.js +8 -4
  237. package/lib/esm/lib/runTasks.js.map +1 -1
  238. package/lib/esm/lib/timing.js +5 -3
  239. package/lib/esm/lib/timing.js.map +1 -1
  240. package/lib/esm/lib/typeWatcher.d.ts +2 -1
  241. package/lib/esm/lib/typeWatcher.js +6 -13
  242. package/lib/esm/lib/typeWatcher.js.map +1 -1
  243. package/lib/esm/lib/userScriptBuilderLayer.d.ts +0 -2
  244. package/lib/esm/lib/userScriptBuilderLayer.js +5 -5
  245. package/lib/esm/lib/userScriptBuilderLayer.js.map +1 -1
  246. package/lib/esm/lib/views.js +3 -2
  247. package/lib/esm/lib/views.js.map +1 -1
  248. package/lib/esm/lib/webAddressingEnv.d.ts +0 -2
  249. package/lib/esm/lib/webAddressingEnv.js +1 -1
  250. package/lib/esm/lib/webAddressingEnv.js.map +1 -1
  251. package/lib/esm/platforms/aws/awsCredentials.js +3 -1
  252. package/lib/esm/platforms/aws/awsCredentials.js.map +1 -1
  253. package/lib/esm/platforms/aws/cdkApp.js +1 -1
  254. package/lib/esm/platforms/aws/cdkApp.js.map +1 -1
  255. package/lib/esm/platforms/aws/clearResources.js +18 -26
  256. package/lib/esm/platforms/aws/clearResources.js.map +1 -1
  257. package/lib/esm/platforms/aws/getDeployEnv.d.ts +1 -0
  258. package/lib/esm/platforms/aws/getDeployEnv.js +8 -0
  259. package/lib/esm/platforms/aws/getDeployEnv.js.map +1 -0
  260. package/lib/esm/platforms/aws/go.js +17 -15
  261. package/lib/esm/platforms/aws/go.js.map +1 -1
  262. package/lib/esm/platforms/aws/goDocker.js +29 -26
  263. package/lib/esm/platforms/aws/goDocker.js.map +1 -1
  264. package/lib/esm/platforms/aws/goDockerManifest.js +6 -1
  265. package/lib/esm/platforms/aws/goDockerManifest.js.map +1 -1
  266. package/lib/esm/platforms/aws/publish.js +13 -11
  267. package/lib/esm/platforms/aws/publish.js.map +1 -1
  268. package/lib/esm/platforms/aws/remote.js +9 -7
  269. package/lib/esm/platforms/aws/remote.js.map +1 -1
  270. package/lib/esm/platforms/aws/setup/buildBucketNamesStep.js +2 -2
  271. package/lib/esm/platforms/aws/setup/buildBucketNamesStep.js.map +1 -1
  272. package/lib/esm/platforms/aws/setup/buildGithubDeployRoleStep.js +4 -3
  273. package/lib/esm/platforms/aws/setup/buildGithubDeployRoleStep.js.map +1 -1
  274. package/lib/esm/platforms/aws/stacks.d.ts +0 -1
  275. package/lib/esm/platforms/aws/stacks.js +20 -32
  276. package/lib/esm/platforms/aws/stacks.js.map +1 -1
  277. package/lib/esm/platforms/aws/teardown.js +9 -7
  278. package/lib/esm/platforms/aws/teardown.js.map +1 -1
  279. package/lib/esm/platforms/aws/viewsSync.js +22 -10
  280. package/lib/esm/platforms/aws/viewsSync.js.map +1 -1
  281. package/lib/esm/platforms/docker/go.js +21 -19
  282. package/lib/esm/platforms/docker/go.js.map +1 -1
  283. package/lib/esm/platforms/docker/index.js +5 -4
  284. package/lib/esm/platforms/docker/index.js.map +1 -1
  285. package/lib/esm/platforms/docker/parseMounts.js +3 -2
  286. package/lib/esm/platforms/docker/parseMounts.js.map +1 -1
  287. package/lib/esm/platforms/index.js +4 -2
  288. package/lib/esm/platforms/index.js.map +1 -1
  289. package/lib/esm/platforms/types.d.ts +2 -2
  290. package/lib/esm/platforms/types.js.map +1 -1
  291. package/package.json +28 -15
  292. package/templates/user-script/README.md +1 -1
@@ -1,26 +1,27 @@
1
- // Docker platform deploy (`qpq go` with platform 'docker') — proof-of-concept
1
+ // Docker platform deploy (`qpq go` with platform 'docker'), proof-of-concept
2
2
  // self-hosting: bakes the QPQ dev server (a full local platform emulation)
3
3
  // plus every service of the app and its pre-built views into one docker image.
4
4
  //
5
5
  // 1. Build workspace packages, then the dev-server bundle (all services).
6
6
  // 2. Build every views microfrontend with a same-origin module-federation
7
7
  // remote base (/<views subdomain>/<svc>), mirroring the AWS layout.
8
- // 3. Assemble an image context under dist/qpq/docker-image/<app>/ — server
8
+ // 3. Assemble an image context under dist/qpq/docker-image/<app>/, server
9
9
  // bundle, web root (every web entry, placed by its port or its domain),
10
10
  // a workspaces-stripped package.json for runtime deps, and the
11
11
  // locally-built quidproquo packages as a vendor overlay.
12
12
  // 4. docker build (buildx with a push when the deployment names a registry or
13
13
  // a target platform), write a docker-compose.yml, print how to run it.
14
14
  //
15
- // Not production-grade (single process, sqlite KVS, in-memory queues) —
15
+ // Not production-grade (single process, sqlite KVS, in-memory queues):
16
16
  // it's the whole product on one box with one command.
17
17
  import { getQpqAppDeployment } from '@qpqjs/config-aws';
18
- import { isQpqPackageName, QpqDeployEnvVar } from '@qpqjs/core';
18
+ import { getDevServerDistPath, getDockerImageContextPath, isQpqPackageName, QpqDeployEnvVar } from '@qpqjs/core';
19
19
  import { getAppServiceQpqConfigs, getDevServerRspackConfig, listInstalledQpqPackageNames, runRspack } from '@qpqjs/deploy-rspack';
20
20
  import { getWebEntryDir, getWebEntryPlacements } from '@qpqjs/dev-server';
21
21
  import { FEDERATED_VIEWS_SUBDOMAIN } from '@qpqjs/webserver';
22
22
  import fs from 'fs';
23
23
  import path from 'path';
24
+ import { createOutput } from '../../lib/createOutput';
24
25
  import { writeDevServerEntry, writeUserScriptChildEntry } from '../../lib/devServerEntry';
25
26
  import { readDevServerPorts } from '../../lib/devServerPorts';
26
27
  import { getRoot, getServiceNamesWithViews } from '../../lib/discovery';
@@ -37,7 +38,8 @@ import { getDockerPlatformSettings } from './getDockerPlatformSettings';
37
38
  import { getImageName } from './getImageName';
38
39
  import { resolvePortMappings } from './resolvePortMappings';
39
40
  import { writeComposeFile } from './writeComposeFile';
40
- const getImageContextDir = (root, appName) => path.join(root, 'dist', 'qpq', 'docker-image', appName);
41
+ const out = createOutput('docker');
42
+ const getImageContextDir = (root, appName) => getDockerImageContextPath(root, appName);
41
43
  // Every web entry's files go where the runtime looks for them. The federated views entry
42
44
  // is assembled from every service's views build (one folder per service, as on AWS);
43
45
  // anything else is its own buildPath. A missing build fails here rather than serving an
@@ -84,12 +86,12 @@ const writeDockerfile = (contextDir, containerPorts) => {
84
86
  };
85
87
  // The consumer root package.json, stripped to what the image's npm install
86
88
  // needs: runtime dependencies (+ overrides). Workspaces/scripts/devDeps are
87
- // host-only concerns — the workspace packages themselves are bundled into the
89
+ // host-only concerns, the workspace packages themselves are bundled into the
88
90
  // server bundle from source.
89
91
  //
90
92
  // quidproquo deps declared as file: refs (a consumer living beside the qpq
91
93
  // monorepo) point outside the image context, where npm install would leave
92
- // dangling symlinks — rewrite them to the vendored copies inside the context.
94
+ // dangling symlinks, rewrite them to the vendored copies inside the context.
93
95
  const writeImagePackageJson = (root, contextDir) => {
94
96
  const rootPackageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
95
97
  const dependencies = { ...(rootPackageJson.dependencies ?? {}) };
@@ -110,7 +112,7 @@ const writeImagePackageJson = (root, contextDir) => {
110
112
  // Copy the locally-built quidproquo packages (which may be npm-linked
111
113
  // checkouts newer than the registry) into vendor/ so the image runs the same
112
114
  // qpq code the bundle was built against. Follows the node_modules symlinks;
113
- // lib/config only — no node_modules, no src.
115
+ // lib/config only, no node_modules, no src.
114
116
  const vendorQuidproquoPackages = (root, contextDir) => {
115
117
  const nodeModules = path.join(root, 'node_modules');
116
118
  const vendorDir = path.join(contextDir, 'vendor');
@@ -135,7 +137,7 @@ export const dockerGo = async (appName, plan) => {
135
137
  return;
136
138
  }
137
139
  if (plan.kind === 'account' || plan.kind === 'bootstrap') {
138
- console.log(`Nothing to do — the docker platform has no ${plan.kind} stacks.`);
140
+ out.log(`Nothing to do — the docker platform has no ${plan.kind} stacks.`);
139
141
  return;
140
142
  }
141
143
  const root = getRoot();
@@ -146,16 +148,16 @@ export const dockerGo = async (appName, plan) => {
146
148
  const containerName = `qpq-${applicationName}`;
147
149
  const volumeName = `${containerName}-data`;
148
150
  // The dev server hosts every service of the app, so per-service/stack
149
- // selections don't apply — the image is always the whole app.
150
- console.log(`\n\nBuilding docker image [${imageName}] — the whole app deploys as one image\n\n`);
151
+ // selections don't apply, the image is always the whole app.
152
+ out.log(`\n\nBuilding docker image [${imageName}] — the whole app deploys as one image\n\n`);
151
153
  logTimeStart('totalTime');
152
154
  await runAppHook(appName, 'predeploy');
153
155
  // Workspace packages resolve through their built dist/ (package.json main),
154
156
  // so bundles would ship stale code unless every lib is tsc'd first.
155
- console.log('Building workspace packages');
157
+ out.log('Building workspace packages');
156
158
  assertNoFailures('Workspace build', await runHookForAppPackages('build', appName, getDefaultHookJobs()));
157
159
  // ---- Server bundle: the dev server + every service, one main.js ----
158
- console.log('Bundling server (dev server + all services)');
160
+ out.log('Bundling server (dev server + all services)');
159
161
  const qpqConfigs = getAppServiceQpqConfigs(root, appName);
160
162
  // Resolved before anything slow runs, so a bad port or domain fails the build up front.
161
163
  const devServerPorts = readDevServerPorts(appName);
@@ -176,21 +178,21 @@ export const dockerGo = async (appName, plan) => {
176
178
  process.env.QPQ_VIEWS_REMOTE_BASE = `/${FEDERATED_VIEWS_SUBDOMAIN}`;
177
179
  const viewServices = getServiceNamesWithViews(appName);
178
180
  for (const serviceName of viewServices) {
179
- console.log(`Bundling views: [${serviceName}]`);
181
+ out.log(`Bundling views: [${serviceName}]`);
180
182
  await bundleViews(appName, serviceName);
181
183
  }
182
184
  delete process.env.QPQ_VIEWS_REMOTE_BASE;
183
185
  clearWebAddressingEnv();
184
186
  // ---- Assemble the image context ----
185
- console.log('Assembling image context');
187
+ out.log('Assembling image context');
186
188
  const contextDir = getImageContextDir(root, appName);
187
189
  fs.rmSync(contextDir, { recursive: true, force: true });
188
190
  fs.mkdirSync(contextDir, { recursive: true });
189
191
  writeDockerfile(contextDir, containerPorts);
190
192
  writeImagePackageJson(root, contextDir);
191
193
  const vendored = vendorQuidproquoPackages(root, contextDir);
192
- console.log(`Vendored ${vendored} quidproquo packages`);
193
- fs.cpSync(path.join(root, 'dist', 'qpq', 'dev-server'), path.join(contextDir, 'server'), { recursive: true });
194
+ out.log(`Vendored ${vendored} quidproquo packages`);
195
+ fs.cpSync(getDevServerDistPath(root), path.join(contextDir, 'server'), { recursive: true });
194
196
  for (const entry of [...webEntryRoutes, ...webEntryHosts]) {
195
197
  copyWebEntryContent(appName, contextDir, entry, viewServices);
196
198
  }
@@ -206,7 +208,7 @@ export const dockerGo = async (appName, plan) => {
206
208
  publicFileStoragePort: mapHostPort(devServerPorts.fileStorage),
207
209
  });
208
210
  // ---- Build the image ----
209
- console.log(`Building docker image${dockerSettings.arch ? ` for ${dockerSettings.arch}` : ''}${dockerSettings.registry ? `, pushing to ${dockerSettings.registry}` : ''}`);
211
+ out.log(`Building docker image${dockerSettings.arch ? ` for ${dockerSettings.arch}` : ''}${dockerSettings.registry ? `, pushing to ${dockerSettings.registry}` : ''}`);
210
212
  await buildImage(imageName, contextDir, dockerSettings);
211
213
  logTimeEnd('totalTime');
212
214
  const hostUrl = (containerPort) => {
@@ -222,7 +224,7 @@ export const dockerGo = async (appName, plan) => {
222
224
  const onHost = dockerSettings.registry
223
225
  ? `On the host (Unraid: Compose Manager, or any docker host), copy the compose file there and run:`
224
226
  : `Run it here:`;
225
- console.log(`
227
+ out.log(`
226
228
  Done. The image is ${where}.
227
229
 
228
230
  ${onHost}
@@ -1 +1 @@
1
- {"version":3,"file":"go.js","sourceRoot":"","sources":["../../../../src/platforms/docker/go.ts"],"names":[],"mappings":"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","sourcesContent":["// Docker platform deploy (`qpq go` with platform 'docker') — proof-of-concept\n// self-hosting: bakes the QPQ dev server (a full local platform emulation)\n// plus every service of the app and its pre-built views into one docker image.\n//\n// 1. Build workspace packages, then the dev-server bundle (all services).\n// 2. Build every views microfrontend with a same-origin module-federation\n// remote base (/<views subdomain>/<svc>), mirroring the AWS layout.\n// 3. Assemble an image context under dist/qpq/docker-image/<app>/ — server\n// bundle, web root (every web entry, placed by its port or its domain),\n// a workspaces-stripped package.json for runtime deps, and the\n// locally-built quidproquo packages as a vendor overlay.\n// 4. docker build (buildx with a push when the deployment names a registry or\n// a target platform), write a docker-compose.yml, print how to run it.\n//\n// Not production-grade (single process, sqlite KVS, in-memory queues) —\n// it's the whole product on one box with one command.\nimport { getQpqAppDeployment } from '@qpqjs/config-aws';\nimport { isQpqPackageName, QpqDeployEnvVar } from '@qpqjs/core';\nimport { getAppServiceQpqConfigs, getDevServerRspackConfig, listInstalledQpqPackageNames, runRspack } from '@qpqjs/deploy-rspack';\nimport { getWebEntryDir, getWebEntryPlacements, WebEntryHost, WebEntryRoute } from '@qpqjs/dev-server';\nimport { FEDERATED_VIEWS_SUBDOMAIN } from '@qpqjs/webserver';\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { DeployPlan } from '../../lib/deployPrompts';\nimport { writeDevServerEntry, writeUserScriptChildEntry } from '../../lib/devServerEntry';\nimport { readDevServerPorts } from '../../lib/devServerPorts';\nimport { getRoot, getServiceNamesWithViews } from '../../lib/discovery';\nimport { getDefaultHookJobs } from '../../lib/getDefaultHookJobs';\nimport { runAppHook, runHookForAppPackages } from '../../lib/hooks';\nimport { getOwnPackageRoot } from '../../lib/packageRoot';\nimport { runCommand } from '../../lib/runCommand';\nimport { assertNoFailures } from '../../lib/runTasks';\nimport { logTimeEnd, logTimeStart } from '../../lib/timing';\nimport { bundleViews, getViewsDistDir } from '../../lib/views';\nimport { clearWebAddressingEnv, setWebAddressingEnv } from '../../lib/webAddressingEnv';\nimport { getContainerPorts } from './getContainerPorts';\nimport { getDockerPlatformSettings, ParsedDockerPlatformSettings } from './getDockerPlatformSettings';\nimport { getImageName } from './getImageName';\nimport { resolvePortMappings } from './resolvePortMappings';\nimport { writeComposeFile } from './writeComposeFile';\n\nconst getImageContextDir = (root: string, appName: string): string => path.join(root, 'dist', 'qpq', 'docker-image', appName);\n\n// Every web entry's files go where the runtime looks for them. The federated views entry\n// is assembled from every service's views build (one folder per service, as on AWS);\n// anything else is its own buildPath. A missing build fails here rather than serving an\n// empty site later.\nconst copyWebEntryContent = (appName: string, contextDir: string, entry: WebEntryHost | WebEntryRoute, viewServices: string[]): void => {\n const label = `${entry.service}/${entry.entryName}`;\n const targetDir = getWebEntryDir(path.join(contextDir, 'web'), entry);\n\n if (entry.webEntry.domain.subDomainName === FEDERATED_VIEWS_SUBDOMAIN) {\n for (const serviceName of viewServices) {\n fs.cpSync(getViewsDistDir(appName, serviceName), path.join(targetDir, serviceName), { recursive: true });\n }\n return;\n }\n\n // A standalone host entry serves its own service's views build, as on AWS.\n if (entry.webEntry.storageDrive.syncServiceViews) {\n fs.cpSync(getViewsDistDir(appName, entry.service), targetDir, { recursive: true });\n return;\n }\n\n if (!entry.webEntry.buildPath) {\n throw new Error(`Web entry ${label} has no buildPath, so there is nothing to serve`);\n }\n const buildDir = path.resolve(entry.configRoot, entry.webEntry.buildPath);\n if (!fs.existsSync(path.join(buildDir, entry.webEntry.indexRoot))) {\n throw new Error(`Web entry ${label} has no ${entry.webEntry.indexRoot} under ${buildDir}; build it before qpq go`);\n }\n fs.cpSync(buildDir, targetDir, { recursive: true });\n};\n\n// Plain `docker build` into the local store unless the deployment asks for a registry or a\n// target platform, which need buildx: `--push` sends a cross-platform image straight to the\n// registry, `--load` keeps a same-machine one local.\nconst buildImage = async (imageName: string, contextDir: string, settings: ParsedDockerPlatformSettings): Promise<void> => {\n if (!settings.registry && !settings.arch) {\n await runCommand('docker', ['build', '-t', imageName, contextDir]);\n return;\n }\n\n const platformArgs = settings.arch ? ['--platform', settings.arch] : [];\n await runCommand('docker', ['buildx', 'build', ...platformArgs, '-t', imageName, settings.registry ? '--push' : '--load', contextDir]);\n};\n\n// The Dockerfile is shared; only its EXPOSE line depends on the app.\nconst writeDockerfile = (contextDir: string, containerPorts: number[]): void => {\n const template = fs.readFileSync(path.join(getOwnPackageRoot(), 'docker', 'dev-server', 'Dockerfile'), 'utf8');\n const dockerfile = template.replace(/^EXPOSE .*$/m, `EXPOSE ${containerPorts.join(' ')}`);\n fs.writeFileSync(path.join(contextDir, 'Dockerfile'), dockerfile);\n};\n\n// The consumer root package.json, stripped to what the image's npm install\n// needs: runtime dependencies (+ overrides). Workspaces/scripts/devDeps are\n// host-only concerns — the workspace packages themselves are bundled into the\n// server bundle from source.\n//\n// quidproquo deps declared as file: refs (a consumer living beside the qpq\n// monorepo) point outside the image context, where npm install would leave\n// dangling symlinks — rewrite them to the vendored copies inside the context.\nconst writeImagePackageJson = (root: string, contextDir: string): void => {\n const rootPackageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));\n\n const dependencies: Record<string, string> = { ...(rootPackageJson.dependencies ?? {}) };\n for (const [name, version] of Object.entries(dependencies)) {\n if (isQpqPackageName(name) && version.startsWith('file:')) {\n dependencies[name] = `file:./vendor/${name}`;\n }\n }\n\n const imagePackageJson = {\n name: `${rootPackageJson.name}-qpq-docker`,\n version: rootPackageJson.version ?? '0.0.0',\n private: true,\n dependencies,\n overrides: rootPackageJson.overrides,\n };\n\n fs.writeFileSync(path.join(contextDir, 'package.json'), JSON.stringify(imagePackageJson, null, 2) + '\\n');\n};\n\n// Copy the locally-built quidproquo packages (which may be npm-linked\n// checkouts newer than the registry) into vendor/ so the image runs the same\n// qpq code the bundle was built against. Follows the node_modules symlinks;\n// lib/config only — no node_modules, no src.\nconst vendorQuidproquoPackages = (root: string, contextDir: string): number => {\n const nodeModules = path.join(root, 'node_modules');\n const vendorDir = path.join(contextDir, 'vendor');\n let vendored = 0;\n\n for (const name of listInstalledQpqPackageNames(nodeModules)) {\n const packageDir = fs.realpathSync(path.join(nodeModules, name));\n const targetDir = path.join(vendorDir, name);\n fs.mkdirSync(targetDir, { recursive: true });\n\n fs.copyFileSync(path.join(packageDir, 'package.json'), path.join(targetDir, 'package.json'));\n for (const sub of ['lib', 'config']) {\n const subDir = path.join(packageDir, sub);\n if (fs.existsSync(subDir)) {\n fs.cpSync(subDir, path.join(targetDir, sub), { recursive: true, dereference: true });\n }\n }\n vendored += 1;\n }\n\n return vendored;\n};\n\nexport const dockerGo = async (appName: string, plan: DeployPlan): Promise<void> => {\n if (plan.kind === 'cancelled') {\n return;\n }\n\n if (plan.kind === 'account' || plan.kind === 'bootstrap') {\n console.log(`Nothing to do — the docker platform has no ${plan.kind} stacks.`);\n return;\n }\n\n const root = getRoot();\n const deploymentName = process.env[QpqDeployEnvVar.deployName]!;\n const dockerSettings = getDockerPlatformSettings(deploymentName, getQpqAppDeployment(root, appName, deploymentName));\n\n const applicationName = process.env[QpqDeployEnvVar.applicationName]!;\n const imageName = getImageName(applicationName, dockerSettings);\n const containerName = `qpq-${applicationName}`;\n const volumeName = `${containerName}-data`;\n\n // The dev server hosts every service of the app, so per-service/stack\n // selections don't apply — the image is always the whole app.\n console.log(`\\n\\nBuilding docker image [${imageName}] — the whole app deploys as one image\\n\\n`);\n\n logTimeStart('totalTime');\n\n await runAppHook(appName, 'predeploy');\n\n // Workspace packages resolve through their built dist/ (package.json main),\n // so bundles would ship stale code unless every lib is tsc'd first.\n console.log('Building workspace packages');\n assertNoFailures('Workspace build', await runHookForAppPackages('build', appName, getDefaultHookJobs()));\n\n // ---- Server bundle: the dev server + every service, one main.js ----\n console.log('Bundling server (dev server + all services)');\n const qpqConfigs = getAppServiceQpqConfigs(root, appName);\n\n // Resolved before anything slow runs, so a bad port or domain fails the build up front.\n const devServerPorts = readDevServerPorts(appName);\n const { hosts: webEntryHosts, routes: webEntryRoutes } = getWebEntryPlacements(qpqConfigs, Object.values(devServerPorts));\n const containerPorts = getContainerPorts(devServerPorts, webEntryHosts);\n const portMappings = resolvePortMappings(deploymentName, dockerSettings, devServerPorts.api, containerPorts);\n const mapHostPort = (containerPort: number): number => portMappings.find((mapping) => mapping.container === containerPort)?.host ?? containerPort;\n\n // Nothing deploys into the container, so the image runs its own pending migrations on start.\n const entry = writeDevServerEntry(root, appName, 'migrate-then-serve');\n const userScriptChildEntry = writeUserScriptChildEntry(root);\n // The image installs its own node_modules next to the bundle, so externals\n // must stay bare; host-resolved absolute paths do not exist in the container.\n await runRspack(getDevServerRspackConfig({ root, entry, userScriptChildEntry, qpqConfigs, portableExternals: true }));\n\n // ---- Views: production builds with same-origin federation remotes ----\n // The browser reaches everything on the page's own host, on the HOST side of the port\n // mappings; an unmapped port stays as is (nothing outside the container can reach it anyway).\n setWebAddressingEnv(qpqConfigs, { api: devServerPorts.api, webSocket: devServerPorts.webSocket, mapHostPort });\n process.env.QPQ_VIEWS_REMOTE_BASE = `/${FEDERATED_VIEWS_SUBDOMAIN}`;\n const viewServices = getServiceNamesWithViews(appName);\n for (const serviceName of viewServices) {\n console.log(`Bundling views: [${serviceName}]`);\n await bundleViews(appName, serviceName);\n }\n delete process.env.QPQ_VIEWS_REMOTE_BASE;\n clearWebAddressingEnv();\n\n // ---- Assemble the image context ----\n console.log('Assembling image context');\n const contextDir = getImageContextDir(root, appName);\n fs.rmSync(contextDir, { recursive: true, force: true });\n fs.mkdirSync(contextDir, { recursive: true });\n\n writeDockerfile(contextDir, containerPorts);\n writeImagePackageJson(root, contextDir);\n\n const vendored = vendorQuidproquoPackages(root, contextDir);\n console.log(`Vendored ${vendored} quidproquo packages`);\n\n fs.cpSync(path.join(root, 'dist', 'qpq', 'dev-server'), path.join(contextDir, 'server'), { recursive: true });\n\n for (const entry of [...webEntryRoutes, ...webEntryHosts]) {\n copyWebEntryContent(appName, contextDir, entry, viewServices);\n }\n\n const composePath = writeComposeFile({\n contextDir,\n imageName,\n serviceName: containerName,\n volumeName,\n portMappings,\n dataPath: dockerSettings.dataPath ?? null,\n mounts: dockerSettings.mounts ?? [],\n publicHost: dockerSettings.publicHost ?? null,\n publicFileStoragePort: mapHostPort(devServerPorts.fileStorage),\n });\n\n // ---- Build the image ----\n console.log(\n `Building docker image${dockerSettings.arch ? ` for ${dockerSettings.arch}` : ''}${dockerSettings.registry ? `, pushing to ${dockerSettings.registry}` : ''}`,\n );\n await buildImage(imageName, contextDir, dockerSettings);\n\n logTimeEnd('totalTime');\n\n const hostUrl = (containerPort: number): string => {\n const hostPort = portMappings.find((mapping) => mapping.container === containerPort)?.host;\n return hostPort === undefined ? `(container port ${containerPort} is not mapped)` : `http://localhost${hostPort === 80 ? '' : `:${hostPort}`}`;\n };\n const siteUrl = hostUrl(devServerPorts.api);\n const entryLines = [\n ...webEntryRoutes.map((route) => ` ${route.service}/${route.entryName}: ${siteUrl}${route.path === '/' ? '' : route.path}`),\n ...webEntryHosts.map((host) => ` ${host.service}/${host.entryName}: ${hostUrl(host.port)}`),\n ].join('\\n');\n const where = dockerSettings.registry ? `pushed to [${imageName}]` : `[${imageName}] in the local docker store`;\n const onHost = dockerSettings.registry\n ? `On the host (Unraid: Compose Manager, or any docker host), copy the compose file there and run:`\n : `Run it here:`;\n console.log(`\nDone. The image is ${where}.\n\n${onHost}\n\n docker compose -f ${composePath} up -d\n\nThen open ${siteUrl} (replace localhost with the host's address)\n${entryLines ? `\\nWeb entries:\\n${entryLines}\\n` : ''}\nPorts come from the deployment's platformSettings.portMappings (${portMappings.map((m) => `${m.host}:${m.container}`).join(', ')})\nand are baked into the frontend, so a host must map the same ones. App state lives in ${dockerSettings.dataPath ?? `the ${volumeName} volume`}.${\n dockerSettings.mounts?.length\n ? `\\nAlso mounted: ${dockerSettings.mounts.map((mount) => `${mount.host} at ${mount.container}${mount.readOnly ? ' (read-only)' : ''}`).join(', ')}.`\n : ''\n }${\n dockerSettings.publicHost\n ? ''\n : `\\nSecure file urls point at localhost; set platformSettings.publicHost to the address browsers use for this host.`\n }\n`);\n};\n"]}
1
+ {"version":3,"file":"go.js","sourceRoot":"","sources":["../../../../src/platforms/docker/go.ts"],"names":[],"mappings":"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","sourcesContent":["// Docker platform deploy (`qpq go` with platform 'docker'), proof-of-concept\n// self-hosting: bakes the QPQ dev server (a full local platform emulation)\n// plus every service of the app and its pre-built views into one docker image.\n//\n// 1. Build workspace packages, then the dev-server bundle (all services).\n// 2. Build every views microfrontend with a same-origin module-federation\n// remote base (/<views subdomain>/<svc>), mirroring the AWS layout.\n// 3. Assemble an image context under dist/qpq/docker-image/<app>/, server\n// bundle, web root (every web entry, placed by its port or its domain),\n// a workspaces-stripped package.json for runtime deps, and the\n// locally-built quidproquo packages as a vendor overlay.\n// 4. docker build (buildx with a push when the deployment names a registry or\n// a target platform), write a docker-compose.yml, print how to run it.\n//\n// Not production-grade (single process, sqlite KVS, in-memory queues):\n// it's the whole product on one box with one command.\nimport { getQpqAppDeployment } from '@qpqjs/config-aws';\nimport { getDevServerDistPath, getDockerImageContextPath, isQpqPackageName, QpqDeployEnvVar } from '@qpqjs/core';\nimport { getAppServiceQpqConfigs, getDevServerRspackConfig, listInstalledQpqPackageNames, runRspack } from '@qpqjs/deploy-rspack';\nimport { getWebEntryDir, getWebEntryPlacements, WebEntryHost, WebEntryRoute } from '@qpqjs/dev-server';\nimport { FEDERATED_VIEWS_SUBDOMAIN } from '@qpqjs/webserver';\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { createOutput } from '../../lib/createOutput';\nimport { DeployPlan } from '../../lib/deployPrompts';\nimport { writeDevServerEntry, writeUserScriptChildEntry } from '../../lib/devServerEntry';\nimport { readDevServerPorts } from '../../lib/devServerPorts';\nimport { getRoot, getServiceNamesWithViews } from '../../lib/discovery';\nimport { getDefaultHookJobs } from '../../lib/getDefaultHookJobs';\nimport { runAppHook, runHookForAppPackages } from '../../lib/hooks';\nimport { getOwnPackageRoot } from '../../lib/packageRoot';\nimport { runCommand } from '../../lib/runCommand';\nimport { assertNoFailures } from '../../lib/runTasks';\nimport { logTimeEnd, logTimeStart } from '../../lib/timing';\nimport { bundleViews, getViewsDistDir } from '../../lib/views';\nimport { clearWebAddressingEnv, setWebAddressingEnv } from '../../lib/webAddressingEnv';\nimport { getContainerPorts } from './getContainerPorts';\nimport { getDockerPlatformSettings, ParsedDockerPlatformSettings } from './getDockerPlatformSettings';\nimport { getImageName } from './getImageName';\nimport { resolvePortMappings } from './resolvePortMappings';\nimport { writeComposeFile } from './writeComposeFile';\n\nconst out = createOutput('docker');\n\nconst getImageContextDir = (root: string, appName: string): string => getDockerImageContextPath(root, appName);\n\n// Every web entry's files go where the runtime looks for them. The federated views entry\n// is assembled from every service's views build (one folder per service, as on AWS);\n// anything else is its own buildPath. A missing build fails here rather than serving an\n// empty site later.\nconst copyWebEntryContent = (appName: string, contextDir: string, entry: WebEntryHost | WebEntryRoute, viewServices: string[]): void => {\n const label = `${entry.service}/${entry.entryName}`;\n const targetDir = getWebEntryDir(path.join(contextDir, 'web'), entry);\n\n if (entry.webEntry.domain.subDomainName === FEDERATED_VIEWS_SUBDOMAIN) {\n for (const serviceName of viewServices) {\n fs.cpSync(getViewsDistDir(appName, serviceName), path.join(targetDir, serviceName), { recursive: true });\n }\n return;\n }\n\n // A standalone host entry serves its own service's views build, as on AWS.\n if (entry.webEntry.storageDrive.syncServiceViews) {\n fs.cpSync(getViewsDistDir(appName, entry.service), targetDir, { recursive: true });\n return;\n }\n\n if (!entry.webEntry.buildPath) {\n throw new Error(`Web entry ${label} has no buildPath, so there is nothing to serve`);\n }\n const buildDir = path.resolve(entry.configRoot, entry.webEntry.buildPath);\n if (!fs.existsSync(path.join(buildDir, entry.webEntry.indexRoot))) {\n throw new Error(`Web entry ${label} has no ${entry.webEntry.indexRoot} under ${buildDir}; build it before qpq go`);\n }\n fs.cpSync(buildDir, targetDir, { recursive: true });\n};\n\n// Plain `docker build` into the local store unless the deployment asks for a registry or a\n// target platform, which need buildx: `--push` sends a cross-platform image straight to the\n// registry, `--load` keeps a same-machine one local.\nconst buildImage = async (imageName: string, contextDir: string, settings: ParsedDockerPlatformSettings): Promise<void> => {\n if (!settings.registry && !settings.arch) {\n await runCommand('docker', ['build', '-t', imageName, contextDir]);\n return;\n }\n\n const platformArgs = settings.arch ? ['--platform', settings.arch] : [];\n await runCommand('docker', ['buildx', 'build', ...platformArgs, '-t', imageName, settings.registry ? '--push' : '--load', contextDir]);\n};\n\n// The Dockerfile is shared; only its EXPOSE line depends on the app.\nconst writeDockerfile = (contextDir: string, containerPorts: number[]): void => {\n const template = fs.readFileSync(path.join(getOwnPackageRoot(), 'docker', 'dev-server', 'Dockerfile'), 'utf8');\n const dockerfile = template.replace(/^EXPOSE .*$/m, `EXPOSE ${containerPorts.join(' ')}`);\n fs.writeFileSync(path.join(contextDir, 'Dockerfile'), dockerfile);\n};\n\n// The consumer root package.json, stripped to what the image's npm install\n// needs: runtime dependencies (+ overrides). Workspaces/scripts/devDeps are\n// host-only concerns, the workspace packages themselves are bundled into the\n// server bundle from source.\n//\n// quidproquo deps declared as file: refs (a consumer living beside the qpq\n// monorepo) point outside the image context, where npm install would leave\n// dangling symlinks, rewrite them to the vendored copies inside the context.\nconst writeImagePackageJson = (root: string, contextDir: string): void => {\n const rootPackageJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));\n\n const dependencies: Record<string, string> = { ...(rootPackageJson.dependencies ?? {}) };\n for (const [name, version] of Object.entries(dependencies)) {\n if (isQpqPackageName(name) && version.startsWith('file:')) {\n dependencies[name] = `file:./vendor/${name}`;\n }\n }\n\n const imagePackageJson = {\n name: `${rootPackageJson.name}-qpq-docker`,\n version: rootPackageJson.version ?? '0.0.0',\n private: true,\n dependencies,\n overrides: rootPackageJson.overrides,\n };\n\n fs.writeFileSync(path.join(contextDir, 'package.json'), JSON.stringify(imagePackageJson, null, 2) + '\\n');\n};\n\n// Copy the locally-built quidproquo packages (which may be npm-linked\n// checkouts newer than the registry) into vendor/ so the image runs the same\n// qpq code the bundle was built against. Follows the node_modules symlinks;\n// lib/config only, no node_modules, no src.\nconst vendorQuidproquoPackages = (root: string, contextDir: string): number => {\n const nodeModules = path.join(root, 'node_modules');\n const vendorDir = path.join(contextDir, 'vendor');\n let vendored = 0;\n\n for (const name of listInstalledQpqPackageNames(nodeModules)) {\n const packageDir = fs.realpathSync(path.join(nodeModules, name));\n const targetDir = path.join(vendorDir, name);\n fs.mkdirSync(targetDir, { recursive: true });\n\n fs.copyFileSync(path.join(packageDir, 'package.json'), path.join(targetDir, 'package.json'));\n for (const sub of ['lib', 'config']) {\n const subDir = path.join(packageDir, sub);\n if (fs.existsSync(subDir)) {\n fs.cpSync(subDir, path.join(targetDir, sub), { recursive: true, dereference: true });\n }\n }\n vendored += 1;\n }\n\n return vendored;\n};\n\nexport const dockerGo = async (appName: string, plan: DeployPlan): Promise<void> => {\n if (plan.kind === 'cancelled') {\n return;\n }\n\n if (plan.kind === 'account' || plan.kind === 'bootstrap') {\n out.log(`Nothing to do — the docker platform has no ${plan.kind} stacks.`);\n return;\n }\n\n const root = getRoot();\n const deploymentName = process.env[QpqDeployEnvVar.deployName]!;\n const dockerSettings = getDockerPlatformSettings(deploymentName, getQpqAppDeployment(root, appName, deploymentName));\n\n const applicationName = process.env[QpqDeployEnvVar.applicationName]!;\n const imageName = getImageName(applicationName, dockerSettings);\n const containerName = `qpq-${applicationName}`;\n const volumeName = `${containerName}-data`;\n\n // The dev server hosts every service of the app, so per-service/stack\n // selections don't apply, the image is always the whole app.\n out.log(`\\n\\nBuilding docker image [${imageName}] — the whole app deploys as one image\\n\\n`);\n\n logTimeStart('totalTime');\n\n await runAppHook(appName, 'predeploy');\n\n // Workspace packages resolve through their built dist/ (package.json main),\n // so bundles would ship stale code unless every lib is tsc'd first.\n out.log('Building workspace packages');\n assertNoFailures('Workspace build', await runHookForAppPackages('build', appName, getDefaultHookJobs()));\n\n // ---- Server bundle: the dev server + every service, one main.js ----\n out.log('Bundling server (dev server + all services)');\n const qpqConfigs = getAppServiceQpqConfigs(root, appName);\n\n // Resolved before anything slow runs, so a bad port or domain fails the build up front.\n const devServerPorts = readDevServerPorts(appName);\n const { hosts: webEntryHosts, routes: webEntryRoutes } = getWebEntryPlacements(qpqConfigs, Object.values(devServerPorts));\n const containerPorts = getContainerPorts(devServerPorts, webEntryHosts);\n const portMappings = resolvePortMappings(deploymentName, dockerSettings, devServerPorts.api, containerPorts);\n const mapHostPort = (containerPort: number): number => portMappings.find((mapping) => mapping.container === containerPort)?.host ?? containerPort;\n\n // Nothing deploys into the container, so the image runs its own pending migrations on start.\n const entry = writeDevServerEntry(root, appName, 'migrate-then-serve');\n const userScriptChildEntry = writeUserScriptChildEntry(root);\n // The image installs its own node_modules next to the bundle, so externals\n // must stay bare; host-resolved absolute paths do not exist in the container.\n await runRspack(getDevServerRspackConfig({ root, entry, userScriptChildEntry, qpqConfigs, portableExternals: true }));\n\n // ---- Views: production builds with same-origin federation remotes ----\n // The browser reaches everything on the page's own host, on the HOST side of the port\n // mappings; an unmapped port stays as is (nothing outside the container can reach it anyway).\n setWebAddressingEnv(qpqConfigs, { api: devServerPorts.api, webSocket: devServerPorts.webSocket, mapHostPort });\n process.env.QPQ_VIEWS_REMOTE_BASE = `/${FEDERATED_VIEWS_SUBDOMAIN}`;\n const viewServices = getServiceNamesWithViews(appName);\n for (const serviceName of viewServices) {\n out.log(`Bundling views: [${serviceName}]`);\n await bundleViews(appName, serviceName);\n }\n delete process.env.QPQ_VIEWS_REMOTE_BASE;\n clearWebAddressingEnv();\n\n // ---- Assemble the image context ----\n out.log('Assembling image context');\n const contextDir = getImageContextDir(root, appName);\n fs.rmSync(contextDir, { recursive: true, force: true });\n fs.mkdirSync(contextDir, { recursive: true });\n\n writeDockerfile(contextDir, containerPorts);\n writeImagePackageJson(root, contextDir);\n\n const vendored = vendorQuidproquoPackages(root, contextDir);\n out.log(`Vendored ${vendored} quidproquo packages`);\n\n fs.cpSync(getDevServerDistPath(root), path.join(contextDir, 'server'), { recursive: true });\n\n for (const entry of [...webEntryRoutes, ...webEntryHosts]) {\n copyWebEntryContent(appName, contextDir, entry, viewServices);\n }\n\n const composePath = writeComposeFile({\n contextDir,\n imageName,\n serviceName: containerName,\n volumeName,\n portMappings,\n dataPath: dockerSettings.dataPath ?? null,\n mounts: dockerSettings.mounts ?? [],\n publicHost: dockerSettings.publicHost ?? null,\n publicFileStoragePort: mapHostPort(devServerPorts.fileStorage),\n });\n\n // ---- Build the image ----\n out.log(\n `Building docker image${dockerSettings.arch ? ` for ${dockerSettings.arch}` : ''}${dockerSettings.registry ? `, pushing to ${dockerSettings.registry}` : ''}`,\n );\n await buildImage(imageName, contextDir, dockerSettings);\n\n logTimeEnd('totalTime');\n\n const hostUrl = (containerPort: number): string => {\n const hostPort = portMappings.find((mapping) => mapping.container === containerPort)?.host;\n return hostPort === undefined ? `(container port ${containerPort} is not mapped)` : `http://localhost${hostPort === 80 ? '' : `:${hostPort}`}`;\n };\n const siteUrl = hostUrl(devServerPorts.api);\n const entryLines = [\n ...webEntryRoutes.map((route) => ` ${route.service}/${route.entryName}: ${siteUrl}${route.path === '/' ? '' : route.path}`),\n ...webEntryHosts.map((host) => ` ${host.service}/${host.entryName}: ${hostUrl(host.port)}`),\n ].join('\\n');\n const where = dockerSettings.registry ? `pushed to [${imageName}]` : `[${imageName}] in the local docker store`;\n const onHost = dockerSettings.registry\n ? `On the host (Unraid: Compose Manager, or any docker host), copy the compose file there and run:`\n : `Run it here:`;\n out.log(`\nDone. The image is ${where}.\n\n${onHost}\n\n docker compose -f ${composePath} up -d\n\nThen open ${siteUrl} (replace localhost with the host's address)\n${entryLines ? `\\nWeb entries:\\n${entryLines}\\n` : ''}\nPorts come from the deployment's platformSettings.portMappings (${portMappings.map((m) => `${m.host}:${m.container}`).join(', ')})\nand are baked into the frontend, so a host must map the same ones. App state lives in ${dockerSettings.dataPath ?? `the ${volumeName} volume`}.${\n dockerSettings.mounts?.length\n ? `\\nAlso mounted: ${dockerSettings.mounts.map((mount) => `${mount.host} at ${mount.container}${mount.readOnly ? ' (read-only)' : ''}`).join(', ')}.`\n : ''\n }${\n dockerSettings.publicHost\n ? ''\n : `\\nSecure file urls point at localhost; set platformSettings.publicHost to the address browsers use for this host.`\n }\n`);\n};\n"]}
@@ -1,17 +1,18 @@
1
+ import { CliError } from '../../lib/CliError';
2
+ import { createOutput } from '../../lib/createOutput';
1
3
  import { BUILD_ONLY_FLAG, FROM_BUILD_FLAG } from '../../lib/goDockerMode';
2
4
  import { getDockerPlatformSettings } from './getDockerPlatformSettings';
3
5
  import { dockerGo } from './go';
6
+ const out = createOutput('docker');
4
7
  const publishNotSupported = async () => {
5
- console.error('The docker platform has no federated code store — story code is baked into the image. Rebuild with qpq go instead.');
6
- process.exit(1);
8
+ throw new CliError('The docker platform has no federated code store: story code is baked into the image. Rebuild with qpq go instead.');
7
9
  };
8
10
  // A docker platform's deploy already is the containerised one, so `qpq go:docker`
9
11
  // (what a scaffolded app's `npm run deploy` runs) is the same build. The image is
10
12
  // the deploy, so there is no saved build to split across two runs.
11
13
  const dockerGoDocker = async (appName, plan, mode) => {
12
14
  if (mode !== 'full') {
13
- console.error(`The docker platform builds and deploys in one step; ${BUILD_ONLY_FLAG} and ${FROM_BUILD_FLAG} do not apply. Run qpq go:docker without them.`);
14
- process.exit(1);
15
+ throw new CliError(`The docker platform builds and deploys in one step; ${BUILD_ONLY_FLAG} and ${FROM_BUILD_FLAG} do not apply. Run qpq go:docker without them.`);
15
16
  }
16
17
  await dockerGo(appName, plan);
17
18
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/platforms/docker/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAgB,MAAM,wBAAwB,CAAC;AAExF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEhC,MAAM,mBAAmB,GAAG,KAAK,IAAmB,EAAE;IACpD,OAAO,CAAC,KAAK,CAAC,oHAAoH,CAAC,CAAC;IACpI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;AAEF,kFAAkF;AAClF,kFAAkF;AAClF,mEAAmE;AACnE,MAAM,cAAc,GAAG,KAAK,EAAE,OAAe,EAAE,IAAgB,EAAE,IAAkB,EAAiB,EAAE;IACpG,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CACX,uDAAuD,eAAe,QAAQ,eAAe,gDAAgD,CAC9I,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACrD,2FAA2F;IAC3F,oFAAoF;IACpF,iBAAiB,EAAE,CAAC,cAAc,EAAE,UAAU,EAAE,EAAE;QAChD,yBAAyB,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;IACxD,CAAC;IAED,EAAE,EAAE,QAAQ;IACZ,QAAQ,EAAE,cAAc;IAExB,OAAO,EAAE,mBAAmB;IAC5B,YAAY,EAAE,mBAAmB;IACjC,aAAa,EAAE,mBAAmB;IAClC,aAAa,EAAE,mBAAmB;CACnC,CAAC","sourcesContent":["import { DeployPlan } from '../../lib/deployPrompts';\nimport { BUILD_ONLY_FLAG, FROM_BUILD_FLAG, GoDockerMode } from '../../lib/goDockerMode';\nimport { QpqPlatformDriver } from '../types';\nimport { getDockerPlatformSettings } from './getDockerPlatformSettings';\nimport { dockerGo } from './go';\n\nconst publishNotSupported = async (): Promise<void> => {\n console.error('The docker platform has no federated code store — story code is baked into the image. Rebuild with qpq go instead.');\n process.exit(1);\n};\n\n// A docker platform's deploy already is the containerised one, so `qpq go:docker`\n// (what a scaffolded app's `npm run deploy` runs) is the same build. The image is\n// the deploy, so there is no saved build to split across two runs.\nconst dockerGoDocker = async (appName: string, plan: DeployPlan, mode: GoDockerMode): Promise<void> => {\n if (mode !== 'full') {\n console.error(\n `The docker platform builds and deploys in one step; ${BUILD_ONLY_FLAG} and ${FROM_BUILD_FLAG} do not apply. Run qpq go:docker without them.`,\n );\n process.exit(1);\n }\n\n await dockerGo(appName, plan);\n};\n\nexport const dockerPlatformDriver: QpqPlatformDriver = {\n // No identity to prime. Mappings are only parsed here; which container ports exist depends\n // on the app's config, which is not loaded yet, so that check happens in the build.\n prepareDeployment: (deploymentName, deployment) => {\n getDockerPlatformSettings(deploymentName, deployment);\n },\n\n go: dockerGo,\n goDocker: dockerGoDocker,\n\n publish: publishNotSupported,\n publishBuild: publishNotSupported,\n publishUpload: publishNotSupported,\n publishDeploy: publishNotSupported,\n};\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/platforms/docker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAgB,MAAM,wBAAwB,CAAC;AAExF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEhC,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;AAEnC,MAAM,mBAAmB,GAAG,KAAK,IAAmB,EAAE;IACpD,MAAM,IAAI,QAAQ,CAAC,mHAAmH,CAAC,CAAC;AAC1I,CAAC,CAAC;AAEF,kFAAkF;AAClF,kFAAkF;AAClF,mEAAmE;AACnE,MAAM,cAAc,GAAG,KAAK,EAAE,OAAe,EAAE,IAAgB,EAAE,IAAkB,EAAiB,EAAE;IACpG,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,QAAQ,CAChB,uDAAuD,eAAe,QAAQ,eAAe,gDAAgD,CAC9I,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACrD,2FAA2F;IAC3F,oFAAoF;IACpF,iBAAiB,EAAE,CAAC,cAAc,EAAE,UAAU,EAAE,EAAE;QAChD,yBAAyB,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;IACxD,CAAC;IAED,EAAE,EAAE,QAAQ;IACZ,QAAQ,EAAE,cAAc;IAExB,OAAO,EAAE,mBAAmB;IAC5B,YAAY,EAAE,mBAAmB;IACjC,aAAa,EAAE,mBAAmB;IAClC,aAAa,EAAE,mBAAmB;CACnC,CAAC","sourcesContent":["import { CliError } from '../../lib/CliError';\nimport { createOutput } from '../../lib/createOutput';\nimport { DeployPlan } from '../../lib/deployPrompts';\nimport { BUILD_ONLY_FLAG, FROM_BUILD_FLAG, GoDockerMode } from '../../lib/goDockerMode';\nimport { QpqPlatformDriver } from '../types';\nimport { getDockerPlatformSettings } from './getDockerPlatformSettings';\nimport { dockerGo } from './go';\n\nconst out = createOutput('docker');\n\nconst publishNotSupported = async (): Promise<void> => {\n throw new CliError('The docker platform has no federated code store: story code is baked into the image. Rebuild with qpq go instead.');\n};\n\n// A docker platform's deploy already is the containerised one, so `qpq go:docker`\n// (what a scaffolded app's `npm run deploy` runs) is the same build. The image is\n// the deploy, so there is no saved build to split across two runs.\nconst dockerGoDocker = async (appName: string, plan: DeployPlan, mode: GoDockerMode): Promise<void> => {\n if (mode !== 'full') {\n throw new CliError(\n `The docker platform builds and deploys in one step; ${BUILD_ONLY_FLAG} and ${FROM_BUILD_FLAG} do not apply. Run qpq go:docker without them.`,\n );\n }\n\n await dockerGo(appName, plan);\n};\n\nexport const dockerPlatformDriver: QpqPlatformDriver = {\n // No identity to prime. Mappings are only parsed here; which container ports exist depends\n // on the app's config, which is not loaded yet, so that check happens in the build.\n prepareDeployment: (deploymentName, deployment) => {\n getDockerPlatformSettings(deploymentName, deployment);\n },\n\n go: dockerGo,\n goDocker: dockerGoDocker,\n\n publish: publishNotSupported,\n publishBuild: publishNotSupported,\n publishUpload: publishNotSupported,\n publishDeploy: publishNotSupported,\n};\n"]}
@@ -14,10 +14,11 @@ export const parseMounts = (value) => value
14
14
  if (!match) {
15
15
  throw new Error(`Mount '${item}' must be host:container with both absolute, optionally ending :ro, e.g. /mnt/user/media:/media`);
16
16
  }
17
- const container = trimTrailingSlashes(match[2]);
17
+ const [, host = '', containerPath = '', mode] = match;
18
+ const container = trimTrailingSlashes(containerPath);
18
19
  if (container === IMAGE_ROOT || container.startsWith(`${IMAGE_ROOT}/`) || container === '/') {
19
20
  throw new Error(`Mount '${item}' would cover the image's own files: mount it somewhere other than / or ${IMAGE_ROOT}`);
20
21
  }
21
- return { host: trimTrailingSlashes(match[1]), container, readOnly: match[3] === 'ro' };
22
+ return { host: trimTrailingSlashes(host), container, readOnly: mode === 'ro' };
22
23
  });
23
24
  //# sourceMappingURL=parseMounts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parseMounts.js","sourceRoot":"","sources":["../../../../src/platforms/docker/parseMounts.ts"],"names":[],"mappings":"AAQA,+DAA+D;AAC/D,MAAM,aAAa,GAAG,qCAAqC,CAAC;AAE5D,gGAAgG;AAChG,aAAa;AACb,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B,MAAM,mBAAmB,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;AAE1F,+FAA+F;AAC/F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAW,EAAE,CACpD,KAAK;KACF,KAAK,CAAC,GAAG,CAAC;KACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;KAC1B,MAAM,CAAC,OAAO,CAAC;KACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;IACZ,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,iGAAiG,CAAC,CAAC;IACnI,CAAC;IAED,MAAM,SAAS,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,IAAI,SAAS,KAAK,UAAU,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,CAAC,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;QAC5F,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,2EAA2E,UAAU,EAAE,CAAC,CAAC;IACzH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;AACzF,CAAC,CAAC,CAAC","sourcesContent":["export type Mount = {\n // Absolute folder on the docker host, e.g. /mnt/user/media/downloads.\n host: string;\n // Where it appears inside the container.\n container: string;\n readOnly: boolean;\n};\n\n// host:container, both absolute, optionally ending :ro or :rw.\nconst MOUNT_PATTERN = /^(\\/[^:]*):(\\/[^:]*?)(?::(ro|rw))?$/;\n\n// The image's own files live under /app (including the state directory), so a mount there would\n// hide them.\nconst IMAGE_ROOT = '/app';\n\nconst trimTrailingSlashes = (folder: string): string => folder.replace(/\\/+$/, '') || '/';\n\n/** Parses \"host:container[:ro], ...\" into mounts, throwing naming the first malformed item. */\nexport const parseMounts = (value: string): Mount[] =>\n value\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean)\n .map((item) => {\n const match = MOUNT_PATTERN.exec(item);\n if (!match) {\n throw new Error(`Mount '${item}' must be host:container with both absolute, optionally ending :ro, e.g. /mnt/user/media:/media`);\n }\n\n const container = trimTrailingSlashes(match[2]);\n if (container === IMAGE_ROOT || container.startsWith(`${IMAGE_ROOT}/`) || container === '/') {\n throw new Error(`Mount '${item}' would cover the image's own files: mount it somewhere other than / or ${IMAGE_ROOT}`);\n }\n\n return { host: trimTrailingSlashes(match[1]), container, readOnly: match[3] === 'ro' };\n });\n"]}
1
+ {"version":3,"file":"parseMounts.js","sourceRoot":"","sources":["../../../../src/platforms/docker/parseMounts.ts"],"names":[],"mappings":"AAQA,+DAA+D;AAC/D,MAAM,aAAa,GAAG,qCAAqC,CAAC;AAE5D,gGAAgG;AAChG,aAAa;AACb,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B,MAAM,mBAAmB,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;AAE1F,+FAA+F;AAC/F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAW,EAAE,CACpD,KAAK;KACF,KAAK,CAAC,GAAG,CAAC;KACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;KAC1B,MAAM,CAAC,OAAO,CAAC;KACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;IACZ,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,iGAAiG,CAAC,CAAC;IACnI,CAAC;IAED,MAAM,CAAC,EAAE,IAAI,GAAG,EAAE,EAAE,aAAa,GAAG,EAAE,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;IACtD,MAAM,SAAS,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;IACrD,IAAI,SAAS,KAAK,UAAU,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,CAAC,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;QAC5F,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,2EAA2E,UAAU,EAAE,CAAC,CAAC;IACzH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,mBAAmB,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,KAAK,IAAI,EAAE,CAAC;AACjF,CAAC,CAAC,CAAC","sourcesContent":["export type Mount = {\n // Absolute folder on the docker host, e.g. /mnt/user/media/downloads.\n host: string;\n // Where it appears inside the container.\n container: string;\n readOnly: boolean;\n};\n\n// host:container, both absolute, optionally ending :ro or :rw.\nconst MOUNT_PATTERN = /^(\\/[^:]*):(\\/[^:]*?)(?::(ro|rw))?$/;\n\n// The image's own files live under /app (including the state directory), so a mount there would\n// hide them.\nconst IMAGE_ROOT = '/app';\n\nconst trimTrailingSlashes = (folder: string): string => folder.replace(/\\/+$/, '') || '/';\n\n/** Parses \"host:container[:ro], ...\" into mounts, throwing naming the first malformed item. */\nexport const parseMounts = (value: string): Mount[] =>\n value\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean)\n .map((item) => {\n const match = MOUNT_PATTERN.exec(item);\n if (!match) {\n throw new Error(`Mount '${item}' must be host:container with both absolute, optionally ending :ro, e.g. /mnt/user/media:/media`);\n }\n\n const [, host = '', containerPath = '', mode] = match;\n const container = trimTrailingSlashes(containerPath);\n if (container === IMAGE_ROOT || container.startsWith(`${IMAGE_ROOT}/`) || container === '/') {\n throw new Error(`Mount '${item}' would cover the image's own files: mount it somewhere other than / or ${IMAGE_ROOT}`);\n }\n\n return { host: trimTrailingSlashes(host), container, readOnly: mode === 'ro' };\n });\n"]}
@@ -1,6 +1,9 @@
1
+ import { CliError } from '../lib/CliError';
2
+ import { createOutput } from '../lib/createOutput';
1
3
  import { awsPlatformDriver } from './aws';
2
4
  import { dockerPlatformDriver } from './docker';
3
5
  import { QpqDeployPlatform } from './types';
6
+ const out = createOutput('platform');
4
7
  const platformDrivers = {
5
8
  [QpqDeployPlatform.aws]: awsPlatformDriver,
6
9
  [QpqDeployPlatform.docker]: dockerPlatformDriver,
@@ -8,8 +11,7 @@ const platformDrivers = {
8
11
  export const getPlatformDriver = (platform) => {
9
12
  const driver = platformDrivers[platform];
10
13
  if (!driver) {
11
- console.error(`Unknown deploy platform '${platform}'. Supported platforms: ${Object.keys(platformDrivers).join(', ')}`);
12
- process.exit(1);
14
+ throw new CliError(`Unknown deploy platform '${platform}'. Supported platforms: ${Object.keys(platformDrivers).join(', ')}`);
13
15
  }
14
16
  return driver;
15
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/platforms/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAqB,MAAM,SAAS,CAAC;AAE/D,MAAM,eAAe,GAAsC;IACzD,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,iBAAiB;IAC1C,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,oBAAoB;CACjD,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,QAAgB,EAAqB,EAAE;IACvE,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAEzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,4BAA4B,QAAQ,2BAA2B,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,cAAc,SAAS,CAAC","sourcesContent":["import { awsPlatformDriver } from './aws';\nimport { dockerPlatformDriver } from './docker';\nimport { QpqDeployPlatform, QpqPlatformDriver } from './types';\n\nconst platformDrivers: Record<string, QpqPlatformDriver> = {\n [QpqDeployPlatform.aws]: awsPlatformDriver,\n [QpqDeployPlatform.docker]: dockerPlatformDriver,\n};\n\nexport const getPlatformDriver = (platform: string): QpqPlatformDriver => {\n const driver = platformDrivers[platform];\n\n if (!driver) {\n console.error(`Unknown deploy platform '${platform}'. Supported platforms: ${Object.keys(platformDrivers).join(', ')}`);\n process.exit(1);\n }\n\n return driver;\n};\n\nexport * from './types';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/platforms/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAqB,MAAM,SAAS,CAAC;AAE/D,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;AAErC,MAAM,eAAe,GAAsC;IACzD,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,iBAAiB;IAC1C,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,oBAAoB;CACjD,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,QAAgB,EAAqB,EAAE;IACvE,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAEzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,QAAQ,CAAC,4BAA4B,QAAQ,2BAA2B,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/H,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,cAAc,SAAS,CAAC","sourcesContent":["import { CliError } from '../lib/CliError';\nimport { createOutput } from '../lib/createOutput';\nimport { awsPlatformDriver } from './aws';\nimport { dockerPlatformDriver } from './docker';\nimport { QpqDeployPlatform, QpqPlatformDriver } from './types';\n\nconst out = createOutput('platform');\n\nconst platformDrivers: Record<string, QpqPlatformDriver> = {\n [QpqDeployPlatform.aws]: awsPlatformDriver,\n [QpqDeployPlatform.docker]: dockerPlatformDriver,\n};\n\nexport const getPlatformDriver = (platform: string): QpqPlatformDriver => {\n const driver = platformDrivers[platform];\n\n if (!driver) {\n throw new CliError(`Unknown deploy platform '${platform}'. Supported platforms: ${Object.keys(platformDrivers).join(', ')}`);\n }\n\n return driver;\n};\n\nexport * from './types';\n"]}
@@ -7,7 +7,7 @@ export declare enum QpqDeployPlatform {
7
7
  aws = "aws",
8
8
  docker = "docker"
9
9
  }
10
- export interface QpqPlatformDriver {
10
+ export type QpqPlatformDriver = {
11
11
  prepareDeployment: (deploymentName: string, deployment: QpqAppDeployment) => void;
12
12
  go: (appName: string, plan: DeployPlan) => Promise<void>;
13
13
  goDocker?: (appName: string, plan: DeployPlan, mode: GoDockerMode) => Promise<void>;
@@ -18,4 +18,4 @@ export interface QpqPlatformDriver {
18
18
  publishBuild: (appName: string, serviceNames: string[]) => Promise<void>;
19
19
  publishUpload: (appName: string, serviceNames: string[]) => Promise<void>;
20
20
  publishDeploy: (appName: string, serviceNames: string[]) => Promise<void>;
21
- }
21
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/platforms/types.ts"],"names":[],"mappings":"AAOA,MAAM,CAAN,IAAY,iBAGX;AAHD,WAAY,iBAAiB;IAC3B,gCAAW,CAAA;IACX,sCAAiB,CAAA;AACnB,CAAC,EAHW,iBAAiB,KAAjB,iBAAiB,QAG5B","sourcesContent":["import { QpqAppDeployment } from '@qpqjs/core';\n\nimport { ClearResourcesPlan } from '../lib/clearResourcesPlan';\nimport { DeployPlan, TeardownPlan } from '../lib/deployPrompts';\nimport { GoDockerMode } from '../lib/goDockerMode';\nimport { SetupStep } from '../lib/setupStep';\n\nexport enum QpqDeployPlatform {\n aws = 'aws',\n docker = 'docker',\n}\n\n// A deploy platform driver — everything that happens after \"what to deploy\"\n// has been decided. `qpq go` resolves the app + deployment, prompts the plan,\n// then hands off here; the platform comes from the deployment's entry in\n// apps/<app>/deploy.config.json, so an app can move platforms with a config\n// change instead of a different command.\nexport interface QpqPlatformDriver {\n // Check the deployment's platformSettings and prime the platform's identity\n // env vars from them. Throws when the entry is incomplete. Runs before any\n // infrastructure.ts is required, since service configs read those vars at load.\n prepareDeployment: (deploymentName: string, deployment: QpqAppDeployment) => void;\n\n // Sequential deploy (`qpq go`).\n go: (appName: string, plan: DeployPlan) => Promise<void>;\n\n // Parallel containerized deploy (`qpq go:docker`) — optional; drivers that\n // have no docker strategy simply omit it. The mode splits the run into a\n // build half and a deploy half (`--build-only` / `--from-build`); a driver\n // whose build and deploy cannot be separated refuses anything but 'full'.\n goDocker?: (appName: string, plan: DeployPlan, mode: GoDockerMode) => Promise<void>;\n\n // Destroy the web/api/inf stacks for selected services (`qpq teardown`) —\n // optional; drivers with no teardown strategy simply omit it.\n teardown?: (appName: string, plan: TeardownPlan) => Promise<void>;\n\n // Empty the stored data of selected resources without touching the stacks\n // (`qpq clear-resources`) — optional; drivers with no strategy omit it.\n clearResources?: (appName: string, plan: ClearResourcesPlan) => Promise<void>;\n\n // The ordered checklist that takes an empty cloud environment to a deployed\n // one (`qpq setup`) — optional; drivers with nothing to set up omit it.\n setupSteps?: (appName: string, deploymentName: string) => Promise<SetupStep[]>;\n\n // Federated remote publishing (`qpq publish[:build|:upload|:deploy]`).\n publish: (appName: string, serviceNames: string[]) => Promise<void>;\n publishBuild: (appName: string, serviceNames: string[]) => Promise<void>;\n publishUpload: (appName: string, serviceNames: string[]) => Promise<void>;\n publishDeploy: (appName: string, serviceNames: string[]) => Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/platforms/types.ts"],"names":[],"mappings":"AAOA,MAAM,CAAN,IAAY,iBAGX;AAHD,WAAY,iBAAiB;IAC3B,gCAAW,CAAA;IACX,sCAAiB,CAAA;AACnB,CAAC,EAHW,iBAAiB,KAAjB,iBAAiB,QAG5B","sourcesContent":["import { QpqAppDeployment } from '@qpqjs/core';\n\nimport { ClearResourcesPlan } from '../lib/clearResourcesPlan';\nimport { DeployPlan, TeardownPlan } from '../lib/deployPrompts';\nimport { GoDockerMode } from '../lib/goDockerMode';\nimport { SetupStep } from '../lib/setupStep';\n\nexport enum QpqDeployPlatform {\n aws = 'aws',\n docker = 'docker',\n}\n\n// A deploy platform driver, everything that happens after \"what to deploy\"\n// has been decided. `qpq go` resolves the app + deployment, prompts the plan,\n// then hands off here; the platform comes from the deployment's entry in\n// apps/<app>/deploy.config.json, so an app can move platforms with a config\n// change instead of a different command.\nexport type QpqPlatformDriver = {\n // Check the deployment's platformSettings and prime the platform's identity\n // env vars from them. Throws when the entry is incomplete. Runs before any\n // infrastructure.ts is required, since service configs read those vars at load.\n prepareDeployment: (deploymentName: string, deployment: QpqAppDeployment) => void;\n\n // Sequential deploy (`qpq go`).\n go: (appName: string, plan: DeployPlan) => Promise<void>;\n\n // Parallel containerized deploy (`qpq go:docker`), optional; drivers that\n // have no docker strategy simply omit it. The mode splits the run into a\n // build half and a deploy half (`--build-only` / `--from-build`); a driver\n // whose build and deploy cannot be separated refuses anything but 'full'.\n goDocker?: (appName: string, plan: DeployPlan, mode: GoDockerMode) => Promise<void>;\n\n // Destroy the web/api/inf stacks for selected services (`qpq teardown`):\n // optional; drivers with no teardown strategy simply omit it.\n teardown?: (appName: string, plan: TeardownPlan) => Promise<void>;\n\n // Empty the stored data of selected resources without touching the stacks\n // (`qpq clear-resources`), optional; drivers with no strategy omit it.\n clearResources?: (appName: string, plan: ClearResourcesPlan) => Promise<void>;\n\n // The ordered checklist that takes an empty cloud environment to a deployed\n // one (`qpq setup`), optional; drivers with nothing to set up omit it.\n setupSteps?: (appName: string, deploymentName: string) => Promise<SetupStep[]>;\n\n // Federated remote publishing (`qpq publish[:build|:upload|:deploy]`).\n publish: (appName: string, serviceNames: string[]) => Promise<void>;\n publishBuild: (appName: string, serviceNames: string[]) => Promise<void>;\n publishUpload: (appName: string, serviceNames: string[]) => Promise<void>;\n publishDeploy: (appName: string, serviceNames: string[]) => Promise<void>;\n};\n"]}
package/package.json CHANGED
@@ -1,10 +1,18 @@
1
1
  {
2
2
  "name": "@qpqjs/cli",
3
- "version": "0.3.0",
4
- "description": "The qpq CLI — build, dev and deploy orchestration for QPQ apps",
3
+ "version": "0.5.0",
4
+ "description": "The qpq CLI: build, dev and deploy orchestration for quidproquo apps.",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/esm/index.js",
7
7
  "types": "./lib/commonjs/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/commonjs/index.d.ts",
11
+ "module": "./lib/esm/index.js",
12
+ "default": "./lib/commonjs/index.js"
13
+ },
14
+ "./package.json": "./package.json"
15
+ },
8
16
  "sideEffects": false,
9
17
  "files": [
10
18
  "lib/**/*",
@@ -24,11 +32,13 @@
24
32
  "lint": "npx eslint .",
25
33
  "lint:fix": "npx eslint . --fix",
26
34
  "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
27
- "build:bin-perms": "node -e \"require('fs').chmodSync('lib/commonjs/bin/qpq.js', 0o755)\""
35
+ "build:bin-perms": "node -e \"require('fs').chmodSync('lib/commonjs/bin/qpq.js', 0o755)\"",
36
+ "test:watch": "vitest"
28
37
  },
29
38
  "repository": {
30
39
  "type": "git",
31
- "url": "git+https://github.com/qpqjs/quidproquo.git"
40
+ "url": "git+https://github.com/qpqjs/quidproquo.git",
41
+ "directory": "packages/cli"
32
42
  },
33
43
  "keywords": [],
34
44
  "author": "",
@@ -45,30 +55,33 @@
45
55
  "@aws-sdk/client-s3": "^3.1093.0",
46
56
  "@aws-sdk/client-sts": "^3.1093.0",
47
57
  "@inquirer/prompts": "^8.5.2",
58
+ "@qpqjs/actionprocessor-aws": "0.5.0",
59
+ "@qpqjs/actionprocessor-node": "0.5.0",
60
+ "@qpqjs/config-aws": "0.5.0",
61
+ "@qpqjs/core": "0.5.0",
62
+ "@qpqjs/deploy-aws": "0.5.0",
63
+ "@qpqjs/deploy-rspack": "0.5.0",
64
+ "@qpqjs/dev-server": "0.5.0",
65
+ "@qpqjs/user-script": "0.5.0",
66
+ "@qpqjs/webserver": "0.5.0",
48
67
  "@rspack/dev-server": "^2.1.0",
49
- "aws-cdk": "^2.1132.1",
68
+ "aws-cdk": "^2.1146.1",
50
69
  "madge": "^8.0.0",
51
- "quidproquo": "0.3.0",
52
- "@qpqjs/actionprocessor-aws": "0.3.0",
53
- "@qpqjs/config-aws": "0.3.0",
54
- "@qpqjs/core": "0.3.0",
55
- "@qpqjs/deploy-aws": "0.3.0",
56
- "@qpqjs/deploy-rspack": "0.3.0",
57
- "@qpqjs/user-script": "0.3.0",
58
- "@qpqjs/dev-server": "0.3.0",
59
- "@qpqjs/webserver": "0.3.0",
60
70
  "ts-node": "^10.9.1",
61
71
  "typescript": "^5.8.2"
62
72
  },
63
73
  "devDependencies": {
64
74
  "@rspack/core": "^2.1.2",
65
75
  "@types/node": "^22.13.13",
66
- "@qpqjs/tsconfig": "0.3.0"
76
+ "@qpqjs/tsconfig": "0.5.0"
67
77
  },
68
78
  "bin": {
69
79
  "qpq": "./lib/commonjs/bin/qpq.js"
70
80
  },
71
81
  "peerDependencies": {
72
82
  "@rspack/core": "^2.0.0"
83
+ },
84
+ "engines": {
85
+ "node": ">=24"
73
86
  }
74
87
  }
@@ -6,7 +6,7 @@ A quidproquo user script. It builds to one JavaScript file that a quidproquo ser
6
6
 
7
7
  - The entry is `src/main.ts`. Split the code across other files and folders as you like; the build folds them in.
8
8
  - Every export of `src/main.ts` must be a function. A generator export runs as a story: it yields quidproquo actions and its return value is what the caller gets. A plain function export returns its value.
9
- - Scripts run in a sandbox. The actions available are the pure ones (`askDateNow`, `askNewGuid`, logging, random numbers) and `askNetworkRequest` for calling out over HTTP; a story that yields a file, store or other resource action fails at that point. The service that hosts scripts may offer its own module to import instead (see `defineUserScriptModule`).
9
+ - Scripts run in a sandbox. The actions available are the pure ones (`askDateNow`, `askGuidNew`, logging, random numbers) and `askNetworkRequest` for calling out over HTTP; a story that yields a file, store or other resource action fails at that point. The service that hosts scripts may offer its own module to import instead (see `defineUserScriptModule`).
10
10
  - Import from `@qpqjs/core`. npm packages you add to `package.json` are bundled into the output. Node builtins such as `fs` are refused at build time.
11
11
 
12
12
  ## Build