@mesh-tech/mesh-cli 0.1.0 → 0.12.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 (504) hide show
  1. package/assets/intent/agents-fence.md +10 -0
  2. package/assets/intent/intent-claude-gate.mjs +255 -0
  3. package/assets/log-shipper.mjs +94 -0
  4. package/bin/mesh.mjs +80 -0
  5. package/dist/bin/mesh.d.ts +7 -9
  6. package/dist/bin/mesh.d.ts.map +1 -1
  7. package/dist/bin/mesh.js +20826 -37
  8. package/dist/bin/mesh.js.map +7 -1
  9. package/dist/build-info.json +4 -0
  10. package/dist/src/commands/agent-api-client.d.ts +79 -0
  11. package/dist/src/commands/agent-api-client.d.ts.map +1 -0
  12. package/dist/src/commands/agent-api-client.js +170 -0
  13. package/dist/src/commands/agent-api-client.js.map +1 -0
  14. package/dist/src/commands/artifacts.d.ts +13 -0
  15. package/dist/src/commands/artifacts.d.ts.map +1 -0
  16. package/dist/src/commands/artifacts.js +140 -0
  17. package/dist/src/commands/artifacts.js.map +1 -0
  18. package/dist/src/commands/cluster.d.ts +45 -0
  19. package/dist/src/commands/cluster.d.ts.map +1 -0
  20. package/dist/src/commands/cluster.js +259 -0
  21. package/dist/src/commands/cluster.js.map +1 -0
  22. package/dist/src/commands/conversations.d.ts +61 -0
  23. package/dist/src/commands/conversations.d.ts.map +1 -0
  24. package/dist/src/commands/conversations.js +239 -0
  25. package/dist/src/commands/conversations.js.map +1 -0
  26. package/dist/src/commands/create-app.d.ts +26 -3
  27. package/dist/src/commands/create-app.d.ts.map +1 -1
  28. package/dist/src/commands/create-app.js +465 -107
  29. package/dist/src/commands/create-app.js.map +1 -1
  30. package/dist/src/commands/deploy.d.ts +19 -0
  31. package/dist/src/commands/deploy.d.ts.map +1 -1
  32. package/dist/src/commands/deploy.js +83 -142
  33. package/dist/src/commands/deploy.js.map +1 -1
  34. package/dist/src/commands/dev-doctor.d.ts +137 -0
  35. package/dist/src/commands/dev-doctor.d.ts.map +1 -0
  36. package/dist/src/commands/dev-doctor.js +671 -0
  37. package/dist/src/commands/dev-doctor.js.map +1 -0
  38. package/dist/src/commands/dev-launch.d.ts +59 -0
  39. package/dist/src/commands/dev-launch.d.ts.map +1 -0
  40. package/dist/src/commands/dev-launch.js +118 -0
  41. package/dist/src/commands/dev-launch.js.map +1 -0
  42. package/dist/src/commands/dev-token-server.d.ts +32 -0
  43. package/dist/src/commands/dev-token-server.d.ts.map +1 -0
  44. package/dist/src/commands/dev-token-server.js +68 -0
  45. package/dist/src/commands/dev-token-server.js.map +1 -0
  46. package/dist/src/commands/dev.d.ts +289 -2
  47. package/dist/src/commands/dev.d.ts.map +1 -1
  48. package/dist/src/commands/dev.js +2501 -574
  49. package/dist/src/commands/dev.js.map +1 -1
  50. package/dist/src/commands/docs.d.ts +3 -0
  51. package/dist/src/commands/docs.d.ts.map +1 -0
  52. package/dist/src/commands/docs.js +262 -0
  53. package/dist/src/commands/docs.js.map +1 -0
  54. package/dist/src/commands/hub/index.d.ts +99 -0
  55. package/dist/src/commands/hub/index.d.ts.map +1 -0
  56. package/dist/src/commands/hub/index.js +452 -0
  57. package/dist/src/commands/hub/index.js.map +1 -0
  58. package/dist/src/commands/init.d.ts +65 -0
  59. package/dist/src/commands/init.d.ts.map +1 -0
  60. package/dist/src/commands/init.js +370 -0
  61. package/dist/src/commands/init.js.map +1 -0
  62. package/dist/src/commands/install-shim.d.ts +21 -0
  63. package/dist/src/commands/install-shim.d.ts.map +1 -0
  64. package/dist/src/commands/install-shim.js +132 -0
  65. package/dist/src/commands/install-shim.js.map +1 -0
  66. package/dist/src/commands/local/auth-provision.d.ts +71 -0
  67. package/dist/src/commands/local/auth-provision.d.ts.map +1 -0
  68. package/dist/src/commands/local/auth-provision.js +286 -0
  69. package/dist/src/commands/local/auth-provision.js.map +1 -0
  70. package/dist/src/commands/local/dev-local.d.ts +97 -0
  71. package/dist/src/commands/local/dev-local.d.ts.map +1 -0
  72. package/dist/src/commands/local/dev-local.js +306 -0
  73. package/dist/src/commands/local/dev-local.js.map +1 -0
  74. package/dist/src/commands/local/docker-runner.d.ts +37 -0
  75. package/dist/src/commands/local/docker-runner.d.ts.map +1 -0
  76. package/dist/src/commands/local/docker-runner.js +104 -0
  77. package/dist/src/commands/local/docker-runner.js.map +1 -0
  78. package/dist/src/commands/local/helpers.d.ts +22 -0
  79. package/dist/src/commands/local/helpers.d.ts.map +1 -0
  80. package/dist/src/commands/local/helpers.js +46 -0
  81. package/dist/src/commands/local/helpers.js.map +1 -0
  82. package/dist/src/commands/local/hub-local.d.ts +51 -0
  83. package/dist/src/commands/local/hub-local.d.ts.map +1 -0
  84. package/dist/src/commands/local/hub-local.js +197 -0
  85. package/dist/src/commands/local/hub-local.js.map +1 -0
  86. package/dist/src/commands/local/index.d.ts +23 -0
  87. package/dist/src/commands/local/index.d.ts.map +1 -0
  88. package/dist/src/commands/local/index.js +386 -0
  89. package/dist/src/commands/local/index.js.map +1 -0
  90. package/dist/src/commands/local/mocks.d.ts +361 -0
  91. package/dist/src/commands/local/mocks.d.ts.map +1 -0
  92. package/dist/src/commands/local/mocks.js +756 -0
  93. package/dist/src/commands/local/mocks.js.map +1 -0
  94. package/dist/src/commands/local/seed-zitadel.d.ts +151 -0
  95. package/dist/src/commands/local/seed-zitadel.d.ts.map +1 -0
  96. package/dist/src/commands/local/seed-zitadel.js +408 -0
  97. package/dist/src/commands/local/seed-zitadel.js.map +1 -0
  98. package/dist/src/commands/local/seed.d.ts +106 -0
  99. package/dist/src/commands/local/seed.d.ts.map +1 -0
  100. package/dist/src/commands/local/seed.js +252 -0
  101. package/dist/src/commands/local/seed.js.map +1 -0
  102. package/dist/src/commands/local/stack.d.ts +173 -0
  103. package/dist/src/commands/local/stack.d.ts.map +1 -0
  104. package/dist/src/commands/local/stack.js +499 -0
  105. package/dist/src/commands/local/stack.js.map +1 -0
  106. package/dist/src/commands/login.d.ts +256 -12
  107. package/dist/src/commands/login.d.ts.map +1 -1
  108. package/dist/src/commands/login.js +978 -50
  109. package/dist/src/commands/login.js.map +1 -1
  110. package/dist/src/commands/peer-addressing.d.ts +51 -0
  111. package/dist/src/commands/peer-addressing.d.ts.map +1 -0
  112. package/dist/src/commands/peer-addressing.js +64 -0
  113. package/dist/src/commands/peer-addressing.js.map +1 -0
  114. package/dist/src/commands/port-ownership.d.ts +69 -0
  115. package/dist/src/commands/port-ownership.d.ts.map +1 -0
  116. package/dist/src/commands/port-ownership.js +161 -0
  117. package/dist/src/commands/port-ownership.js.map +1 -0
  118. package/dist/src/commands/registry-publish.d.ts +3 -0
  119. package/dist/src/commands/registry-publish.d.ts.map +1 -0
  120. package/dist/src/commands/registry-publish.js +161 -0
  121. package/dist/src/commands/registry-publish.js.map +1 -0
  122. package/dist/src/commands/registry.d.ts +146 -2
  123. package/dist/src/commands/registry.d.ts.map +1 -1
  124. package/dist/src/commands/registry.js +541 -85
  125. package/dist/src/commands/registry.js.map +1 -1
  126. package/dist/src/commands/secrets/index.d.ts.map +1 -1
  127. package/dist/src/commands/secrets/index.js +15 -1
  128. package/dist/src/commands/secrets/index.js.map +1 -1
  129. package/dist/src/commands/secrets/migrate-config.d.ts +24 -0
  130. package/dist/src/commands/secrets/migrate-config.d.ts.map +1 -0
  131. package/dist/src/commands/secrets/migrate-config.js +277 -0
  132. package/dist/src/commands/secrets/migrate-config.js.map +1 -0
  133. package/dist/src/commands/secrets/set.d.ts +4 -0
  134. package/dist/src/commands/secrets/set.d.ts.map +1 -1
  135. package/dist/src/commands/secrets/set.js +243 -64
  136. package/dist/src/commands/secrets/set.js.map +1 -1
  137. package/dist/src/commands/skills.d.ts +34 -0
  138. package/dist/src/commands/skills.d.ts.map +1 -0
  139. package/dist/src/commands/skills.js +207 -0
  140. package/dist/src/commands/skills.js.map +1 -0
  141. package/dist/src/commands/stack.d.ts.map +1 -1
  142. package/dist/src/commands/stack.js +361 -23
  143. package/dist/src/commands/stack.js.map +1 -1
  144. package/dist/src/commands/temporal.d.ts +15 -0
  145. package/dist/src/commands/temporal.d.ts.map +1 -0
  146. package/dist/src/commands/temporal.js +781 -0
  147. package/dist/src/commands/temporal.js.map +1 -0
  148. package/dist/src/commands/tenant.d.ts +56 -0
  149. package/dist/src/commands/tenant.d.ts.map +1 -0
  150. package/dist/src/commands/tenant.js +233 -0
  151. package/dist/src/commands/tenant.js.map +1 -0
  152. package/dist/src/commands/tunnel/index.d.ts +49 -3
  153. package/dist/src/commands/tunnel/index.d.ts.map +1 -1
  154. package/dist/src/commands/tunnel/index.js +331 -8
  155. package/dist/src/commands/tunnel/index.js.map +1 -1
  156. package/dist/src/commands/vcs/clone.d.ts +3 -0
  157. package/dist/src/commands/vcs/clone.d.ts.map +1 -0
  158. package/dist/src/commands/vcs/clone.js +20 -0
  159. package/dist/src/commands/vcs/clone.js.map +1 -0
  160. package/dist/src/commands/vcs/common.d.ts +21 -0
  161. package/dist/src/commands/vcs/common.d.ts.map +1 -0
  162. package/dist/src/commands/vcs/common.js +62 -0
  163. package/dist/src/commands/vcs/common.js.map +1 -0
  164. package/dist/src/commands/vcs/drafts.d.ts +13 -0
  165. package/dist/src/commands/vcs/drafts.d.ts.map +1 -0
  166. package/dist/src/commands/vcs/drafts.js +45 -0
  167. package/dist/src/commands/vcs/drafts.js.map +1 -0
  168. package/dist/src/commands/vcs/get.d.ts +8 -0
  169. package/dist/src/commands/vcs/get.d.ts.map +1 -0
  170. package/dist/src/commands/vcs/get.js +61 -0
  171. package/dist/src/commands/vcs/get.js.map +1 -0
  172. package/dist/src/commands/vcs/index.d.ts +3 -0
  173. package/dist/src/commands/vcs/index.d.ts.map +1 -0
  174. package/dist/src/commands/vcs/index.js +58 -0
  175. package/dist/src/commands/vcs/index.js.map +1 -0
  176. package/dist/src/commands/vcs/propose.d.ts +23 -0
  177. package/dist/src/commands/vcs/propose.d.ts.map +1 -0
  178. package/dist/src/commands/vcs/propose.js +94 -0
  179. package/dist/src/commands/vcs/propose.js.map +1 -0
  180. package/dist/src/commands/vcs/review.d.ts +15 -0
  181. package/dist/src/commands/vcs/review.d.ts.map +1 -0
  182. package/dist/src/commands/vcs/review.js +35 -0
  183. package/dist/src/commands/vcs/review.js.map +1 -0
  184. package/dist/src/commands/vcs-enrich.d.ts +15 -0
  185. package/dist/src/commands/vcs-enrich.d.ts.map +1 -0
  186. package/dist/src/commands/vcs-enrich.js +28 -0
  187. package/dist/src/commands/vcs-enrich.js.map +1 -0
  188. package/dist/src/commands/vpn/index.d.ts +24 -0
  189. package/dist/src/commands/vpn/index.d.ts.map +1 -0
  190. package/dist/src/commands/vpn/index.js +543 -0
  191. package/dist/src/commands/vpn/index.js.map +1 -0
  192. package/dist/src/commands/vpn/tunnel.d.ts +11 -0
  193. package/dist/src/commands/vpn/tunnel.d.ts.map +1 -0
  194. package/dist/src/commands/vpn/tunnel.js +188 -0
  195. package/dist/src/commands/vpn/tunnel.js.map +1 -0
  196. package/dist/src/commands/workflow.d.ts +24 -0
  197. package/dist/src/commands/workflow.d.ts.map +1 -0
  198. package/dist/src/commands/workflow.js +577 -0
  199. package/dist/src/commands/workflow.js.map +1 -0
  200. package/dist/src/docs/assemble.d.ts +217 -0
  201. package/dist/src/docs/assemble.d.ts.map +1 -0
  202. package/dist/src/docs/assemble.js +739 -0
  203. package/dist/src/docs/assemble.js.map +1 -0
  204. package/dist/src/docs/cli-reference.d.ts +93 -0
  205. package/dist/src/docs/cli-reference.d.ts.map +1 -0
  206. package/dist/src/docs/cli-reference.js +256 -0
  207. package/dist/src/docs/cli-reference.js.map +1 -0
  208. package/dist/src/docs/discover.d.ts +60 -0
  209. package/dist/src/docs/discover.d.ts.map +1 -0
  210. package/dist/src/docs/discover.js +233 -0
  211. package/dist/src/docs/discover.js.map +1 -0
  212. package/dist/src/docs/portal.d.ts +79 -0
  213. package/dist/src/docs/portal.d.ts.map +1 -0
  214. package/dist/src/docs/portal.js +242 -0
  215. package/dist/src/docs/portal.js.map +1 -0
  216. package/dist/src/docs/registry-docs.d.ts +43 -0
  217. package/dist/src/docs/registry-docs.d.ts.map +1 -0
  218. package/dist/src/docs/registry-docs.js +138 -0
  219. package/dist/src/docs/registry-docs.js.map +1 -0
  220. package/dist/src/docs/schema.d.ts +48 -0
  221. package/dist/src/docs/schema.d.ts.map +1 -0
  222. package/dist/src/docs/schema.js +96 -0
  223. package/dist/src/docs/schema.js.map +1 -0
  224. package/dist/src/docs/serve.d.ts +27 -0
  225. package/dist/src/docs/serve.d.ts.map +1 -0
  226. package/dist/src/docs/serve.js +102 -0
  227. package/dist/src/docs/serve.js.map +1 -0
  228. package/dist/src/docs/start.d.ts +80 -0
  229. package/dist/src/docs/start.d.ts.map +1 -0
  230. package/dist/src/docs/start.js +313 -0
  231. package/dist/src/docs/start.js.map +1 -0
  232. package/dist/src/eval/agent-eval.d.mts +14 -0
  233. package/dist/src/eval/agent-eval.d.mts.map +1 -0
  234. package/dist/src/eval/agent-eval.mjs +273 -0
  235. package/dist/src/eval/agent-eval.mjs.map +1 -0
  236. package/dist/src/index.js +624 -7
  237. package/dist/src/index.js.map +7 -1
  238. package/dist/src/program.d.ts +26 -0
  239. package/dist/src/program.d.ts.map +1 -0
  240. package/dist/src/program.js +76 -0
  241. package/dist/src/program.js.map +1 -0
  242. package/dist/src/utils/auth-preflight.d.ts +159 -0
  243. package/dist/src/utils/auth-preflight.d.ts.map +1 -0
  244. package/dist/src/utils/auth-preflight.js +298 -0
  245. package/dist/src/utils/auth-preflight.js.map +1 -0
  246. package/dist/src/utils/aws-auth.d.ts +181 -0
  247. package/dist/src/utils/aws-auth.d.ts.map +1 -0
  248. package/dist/src/utils/aws-auth.js +527 -0
  249. package/dist/src/utils/aws-auth.js.map +1 -0
  250. package/dist/src/utils/bastion.d.ts +1 -1
  251. package/dist/src/utils/bastion.d.ts.map +1 -1
  252. package/dist/src/utils/bastion.js +29 -8
  253. package/dist/src/utils/bastion.js.map +1 -1
  254. package/dist/src/utils/build-info.d.ts +33 -0
  255. package/dist/src/utils/build-info.d.ts.map +1 -0
  256. package/dist/src/utils/build-info.js +102 -0
  257. package/dist/src/utils/build-info.js.map +1 -0
  258. package/dist/src/utils/capture-history.d.ts +62 -0
  259. package/dist/src/utils/capture-history.d.ts.map +1 -0
  260. package/dist/src/utils/capture-history.js +94 -0
  261. package/dist/src/utils/capture-history.js.map +1 -0
  262. package/dist/src/utils/deploy-preflight.d.ts +52 -0
  263. package/dist/src/utils/deploy-preflight.d.ts.map +1 -0
  264. package/dist/src/utils/deploy-preflight.js +183 -0
  265. package/dist/src/utils/deploy-preflight.js.map +1 -0
  266. package/dist/src/utils/errors.d.ts +75 -0
  267. package/dist/src/utils/errors.d.ts.map +1 -0
  268. package/dist/src/utils/errors.js +106 -0
  269. package/dist/src/utils/errors.js.map +1 -0
  270. package/dist/src/utils/first-party-contexts.d.ts +40 -0
  271. package/dist/src/utils/first-party-contexts.d.ts.map +1 -0
  272. package/dist/src/utils/first-party-contexts.js +53 -0
  273. package/dist/src/utils/first-party-contexts.js.map +1 -0
  274. package/dist/src/utils/index.d.ts +2 -0
  275. package/dist/src/utils/index.d.ts.map +1 -1
  276. package/dist/src/utils/index.js +2 -0
  277. package/dist/src/utils/index.js.map +1 -1
  278. package/dist/src/utils/kubeconfig.d.ts +62 -0
  279. package/dist/src/utils/kubeconfig.d.ts.map +1 -0
  280. package/dist/src/utils/kubeconfig.js +118 -0
  281. package/dist/src/utils/kubeconfig.js.map +1 -0
  282. package/dist/src/utils/log.d.ts +27 -1
  283. package/dist/src/utils/log.d.ts.map +1 -1
  284. package/dist/src/utils/log.js +59 -5
  285. package/dist/src/utils/log.js.map +1 -1
  286. package/dist/src/utils/pid.d.ts +47 -0
  287. package/dist/src/utils/pid.d.ts.map +1 -0
  288. package/dist/src/utils/pid.js +83 -0
  289. package/dist/src/utils/pid.js.map +1 -0
  290. package/dist/src/utils/pulumi-run.d.ts +23 -0
  291. package/dist/src/utils/pulumi-run.d.ts.map +1 -0
  292. package/dist/src/utils/pulumi-run.js +112 -0
  293. package/dist/src/utils/pulumi-run.js.map +1 -0
  294. package/dist/src/utils/pulumi.d.ts +15 -0
  295. package/dist/src/utils/pulumi.d.ts.map +1 -1
  296. package/dist/src/utils/pulumi.js +35 -0
  297. package/dist/src/utils/pulumi.js.map +1 -1
  298. package/dist/src/utils/reachability.d.ts +29 -0
  299. package/dist/src/utils/reachability.d.ts.map +1 -0
  300. package/dist/src/utils/reachability.js +81 -0
  301. package/dist/src/utils/reachability.js.map +1 -0
  302. package/dist/src/utils/recover-conversation.d.ts +154 -0
  303. package/dist/src/utils/recover-conversation.d.ts.map +1 -0
  304. package/dist/src/utils/recover-conversation.js +314 -0
  305. package/dist/src/utils/recover-conversation.js.map +1 -0
  306. package/dist/src/utils/registry-broker.d.ts +148 -0
  307. package/dist/src/utils/registry-broker.d.ts.map +1 -0
  308. package/dist/src/utils/registry-broker.js +180 -0
  309. package/dist/src/utils/registry-broker.js.map +1 -0
  310. package/dist/src/utils/socks-forward.d.ts +40 -0
  311. package/dist/src/utils/socks-forward.d.ts.map +1 -0
  312. package/dist/src/utils/socks-forward.js +97 -0
  313. package/dist/src/utils/socks-forward.js.map +1 -0
  314. package/dist/src/utils/stack-flag.d.ts +23 -0
  315. package/dist/src/utils/stack-flag.d.ts.map +1 -0
  316. package/dist/src/utils/stack-flag.js +41 -0
  317. package/dist/src/utils/stack-flag.js.map +1 -0
  318. package/dist/src/utils/tailscale-targets.d.ts +52 -0
  319. package/dist/src/utils/tailscale-targets.d.ts.map +1 -0
  320. package/dist/src/utils/tailscale-targets.js +93 -0
  321. package/dist/src/utils/tailscale-targets.js.map +1 -0
  322. package/dist/src/utils/tailscale.d.ts +277 -0
  323. package/dist/src/utils/tailscale.d.ts.map +1 -0
  324. package/dist/src/utils/tailscale.js +1007 -0
  325. package/dist/src/utils/tailscale.js.map +1 -0
  326. package/dist/src/utils/temporal-auth.d.ts +43 -0
  327. package/dist/src/utils/temporal-auth.d.ts.map +1 -0
  328. package/dist/src/utils/temporal-auth.js +176 -0
  329. package/dist/src/utils/temporal-auth.js.map +1 -0
  330. package/dist/src/utils/temporal-codec.d.ts +101 -0
  331. package/dist/src/utils/temporal-codec.d.ts.map +1 -0
  332. package/dist/src/utils/temporal-codec.js +319 -0
  333. package/dist/src/utils/temporal-codec.js.map +1 -0
  334. package/dist/src/utils/tunnel-ownership.d.ts +130 -0
  335. package/dist/src/utils/tunnel-ownership.d.ts.map +1 -0
  336. package/dist/src/utils/tunnel-ownership.js +274 -0
  337. package/dist/src/utils/tunnel-ownership.js.map +1 -0
  338. package/dist/src/utils/vpn-join.d.ts +32 -0
  339. package/dist/src/utils/vpn-join.d.ts.map +1 -0
  340. package/dist/src/utils/vpn-join.js +62 -0
  341. package/dist/src/utils/vpn-join.js.map +1 -0
  342. package/dist/src/utils/vpn.d.ts +62 -0
  343. package/dist/src/utils/vpn.d.ts.map +1 -0
  344. package/dist/src/utils/vpn.js +183 -0
  345. package/dist/src/utils/vpn.js.map +1 -0
  346. package/dist/src/utils/workflow-fingerprint.d.ts +49 -0
  347. package/dist/src/utils/workflow-fingerprint.d.ts.map +1 -0
  348. package/dist/src/utils/workflow-fingerprint.js +135 -0
  349. package/dist/src/utils/workflow-fingerprint.js.map +1 -0
  350. package/dist/src/utils/worktree-identity.d.ts +86 -0
  351. package/dist/src/utils/worktree-identity.d.ts.map +1 -0
  352. package/dist/src/utils/worktree-identity.js +164 -0
  353. package/dist/src/utils/worktree-identity.js.map +1 -0
  354. package/fragments/agents/AGENTS.md.hbs +92 -0
  355. package/fragments/agents/CLAUDE.md.hbs +8 -0
  356. package/fragments/base/Pulumi.dev.yaml.hbs +10 -0
  357. package/fragments/base/Pulumi.yaml.hbs +9 -0
  358. package/fragments/base/index.ts.hbs +107 -0
  359. package/fragments/base/package.json.hbs +22 -0
  360. package/{templates/api-web-db/api → fragments/base}/tsconfig.json +3 -4
  361. package/fragments/bucket/api/src/storage.ts.hbs +81 -0
  362. package/fragments/database/api/src/db.ts.hbs +23 -0
  363. package/fragments/database/prisma/schema.prisma.hbs +18 -0
  364. package/{templates/api-web-db → fragments/service}/api/.dockerignore +2 -0
  365. package/fragments/service/api/package.json.hbs +40 -0
  366. package/fragments/service/api/src/index.ts.hbs +58 -0
  367. package/{templates/api-web-db → fragments/service/api}/tsconfig.json +5 -3
  368. package/fragments/temporal/worker/.dockerignore +4 -0
  369. package/fragments/temporal/worker/Dockerfile +15 -0
  370. package/{templates/temporal-api-worker → fragments/temporal}/worker/package.json.hbs +3 -2
  371. package/fragments/temporal/worker/src/activities.ts.hbs +14 -0
  372. package/fragments/temporal/worker/src/worker.ts.hbs +27 -0
  373. package/fragments/temporal/worker/src/workflows.ts.hbs +24 -0
  374. package/fragments/temporal/worker/tsconfig.json +13 -0
  375. package/package.json +35 -21
  376. package/skills/core/SKILL.md +365 -0
  377. package/skills/pull-remote-agent-context/SKILL.md +194 -0
  378. package/stack/docker-compose.hub.yml +134 -0
  379. package/stack/docker-compose.yml +447 -0
  380. package/stack/hub/Dockerfile.api +18 -0
  381. package/stack/hub/Dockerfile.auth +10 -0
  382. package/stack/hub/Dockerfile.ui +10 -0
  383. package/stack/init/01-databases.sql +12 -0
  384. package/stack/observability/blackbox.yml +20 -0
  385. package/stack/observability/otel-collector.yaml +73 -0
  386. package/stack/observability/prometheus.yml +36 -0
  387. package/stack/observability/tempo.yaml +25 -0
  388. package/stack/temporal/local.yaml +44 -0
  389. package/templates/api-auth/AGENTS.md.hbs +16 -0
  390. package/templates/api-auth/Pulumi.dev.yaml.hbs +8 -0
  391. package/templates/api-auth/Pulumi.yaml.hbs +8 -0
  392. package/templates/api-auth/README.md.hbs +67 -0
  393. package/templates/api-auth/api/package.json.hbs +28 -0
  394. package/templates/api-auth/api/src/index.ts.hbs +96 -0
  395. package/templates/api-auth/api/src/schema.ts.hbs +35 -0
  396. package/templates/api-auth/api/src/seed-authz.ts.hbs +48 -0
  397. package/templates/api-auth/api/src/spicedb-http-provider.ts.hbs +89 -0
  398. package/templates/api-auth/index.ts.hbs +65 -0
  399. package/templates/api-auth/package.json.hbs +20 -0
  400. package/templates/api-auth/skills/develop/SKILL.md.hbs +32 -0
  401. package/templates/api-role-gating/AGENTS.md.hbs +20 -0
  402. package/templates/api-role-gating/Pulumi.dev.yaml.hbs +8 -0
  403. package/templates/api-role-gating/Pulumi.yaml.hbs +8 -0
  404. package/templates/api-role-gating/README.md.hbs +64 -0
  405. package/templates/api-role-gating/api/Dockerfile +17 -0
  406. package/templates/api-role-gating/api/package.json.hbs +28 -0
  407. package/templates/api-role-gating/api/src/authn.ts.hbs +29 -0
  408. package/templates/api-role-gating/api/src/authz.ts.hbs +12 -0
  409. package/templates/api-role-gating/api/src/main.ts.hbs +58 -0
  410. package/templates/api-role-gating/api/src/schema.ts.hbs +22 -0
  411. package/templates/api-role-gating/api/tsconfig.json +13 -0
  412. package/templates/api-role-gating/index.ts.hbs +107 -0
  413. package/templates/api-role-gating/package.json.hbs +21 -0
  414. package/templates/api-role-gating/skills/develop/SKILL.md.hbs +60 -0
  415. package/templates/api-role-gating/tsconfig.json +10 -0
  416. package/templates/apps-repo/README.md.hbs +24 -0
  417. package/templates/apps-repo/gitignore +41 -0
  418. package/templates/apps-repo/npmrc.hbs +7 -0
  419. package/templates/apps-repo/package.json.hbs +15 -0
  420. package/templates/apps-repo/pnpm-workspace.yaml +3 -0
  421. package/templates/apps-repo/tsconfig.json +18 -0
  422. package/templates/external-service/AGENTS.md.hbs +20 -0
  423. package/templates/external-service/Pulumi.dev.yaml.hbs +8 -0
  424. package/templates/external-service/Pulumi.yaml.hbs +8 -0
  425. package/templates/external-service/README.md.hbs +56 -0
  426. package/templates/external-service/api/Dockerfile +15 -0
  427. package/templates/external-service/api/package.json.hbs +25 -0
  428. package/templates/external-service/api/src/index.ts.hbs +81 -0
  429. package/templates/external-service/index.ts.hbs +82 -0
  430. package/templates/external-service/mocks/vendorpay/package.json.hbs +9 -0
  431. package/templates/external-service/mocks/vendorpay/server.mjs.hbs +61 -0
  432. package/templates/external-service/package.json.hbs +34 -0
  433. package/templates/external-service/skills/develop/SKILL.md.hbs +55 -0
  434. package/templates/external-service/tsconfig.json +10 -0
  435. package/templates/platform-repo/AGENTS.md.hbs +18 -0
  436. package/templates/platform-repo/README.md.hbs +38 -0
  437. package/templates/platform-repo/core/Pulumi.yaml.hbs +12 -0
  438. package/templates/platform-repo/core/Pulumi.{{tenant}}-{{env}}.yaml.hbs +57 -0
  439. package/templates/platform-repo/core/index.ts +62 -0
  440. package/templates/platform-repo/core/package.json.hbs +22 -0
  441. package/templates/platform-repo/core/tsconfig.json +8 -0
  442. package/templates/platform-repo/package.json.hbs +15 -0
  443. package/templates/platform-repo/platform/Pulumi.yaml.hbs +12 -0
  444. package/templates/platform-repo/platform/Pulumi.{{tenant}}-{{env}}.yaml.hbs +59 -0
  445. package/templates/platform-repo/platform/index.ts +95 -0
  446. package/templates/platform-repo/platform/package.json.hbs +26 -0
  447. package/templates/platform-repo/platform/tsconfig.json +8 -0
  448. package/templates/platform-repo/pnpm-workspace.yaml +3 -0
  449. package/templates/workflow/AGENTS.md.hbs +15 -0
  450. package/templates/workflow/Pulumi.dev.yaml.hbs +8 -0
  451. package/templates/workflow/Pulumi.yaml.hbs +8 -0
  452. package/templates/workflow/README.md.hbs +45 -0
  453. package/templates/workflow/api/.dockerignore +4 -0
  454. package/templates/workflow/api/Dockerfile +15 -0
  455. package/templates/{temporal-api-worker → workflow}/api/package.json.hbs +8 -6
  456. package/templates/workflow/api/src/index.ts.hbs +130 -0
  457. package/templates/workflow/api/tsconfig.json +14 -0
  458. package/templates/workflow/index.ts.hbs +67 -0
  459. package/templates/workflow/package.json.hbs +20 -0
  460. package/templates/workflow/skills/develop/SKILL.md.hbs +32 -0
  461. package/templates/workflow/tsconfig.json +10 -0
  462. package/templates/workflow/worker/.dockerignore +4 -0
  463. package/templates/workflow/worker/Dockerfile +13 -0
  464. package/templates/workflow/worker/package.json.hbs +25 -0
  465. package/templates/workflow/worker/src/worker.ts.hbs +24 -0
  466. package/templates/workflow/worker/tsconfig.json +14 -0
  467. package/dist/src/commands/devbox.d.ts +0 -22
  468. package/dist/src/commands/devbox.d.ts.map +0 -1
  469. package/dist/src/commands/devbox.js +0 -463
  470. package/dist/src/commands/devbox.js.map +0 -1
  471. package/templates/api-web-db/api/Dockerfile +0 -16
  472. package/templates/api-web-db/api/package.json.hbs +0 -21
  473. package/templates/api-web-db/api/src/index.ts.hbs +0 -123
  474. package/templates/api-web-db/package.json.hbs +0 -27
  475. package/templates/api-web-db/sst.config.ts.hbs +0 -151
  476. package/templates/api-web-db/web/.dockerignore +0 -3
  477. package/templates/api-web-db/web/Dockerfile +0 -17
  478. package/templates/api-web-db/web/app/lib/db.server.ts +0 -36
  479. package/templates/api-web-db/web/app/root.tsx +0 -29
  480. package/templates/api-web-db/web/app/routes/home.tsx.hbs +0 -114
  481. package/templates/api-web-db/web/app/routes.ts +0 -3
  482. package/templates/api-web-db/web/package.json.hbs +0 -30
  483. package/templates/api-web-db/web/prisma/schema.prisma +0 -25
  484. package/templates/api-web-db/web/prisma.config.ts +0 -18
  485. package/templates/api-web-db/web/react-router.config.ts +0 -5
  486. package/templates/api-web-db/web/tsconfig.json +0 -19
  487. package/templates/api-web-db/web/vite.config.ts +0 -9
  488. package/templates/temporal-api-worker/README.md.hbs +0 -133
  489. package/templates/temporal-api-worker/api/src/index.ts.hbs +0 -145
  490. package/templates/temporal-api-worker/package.json.hbs +0 -29
  491. package/templates/temporal-api-worker/sst.config.ts.hbs +0 -161
  492. package/templates/temporal-api-worker/worker/Dockerfile +0 -11
  493. package/templates/temporal-api-worker/worker/src/bundle-workflows.ts +0 -38
  494. package/templates/temporal-api-worker/worker/src/worker.ts.hbs +0 -93
  495. /package/templates/{temporal-api-worker → api-auth}/api/.dockerignore +0 -0
  496. /package/templates/{temporal-api-worker → api-auth}/api/Dockerfile +0 -0
  497. /package/templates/{temporal-api-worker → api-auth}/api/tsconfig.json +0 -0
  498. /package/templates/{temporal-api-worker → api-auth}/tsconfig.json +0 -0
  499. /package/templates/{temporal-api-worker/worker → api-role-gating/api}/.dockerignore +0 -0
  500. /package/templates/{temporal-api-worker/worker → external-service/api}/tsconfig.json +0 -0
  501. /package/templates/{temporal-api-worker → workflow}/api/src/encryption-codec.ts +0 -0
  502. /package/templates/{temporal-api-worker → workflow}/worker/src/activities.ts.hbs +0 -0
  503. /package/templates/{temporal-api-worker → workflow}/worker/src/encryption-codec.ts +0 -0
  504. /package/templates/{temporal-api-worker → workflow}/worker/src/workflows.ts.hbs +0 -0
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: develop-{{name}}
3
+ description: Run, extend, and deploy the {{name}} authenticated API — local 401/200/403 proof, adding resources/actions to the authz schema, gated routes.
4
+ ---
5
+
6
+ # Developing {{name}}
7
+
8
+ ## Run locally + prove auth (zero cloud access)
9
+
10
+ ```bash
11
+ mesh start && mesh login local && pnpm install && mesh dev
12
+ ```
13
+
14
+ Then the README's curl sequence: `/health` open → `/api/me` 401 without / 200 with the `mesh login local` token → `/api/report` 403 until `pnpm seed:authz -- <sub>` grants `report:view` → 200. Grants are per-subject in SpiceDB — `ops@local.mesh` stays 403.
15
+
16
+ ## Add a gated resource or action
17
+
18
+ 1. Extend `api/src/schema.ts` (`defineSchema`): add the resource/action/relation. The schema is the single source of truth — never hand-roll checks.
19
+ 2. Gate the route: `app.get("/api/thing/:id", m.require("thing", "view"), …)` (the `:id` param is the resource id by default).
20
+ 3. Re-run `pnpm seed:authz` (it rewrites the compiled SpiceDB schema), grant relations with the provider's `writeRelationship`, and re-curl.
21
+
22
+ ## Auth planes
23
+
24
+ - **authn** (`@mesh-tech/authn`, zitadel-jwt): who is calling — `requireAuth()` on `/api/*`, `publicRoute()` for open routes. Issuer comes from `ZITADEL_ISSUER` (mesh dev injects it, local or tethered).
25
+ - **authz** (`@mesh-tech/authz`): what they may do — `m.require(resource, action)` backed by SpiceDB (`SPICEDB_HTTP_ENDPOINT`/`SPICEDB_PRESHARED_KEY`).
26
+ - **Deployed edge**: the Service also runs behind the platform oauth2-proxy (`auth:` block in `index.ts`, needs `{{name}}:authClientId`/`authClientSecret` stack config).
27
+
28
+ ## Deploy
29
+
30
+ ```bash
31
+ mesh login {{tenant}}.dev && mesh deploy up --yes
32
+ ```
@@ -0,0 +1,20 @@
1
+ # Agent guidance — {{name}} (role-gating API)
2
+
3
+ - Invoke the CLI as `pnpm mesh <cmd>` or (cwd-independent) `pnpm exec mesh <cmd>`.
4
+ Operations are `mesh` commands, never raw `aws`/`pulumi`/`kubectl`.
5
+ - This app is **role-gating**: authorization is a coarse-role check on the
6
+ caller's Zitadel project roles, enforced in-process. There is NO SpiceDB — do
7
+ not add one (the `AppAuthzPointer` guard fails the deploy if you do).
8
+ - Authorization vocabulary lives ONLY in `api/src/schema.ts` (`coarseRoles`).
9
+ Routes enforce it with `m.requireRole("<role>")` — never hand-roll role checks.
10
+ The same `coarseRoles` become the app's Zitadel project roles in `index.ts`.
11
+ - **Two non-negotiables for role-gating apps (already wired — keep them):**
12
+ 1. `api/package.json` build MUST be `esm-bundle …`, not `tsc` — plain `tsc`
13
+ ships bare `@mesh-tech/*` imports the container can't resolve.
14
+ 2. `index.ts` MUST `Export` `compileOpsHubMetadata(schema)` and pass
15
+ `opsHubMetadataRef` to `AppAuthzPointer`, or the Hub create-key wizard
16
+ 409s (`METADATA_UNPUBLISHED`).
17
+ - Machine/API-key callers carry roles under the project-id-keyed Zitadel claim;
18
+ `authn.ts` passes `projectId` to `zitadelJwtScheme` so it reads the right key.
19
+ - Pattern skills for authn/authz ship inside those packages (TanStack Intent
20
+ discovers them after `pnpm install`).
@@ -0,0 +1,8 @@
1
+ config:
2
+ aws:region: us-east-2
3
+ mesh:tenant: {{tenant}}
4
+ mesh:platform:
5
+ name: mesh
6
+ env: dev
7
+ mesh:deploy: false
8
+ mesh:deployerRole: arn:aws:iam::123456789012:role/{{tenant}}-dev-apps-deployer
@@ -0,0 +1,8 @@
1
+ name: {{name}}
2
+ runtime:
3
+ name: nodejs
4
+ options:
5
+ packagemanager: pnpm
6
+ nodeargs: "--import tsx"
7
+ backend:
8
+ url: s3://mesh-platform-pulumi-state
@@ -0,0 +1,64 @@
1
+ # {{titleCase name}}
2
+
3
+ A **role-gating** API: authorization is a coarse-role check on the caller's
4
+ Zitadel project roles — enforced **in-process**, no SpiceDB. This is the
5
+ `role-gating` counterpart to the `api-auth` (policy-engine) template.
6
+
7
+ - `@mesh-tech/authn` (Zitadel JWT) — who is calling.
8
+ - `@mesh-tech/authz` with `zitadelRoleProvider()` — `m.requireRole("<role>")`,
9
+ resolved from the roles that rode in on the token.
10
+
11
+ ## Routes
12
+
13
+ | Route | Requires |
14
+ |------------|---------------------|
15
+ | `/health` | nothing (open) |
16
+ | `/admin` | role `admin` |
17
+ | `/reports` | role `viewer` |
18
+
19
+ Roles are declared once in `api/src/schema.ts` (`coarseRoles`) and become the
20
+ app's Zitadel **project roles** (see `index.ts`).
21
+
22
+ ## Run it locally
23
+
24
+ ```bash
25
+ mesh start # local platform (seeded Zitadel)
26
+ pnpm install
27
+ mesh dev # wires the api to the local platform
28
+ ```
29
+
30
+ ## Two things a role-gating app MUST do (baked in here)
31
+
32
+ 1. **`esm-bundle` build, not `tsc`.** `api/package.json` builds with
33
+ `esm-bundle src/main.ts --outfile dist/main.js` — plain `tsc` leaves bare
34
+ `@mesh-tech/*` workspace imports unresolvable in the container
35
+ (`ERR_MODULE_NOT_FOUND` / CrashLoopBackOff).
36
+ 2. **Publish ops-hub metadata.** `index.ts` exports `compileOpsHubMetadata(schema)`
37
+ at the conventional path and threads `opsHubMetadataRef` into
38
+ `AppAuthzPointer`. Without it the Hub's create-key wizard hard-409s
39
+ (`METADATA_UNPUBLISHED`) — a role-gating app has no `SpiceDBSchema` component
40
+ to publish the blob for it.
41
+
42
+ ## Add or change roles
43
+
44
+ Edit `coarseRoles` in `api/src/schema.ts`, gate routes with
45
+ `m.requireRole("<role>")`, and redeploy — `ZitadelAppIdentity` re-syncs the
46
+ project roles and the ops-hub metadata republishes automatically.
47
+
48
+ ## Deploy
49
+
50
+ ```bash
51
+ mesh login {{tenant}}.dev && mesh deploy up --yes
52
+ ```
53
+
54
+ The target platform must have Zitadel enabled (the `ZitadelConnector` reads it
55
+ at preview time).
56
+
57
+ ## Layout
58
+
59
+ - `index.ts` — Pulumi program (identity + roles, Service, ops-hub metadata,
60
+ `AppAuthzPointer` mode `role-gating`)
61
+ - `api/src/main.ts` — Hono app: authn middleware + `m.requireRole(...)`
62
+ - `api/src/schema.ts` — the authz schema (single source of truth; `coarseRoles`)
63
+ - `api/src/authn.ts` — Zitadel JWT scheme (project-id-keyed roles claim)
64
+ - `api/src/authz.ts` — in-process `zitadelRoleProvider()`
@@ -0,0 +1,17 @@
1
+ # NOTE: mesh.apps.Service auto-builds pnpm-workspace apps on the host and
2
+ # generates its own Docker context — this Dockerfile is a fallback for manual
3
+ # builds. The build needs devDeps (esm-bundle bundles workspace imports into a
4
+ # single file), so install ALL deps, not --omit=dev.
5
+ FROM node:20-slim
6
+
7
+ WORKDIR /app
8
+
9
+ COPY package*.json ./
10
+ RUN npm ci
11
+
12
+ COPY . .
13
+ RUN npm run build
14
+
15
+ EXPOSE 3000
16
+
17
+ CMD ["node", "dist/main.js"]
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "{{name}}-api",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./src/main.ts",
8
+ "./schema": "./src/schema.ts"
9
+ },
10
+ "scripts": {
11
+ "dev": "tsx watch src/main.ts",
12
+ "start": "node dist/main.js",
13
+ "build": "esm-bundle src/main.ts --outfile dist/main.js",
14
+ "check-types": "tsc --noEmit"
15
+ },
16
+ "dependencies": {
17
+ "@mesh-tech/authn": "latest",
18
+ "@mesh-tech/authz": "latest",
19
+ "hono": "^4.0.0",
20
+ "@hono/node-server": "^1.0.0"
21
+ },
22
+ "devDependencies": {
23
+ "@mesh-tech/esm-bundle": "latest",
24
+ "@types/node": "^20.0.0",
25
+ "tsx": "^4.0.0",
26
+ "typescript": "^5.0.0"
27
+ }
28
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * L1 authn — Zitadel JWT (@mesh-tech/authn).
3
+ *
4
+ * `projectId` (the app's own Zitadel project id / token audience) is passed so
5
+ * the scheme reads the PROJECT-ID-KEYED roles claim
6
+ * (`urn:zitadel:iam:org:project:${projectId}:roles`) that machine
7
+ * (client-credentials / API-key) tokens actually carry — the generic claim is
8
+ * empty for those, so wiring the wrong key silently 403s every gated route
9
+ * (MESH-2288 / MESH-2282). Fails closed when unconfigured.
10
+ */
11
+ import { createAuthn, type Authn, type AuthnScheme } from "@mesh-tech/authn";
12
+ import { zitadelJwtScheme } from "@mesh-tech/authn/schemes/zitadel-jwt";
13
+
14
+ export const createAuthnFromEnv = (env: NodeJS.ProcessEnv = process.env): Authn | undefined => {
15
+ const schemes: Record<string, AuthnScheme> = {};
16
+ if (env.ZITADEL_ISSUER) {
17
+ const audience = env.ZITADEL_AUDIENCE ?? env.ZITADEL_PROJECT_ID;
18
+ if (!audience) throw new Error("{{name}} authn: ZITADEL_ISSUER set but no ZITADEL_PROJECT_ID/ZITADEL_AUDIENCE");
19
+ // The app knows its own project id (== audience here); let the scheme derive
20
+ // the exact project-scoped roles claim from it.
21
+ const projectId = env.ZITADEL_PROJECT_ID ?? audience;
22
+ schemes["zitadel-jwt"] = zitadelJwtScheme({
23
+ issuer: env.ZITADEL_ISSUER,
24
+ audience,
25
+ projectId,
26
+ });
27
+ }
28
+ return Object.keys(schemes).length > 0 ? createAuthn({ schemes }) : undefined;
29
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * L2 authz — role-gating (@mesh-tech/authz).
3
+ *
4
+ * `zitadelRoleProvider` resolves checks IN-PROCESS from the verified JWT's
5
+ * project roles — no SpiceDB, no metadata fetcher, no network dependency
6
+ * (authz spec §2). Routes gate with `m.requireRole("<role>")`.
7
+ */
8
+ import { createAuthz, zitadelRoleProvider } from "@mesh-tech/authz/runtime";
9
+ import schema from "./schema.js";
10
+
11
+ export const createAppAuthz = () =>
12
+ createAuthz({ schemas: { "{{name}}": { schema, provider: zitadelRoleProvider() } } });
@@ -0,0 +1,58 @@
1
+ /**
2
+ * {{titleCase name}} api — role-gating reference (authz mode "role-gating").
3
+ * L1 authn: Zitadel JWT (audience = this app's project).
4
+ * L2 authz: `requireRole` against the roles that rode in on the token.
5
+ *
6
+ * `deps.testAuth` swaps L1 for a fixed principal in unit tests; production
7
+ * always runs the real scheme (fail-closed 401 when unconfigured).
8
+ */
9
+ import { serve } from "@hono/node-server";
10
+ import { Hono } from "hono";
11
+ import { createAuthnMiddleware, type AuthnVariables } from "@mesh-tech/authn/hono";
12
+ import { createAuthzMiddleware, type AuthzVariables } from "@mesh-tech/authz/hono";
13
+ import { createAuthnFromEnv } from "./authn.js";
14
+ import { createAppAuthz } from "./authz.js";
15
+
16
+ type TestAuth = { subjectSub: string; coarseRole?: string | readonly string[] };
17
+ type AppEnv = { Variables: AuthnVariables & AuthzVariables };
18
+
19
+ /** The role-gated route paths (kept in one place so authn + authz agree). */
20
+ const GATED = ["/admin", "/reports"] as const;
21
+
22
+ export const createApp = (deps: { testAuth?: TestAuth } = {}) => {
23
+ const app = new Hono<AppEnv>();
24
+ const m = createAuthzMiddleware(createAppAuthz());
25
+
26
+ // Open: no token needed.
27
+ app.get("/health", (c) => c.json({ ok: true, app: "{{name}}", mode: "role-gating" }));
28
+
29
+ if (deps.testAuth) {
30
+ const testAuth = deps.testAuth;
31
+ app.use("*", async (c, next) => {
32
+ c.set("auth", { scheme: "test", authenticatedAt: Date.now(), ...testAuth });
33
+ await next();
34
+ });
35
+ } else {
36
+ const authn = createAuthnFromEnv();
37
+ if (authn) {
38
+ const { middleware } = createAuthnMiddleware(authn);
39
+ for (const path of GATED) app.use(path, middleware());
40
+ } else {
41
+ // Fail closed: no authn configured → every gated route is 401, never open.
42
+ for (const path of GATED) app.use(path, (c) => c.json({ error: "authn unconfigured" }, 401));
43
+ }
44
+ }
45
+ app.use("*", m.authContextMiddleware());
46
+
47
+ // Role-gated: the caller's Zitadel project roles must include the named role.
48
+ app.get("/admin", m.requireRole("admin"), (c) => c.json({ ok: true, role: "admin" }));
49
+ app.get("/reports", m.requireRole("viewer"), (c) => c.json({ reports: [], role: "viewer" }));
50
+
51
+ return app;
52
+ };
53
+
54
+ if (process.env.NODE_ENV !== "test" && process.argv[1]?.endsWith("main.js")) {
55
+ const port = Number(process.env.PORT ?? 3000);
56
+ serve({ fetch: createApp().fetch, port });
57
+ console.log(`{{name}} api listening on :${port} (role-gating)`);
58
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Authorization schema — the single source of truth (@mesh-tech/authz).
3
+ *
4
+ * mode "role-gating": enforcement is a coarse-role check on the caller's
5
+ * Zitadel project roles (no SpiceDB, no resources/relations). `coarseRoles` is
6
+ * the whole vocabulary — it becomes the app's Zitadel PROJECT ROLES (declared
7
+ * in `index.ts`), what the Hub create-key wizard lists, and what
8
+ * `m.requireRole(...)` checks against at request time.
9
+ *
10
+ * Exported as the DEFAULT export so both the api runtime (`authz.ts`) and the
11
+ * Pulumi program (`index.ts`, for `compileOpsHubMetadata`) import the same
12
+ * definition.
13
+ */
14
+
15
+ import { defineSchema } from "@mesh-tech/authz/schema";
16
+
17
+ export default defineSchema({
18
+ namespace: "{{name}}",
19
+ version: "0.1.0",
20
+ mode: "role-gating",
21
+ coarseRoles: ["admin", "viewer"] as const,
22
+ });
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true
11
+ },
12
+ "include": ["src/**/*"]
13
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * {{titleCase name}} — role-gating API (authz mode "role-gating", MESH-2278).
3
+ *
4
+ * Authorization is enforced IN-PROCESS from the Zitadel JWT's project roles —
5
+ * there is NO SpiceDB. The app declares its coarse roles as Zitadel PROJECT
6
+ * ROLES (so API keys can be granted them), publishes its ops-hub metadata
7
+ * (required — the Hub create-key wizard 409s without it), and broadcasts
8
+ * mode "role-gating". Counterpart to the `api-auth` (policy-engine) template.
9
+ *
10
+ * Wires, IN ORDER:
11
+ * 1. ZitadelConnector — authed provider for the platform Zitadel.
12
+ * 2. ZitadelAppIdentity — this app's OWN project; roles = schema.coarseRoles
13
+ * (roleAssertion defaults ON so granted roles ride in
14
+ * tokens — essential; there is no SpiceDB fallback).
15
+ * 3. AppEnvironment — namespace + providers, bound to the app's project.
16
+ * 4. api Service — Hono app gating routes by role, in-process.
17
+ * 5. ops-hub metadata — the compiled schema blob (coarseRoles + mode).
18
+ * 6. AppAuthzPointer — mode "role-gating"; guard fails deploy if SpiceDB.
19
+ *
20
+ * Prerequisite: the target platform must have Zitadel enabled — ZitadelConnector
21
+ * eager-reads it at preview time.
22
+ *
23
+ * Local: mesh start && mesh dev
24
+ * Deploy: mesh deploy up
25
+ */
26
+ import * as pulumi from "@pulumi/pulumi";
27
+ import { mesh } from "@mesh-tech/app-kit";
28
+ import { compileOpsHubMetadata } from "@mesh-tech/authz";
29
+ import type { OpsHubMetadata } from "@mesh-tech/authz";
30
+ // The authz schema is the single source of truth, shared by the api (enforces
31
+ // it) and this Pulumi program (compiles it to ops-hub metadata + Zitadel roles).
32
+ import schemaDef from "./api/src/schema.js";
33
+
34
+ const { tenant, platform, stack, deploy } = mesh.apps.getConfig(pulumi);
35
+ const appName = "{{name}}";
36
+
37
+ // --- 1. Connector — authed provider for the platform Zitadel. ---
38
+ const connector = new mesh.auth.ZitadelConnector("idp", { tenant, env: platform.env });
39
+
40
+ // --- 2. App identity — this app's OWN Zitadel project + roles. ---
41
+ // The schema's coarse roles become Zitadel PROJECT ROLES: the vocabulary the
42
+ // api-keys control plane grants against and the Hub create-key wizard lists.
43
+ // roleAssertion defaults ON (roles are declared) so granted roles ride in the
44
+ // token — without it a minted API key authenticates but carries no roles, which
45
+ // is fatal for role-gating (no SpiceDB fallback).
46
+ const identity = new mesh.auth.ZitadelAppIdentity("identity", {
47
+ connector,
48
+ tenant,
49
+ env: platform.env,
50
+ project: { name: appName },
51
+ roles: [...schemaDef.coarseRoles],
52
+ applications: {
53
+ api: { type: "api" },
54
+ },
55
+ });
56
+
57
+ // --- 3. Environment — bound to the app's own project via zitadelAppProjectId. ---
58
+ const env = new mesh.apps.AppEnvironment("env", {
59
+ tenant,
60
+ platform,
61
+ stack,
62
+ deploy,
63
+ appName,
64
+ namespace: true,
65
+ database: false,
66
+ zitadelAppProjectId: identity.projectId,
67
+ });
68
+
69
+ // --- 4. api Service — in-process authn + role check; no oauth2-proxy, no SpiceDB. ---
70
+ const api = new mesh.apps.Service("api", {
71
+ env,
72
+ runtime: "node",
73
+ src: "./api",
74
+ port: 3000,
75
+ environment: {
76
+ ZITADEL_ISSUER: pulumi.output(env.zitadel).apply((z) => z?.issuer ?? ""),
77
+ ZITADEL_PROJECT_ID: identity.projectId,
78
+ },
79
+ ingress: env.buildIngress({
80
+ subdomain: "{{name}}-api",
81
+ healthCheckPath: "/health",
82
+ }),
83
+ replicas: 1,
84
+ resources: { cpu: "100m", memory: "128Mi" },
85
+ });
86
+
87
+ // --- 5. Ops-hub metadata — MANDATORY for role-gating apps. ---
88
+ // The Hub create-key path validates requested roles against the PUBLISHED
89
+ // coarseRoles and hard-409s (METADATA_UNPUBLISHED) without it. Role-gating apps
90
+ // have no SpiceDBSchema component to export it, so publish the compiled blob
91
+ // directly at the conventional path the Hub assembler sweeps.
92
+ const opsHubMetadataRef = `/mesh-platform/${tenant}/${platform.env}/apps/${appName}/stacks/${stack}/authz/ops-hub-metadata`;
93
+ new mesh.exports.Export<OpsHubMetadata>("ops-hub-metadata", {
94
+ path: opsHubMetadataRef,
95
+ value: compileOpsHubMetadata(schemaDef),
96
+ });
97
+
98
+ // --- 6. AppAuthzPointer — LAST. mode "role-gating" tells Ops Hub to render the
99
+ // role-gating surface; its guard fails the deploy if any SpiceDB is registered. ---
100
+ new mesh.auth.AppAuthzPointer("authz", { env, mode: "role-gating", opsHubMetadataRef });
101
+
102
+ export const app = env.register({
103
+ description: "{{titleCase name}} — role-gating API (roles enforced in-process from the Zitadel JWT)",
104
+ });
105
+
106
+ /** The app's own Zitadel project id (grant API keys against this). */
107
+ export const zitadelProjectId = identity.projectId;
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "packageManager": "pnpm@10.29.2",
7
+ "keywords": ["tanstack-intent"],
8
+ "scripts": {
9
+ "mesh": "mesh",
10
+ "typecheck": "tsc --noEmit"
11
+ },
12
+ "dependencies": {
13
+ "@mesh-tech/app-kit": "latest",
14
+ "@mesh-tech/authz": "latest",
15
+ "@pulumi/pulumi": "^3.214.1"
16
+ },
17
+ "devDependencies": {
18
+ "tsx": "^4.20.4",
19
+ "typescript": "^5.7.2"
20
+ }
21
+ }
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: develop-{{name}}
3
+ description: Run, extend, and deploy the {{name}} role-gating API — coarse-role checks on Zitadel project roles (no SpiceDB), esm-bundle build, mandatory ops-hub metadata export.
4
+ ---
5
+
6
+ # Developing {{name}} (role-gating)
7
+
8
+ This app enforces authorization as a **coarse-role check** on the caller's
9
+ Zitadel project roles, **in-process** — no SpiceDB. Roles are declared once in
10
+ `api/src/schema.ts` and become the app's Zitadel project roles in `index.ts`.
11
+
12
+ ## Run locally
13
+
14
+ ```bash
15
+ mesh start && pnpm install && mesh dev
16
+ ```
17
+
18
+ `/health` is open; `/admin` needs role `admin`; `/reports` needs role `viewer`.
19
+ A token without the role → 403; no/invalid token on a gated route → 401.
20
+
21
+ ## Add or change a role-gated route
22
+
23
+ 1. Add the role to `coarseRoles` in `api/src/schema.ts`.
24
+ 2. Gate the route: `app.get("/thing", m.requireRole("<role>"), …)` and add its
25
+ path to the `GATED` list in `api/src/main.ts` (so authn runs on it too).
26
+ 3. Redeploy — `ZitadelAppIdentity` re-syncs the project roles and the ops-hub
27
+ metadata republishes.
28
+
29
+ ## Two role-gating gotchas (already wired — do NOT regress)
30
+
31
+ Both were discovered the hard way (MESH-2282) and each costs a redeploy:
32
+
33
+ 1. **`esm-bundle` build, not `tsc`.** `api/package.json`:
34
+ `"build": "esm-bundle src/main.ts --outfile dist/main.js"` with the
35
+ `@mesh-tech/esm-bundle` devDep. Plain `tsc` leaves bare `@mesh-tech/*`
36
+ workspace imports unresolvable in the Service container
37
+ (`ERR_MODULE_NOT_FOUND` / CrashLoopBackOff).
38
+ 2. **Publish ops-hub metadata.** `index.ts` does
39
+ `mesh.exports.Export(compileOpsHubMetadata(schema))` at
40
+ `…/apps/{{name}}/stacks/{stack}/authz/ops-hub-metadata` and passes that
41
+ `opsHubMetadataRef` to `AppAuthzPointer`. A role-gating app has no
42
+ `SpiceDBSchema` component to publish this, and the Hub create-key wizard
43
+ hard-409s (`METADATA_UNPUBLISHED`) without it — it validates requested roles
44
+ against the app's PUBLISHED `coarseRoles`.
45
+
46
+ ## Never add SpiceDB
47
+
48
+ `AppAuthzPointer({ mode: "role-gating" })` trips a deploy-time guard if any
49
+ SpiceDB instance is registered. Role-gating means roles are the whole authz
50
+ story; for resource/relation-level rules use the `api-auth` (policy-engine)
51
+ template instead.
52
+
53
+ ## Deploy
54
+
55
+ ```bash
56
+ mesh login {{tenant}}.dev && mesh deploy up --yes
57
+ ```
58
+
59
+ The target platform must have Zitadel enabled — `ZitadelConnector` reads it at
60
+ preview time.
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true
9
+ }
10
+ }
@@ -0,0 +1,24 @@
1
+ # {{repoName}}
2
+
3
+ {{tenantTitle}} applications deployed on the Mesh platform (app tenant: `{{tenant}}`).
4
+
5
+ Each directory under `apps/` is an independent Pulumi project scaffolded with
6
+ `mesh create-app`.
7
+
8
+ ## Setup
9
+
10
+ ```bash
11
+ mesh registry login # CodeArtifact token for @mesh-tech packages
12
+ pnpm install
13
+ mesh init app-tenant --tenant {{tenant}} # the doctor — checks auth, registry, tenant registration, repo shape
14
+ ```
15
+
16
+ ## Adding an app
17
+
18
+ ```bash
19
+ mesh create-app --tenant {{tenant}} --name my-app --primitives service
20
+ cd apps/my-app
21
+ pnpm install
22
+ mesh dev # run locally
23
+ mesh deploy up # deploy via the stack's deployer role
24
+ ```
@@ -0,0 +1,41 @@
1
+ # Dependencies
2
+ node_modules
3
+
4
+ # Build output
5
+ dist/
6
+ build/
7
+ .deploy/
8
+
9
+ # Local secret material — never commit (credential values live in Secrets Manager)
10
+ data.json
11
+ *-creds.json
12
+ creds*.json
13
+ secrets*.json
14
+
15
+ # Misc
16
+ .DS_Store
17
+ *.pem
18
+ .env
19
+ .env.*
20
+ !.env.example
21
+ .envrc
22
+
23
+ # Local files
24
+ *.local
25
+ *.local.*
26
+
27
+ # Debug
28
+ logs/
29
+ npm-debug.log*
30
+ pnpm-debug.log*
31
+
32
+ # TypeScript
33
+ *.tsbuildinfo
34
+
35
+ # Pulumi
36
+ .pulumi/
37
+ # Personal dev stacks (never commit) — keep the shared dev/prod stacks
38
+ Pulumi.dev-*.yaml
39
+
40
+ # Temporary
41
+ temp/
@@ -0,0 +1,7 @@
1
+ # CodeArtifact registry for @mesh-tech scoped packages.
2
+ #
3
+ # This file contains ONLY the registry URL — never the auth token.
4
+ # The auth token lives in ~/.npmrc, written by:
5
+ # mesh registry login
6
+ #
7
+ @mesh-tech:registry={{registryUrl}}
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "{{repoName}}",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "description": "{{tenantTitle}} applications deployed on the Mesh platform",
7
+ "packageManager": "pnpm@10.29.2",
8
+ "scripts": {
9
+ "mesh": "mesh",
10
+ "typecheck": "pnpm -r typecheck"
11
+ },
12
+ "devDependencies": {
13
+ "@mesh-tech/mesh-cli": "latest"
14
+ }
15
+ }
@@ -0,0 +1,3 @@
1
+ # Workspace packages — each app is an independent Pulumi project
2
+ packages:
3
+ - apps/*
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "resolveJsonModule": true,
11
+ "declaration": true,
12
+ "declarationMap": true,
13
+ "sourceMap": true,
14
+ "outDir": "./dist",
15
+ "rootDir": "."
16
+ },
17
+ "exclude": ["node_modules", "dist"]
18
+ }
@@ -0,0 +1,20 @@
1
+ # Agent guidance — {{name}}
2
+
3
+ - Invoke the CLI as `pnpm mesh <cmd>` or (cwd-independent) `pnpm exec mesh <cmd>` —
4
+ a `"mesh"` script + the bundled `@mesh-tech/*` dep make both work after
5
+ `pnpm install`. For a bare `mesh` on PATH, run once: `pnpm exec mesh install-shim`.
6
+ - Operations are `mesh` commands, never raw `aws`/`pulumi`/`kubectl`:
7
+ `mesh start` (local platform), `mesh dev --externals` (run services +
8
+ vendor mock), `mesh login`, `mesh deploy`, `mesh secrets set`.
9
+ - Local loop needs zero cloud access: `mesh start && mesh dev --externals`, then
10
+ `curl -X POST localhost:3000/payments/quote -d '{"amount":125.5}'`.
11
+ - Credentials are NEVER in code/env/config: declare fields on the
12
+ `ExternalService` (index.ts), read them at runtime with
13
+ `resolveCredentials("vendorpay")`. Real values: `mesh secrets set
14
+ external/vendorpay`; local values: seeded automatically by `mesh dev
15
+ --externals` from the `mesh.externals` declaration in package.json.
16
+ - Vendor HTTP calls go through `@mesh-tech/http-client` (`enhanceFetch`) for
17
+ correlation-id propagation and structured request logs.
18
+ - Pattern skills for the SDKs used here ship inside the `@mesh-tech/*`
19
+ packages (discoverable via TanStack Intent after `pnpm install`).
20
+ - This app's own skill lives at `skills/develop/SKILL.md`.