@mesh-tech/mesh-cli 0.1.1 → 0.12.1
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.
- package/assets/intent/agents-fence.md +10 -0
- package/assets/intent/intent-claude-gate.mjs +255 -0
- package/assets/log-shipper.mjs +94 -0
- package/bin/mesh.mjs +80 -0
- package/dist/bin/mesh.d.ts +7 -9
- package/dist/bin/mesh.d.ts.map +1 -1
- package/dist/bin/mesh.js +20878 -37
- package/dist/bin/mesh.js.map +7 -1
- package/dist/build-info.json +4 -0
- package/dist/src/commands/agent-api-client.d.ts +79 -0
- package/dist/src/commands/agent-api-client.d.ts.map +1 -0
- package/dist/src/commands/agent-api-client.js +170 -0
- package/dist/src/commands/agent-api-client.js.map +1 -0
- package/dist/src/commands/artifacts.d.ts +13 -0
- package/dist/src/commands/artifacts.d.ts.map +1 -0
- package/dist/src/commands/artifacts.js +140 -0
- package/dist/src/commands/artifacts.js.map +1 -0
- package/dist/src/commands/cluster.d.ts +45 -0
- package/dist/src/commands/cluster.d.ts.map +1 -0
- package/dist/src/commands/cluster.js +259 -0
- package/dist/src/commands/cluster.js.map +1 -0
- package/dist/src/commands/conversations.d.ts +61 -0
- package/dist/src/commands/conversations.d.ts.map +1 -0
- package/dist/src/commands/conversations.js +239 -0
- package/dist/src/commands/conversations.js.map +1 -0
- package/dist/src/commands/create-app.d.ts +26 -3
- package/dist/src/commands/create-app.d.ts.map +1 -1
- package/dist/src/commands/create-app.js +465 -107
- package/dist/src/commands/create-app.js.map +1 -1
- package/dist/src/commands/deploy.d.ts +19 -0
- package/dist/src/commands/deploy.d.ts.map +1 -1
- package/dist/src/commands/deploy.js +83 -142
- package/dist/src/commands/deploy.js.map +1 -1
- package/dist/src/commands/dev-doctor.d.ts +137 -0
- package/dist/src/commands/dev-doctor.d.ts.map +1 -0
- package/dist/src/commands/dev-doctor.js +671 -0
- package/dist/src/commands/dev-doctor.js.map +1 -0
- package/dist/src/commands/dev-launch.d.ts +59 -0
- package/dist/src/commands/dev-launch.d.ts.map +1 -0
- package/dist/src/commands/dev-launch.js +118 -0
- package/dist/src/commands/dev-launch.js.map +1 -0
- package/dist/src/commands/dev-token-server.d.ts +32 -0
- package/dist/src/commands/dev-token-server.d.ts.map +1 -0
- package/dist/src/commands/dev-token-server.js +68 -0
- package/dist/src/commands/dev-token-server.js.map +1 -0
- package/dist/src/commands/dev.d.ts +289 -2
- package/dist/src/commands/dev.d.ts.map +1 -1
- package/dist/src/commands/dev.js +2501 -574
- package/dist/src/commands/dev.js.map +1 -1
- package/dist/src/commands/docs.d.ts +3 -0
- package/dist/src/commands/docs.d.ts.map +1 -0
- package/dist/src/commands/docs.js +262 -0
- package/dist/src/commands/docs.js.map +1 -0
- package/dist/src/commands/hub/index.d.ts +99 -0
- package/dist/src/commands/hub/index.d.ts.map +1 -0
- package/dist/src/commands/hub/index.js +452 -0
- package/dist/src/commands/hub/index.js.map +1 -0
- package/dist/src/commands/init.d.ts +65 -0
- package/dist/src/commands/init.d.ts.map +1 -0
- package/dist/src/commands/init.js +370 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/install-shim.d.ts +28 -0
- package/dist/src/commands/install-shim.d.ts.map +1 -0
- package/dist/src/commands/install-shim.js +191 -0
- package/dist/src/commands/install-shim.js.map +1 -0
- package/dist/src/commands/local/auth-provision.d.ts +71 -0
- package/dist/src/commands/local/auth-provision.d.ts.map +1 -0
- package/dist/src/commands/local/auth-provision.js +286 -0
- package/dist/src/commands/local/auth-provision.js.map +1 -0
- package/dist/src/commands/local/dev-local.d.ts +97 -0
- package/dist/src/commands/local/dev-local.d.ts.map +1 -0
- package/dist/src/commands/local/dev-local.js +306 -0
- package/dist/src/commands/local/dev-local.js.map +1 -0
- package/dist/src/commands/local/docker-runner.d.ts +37 -0
- package/dist/src/commands/local/docker-runner.d.ts.map +1 -0
- package/dist/src/commands/local/docker-runner.js +104 -0
- package/dist/src/commands/local/docker-runner.js.map +1 -0
- package/dist/src/commands/local/helpers.d.ts +22 -0
- package/dist/src/commands/local/helpers.d.ts.map +1 -0
- package/dist/src/commands/local/helpers.js +46 -0
- package/dist/src/commands/local/helpers.js.map +1 -0
- package/dist/src/commands/local/hub-local.d.ts +51 -0
- package/dist/src/commands/local/hub-local.d.ts.map +1 -0
- package/dist/src/commands/local/hub-local.js +197 -0
- package/dist/src/commands/local/hub-local.js.map +1 -0
- package/dist/src/commands/local/index.d.ts +23 -0
- package/dist/src/commands/local/index.d.ts.map +1 -0
- package/dist/src/commands/local/index.js +386 -0
- package/dist/src/commands/local/index.js.map +1 -0
- package/dist/src/commands/local/mocks.d.ts +361 -0
- package/dist/src/commands/local/mocks.d.ts.map +1 -0
- package/dist/src/commands/local/mocks.js +756 -0
- package/dist/src/commands/local/mocks.js.map +1 -0
- package/dist/src/commands/local/seed-zitadel.d.ts +151 -0
- package/dist/src/commands/local/seed-zitadel.d.ts.map +1 -0
- package/dist/src/commands/local/seed-zitadel.js +408 -0
- package/dist/src/commands/local/seed-zitadel.js.map +1 -0
- package/dist/src/commands/local/seed.d.ts +106 -0
- package/dist/src/commands/local/seed.d.ts.map +1 -0
- package/dist/src/commands/local/seed.js +252 -0
- package/dist/src/commands/local/seed.js.map +1 -0
- package/dist/src/commands/local/stack.d.ts +173 -0
- package/dist/src/commands/local/stack.d.ts.map +1 -0
- package/dist/src/commands/local/stack.js +499 -0
- package/dist/src/commands/local/stack.js.map +1 -0
- package/dist/src/commands/login.d.ts +256 -12
- package/dist/src/commands/login.d.ts.map +1 -1
- package/dist/src/commands/login.js +978 -50
- package/dist/src/commands/login.js.map +1 -1
- package/dist/src/commands/peer-addressing.d.ts +51 -0
- package/dist/src/commands/peer-addressing.d.ts.map +1 -0
- package/dist/src/commands/peer-addressing.js +64 -0
- package/dist/src/commands/peer-addressing.js.map +1 -0
- package/dist/src/commands/port-ownership.d.ts +69 -0
- package/dist/src/commands/port-ownership.d.ts.map +1 -0
- package/dist/src/commands/port-ownership.js +161 -0
- package/dist/src/commands/port-ownership.js.map +1 -0
- package/dist/src/commands/registry-publish.d.ts +3 -0
- package/dist/src/commands/registry-publish.d.ts.map +1 -0
- package/dist/src/commands/registry-publish.js +161 -0
- package/dist/src/commands/registry-publish.js.map +1 -0
- package/dist/src/commands/registry.d.ts +146 -2
- package/dist/src/commands/registry.d.ts.map +1 -1
- package/dist/src/commands/registry.js +541 -85
- package/dist/src/commands/registry.js.map +1 -1
- package/dist/src/commands/secrets/index.d.ts.map +1 -1
- package/dist/src/commands/secrets/index.js +15 -1
- package/dist/src/commands/secrets/index.js.map +1 -1
- package/dist/src/commands/secrets/migrate-config.d.ts +24 -0
- package/dist/src/commands/secrets/migrate-config.d.ts.map +1 -0
- package/dist/src/commands/secrets/migrate-config.js +277 -0
- package/dist/src/commands/secrets/migrate-config.js.map +1 -0
- package/dist/src/commands/secrets/set.d.ts +1 -0
- package/dist/src/commands/secrets/set.d.ts.map +1 -1
- package/dist/src/commands/secrets/set.js +96 -2
- package/dist/src/commands/secrets/set.js.map +1 -1
- package/dist/src/commands/skills.d.ts +34 -0
- package/dist/src/commands/skills.d.ts.map +1 -0
- package/dist/src/commands/skills.js +207 -0
- package/dist/src/commands/skills.js.map +1 -0
- package/dist/src/commands/stack.d.ts.map +1 -1
- package/dist/src/commands/stack.js +361 -23
- package/dist/src/commands/stack.js.map +1 -1
- package/dist/src/commands/temporal.d.ts +15 -0
- package/dist/src/commands/temporal.d.ts.map +1 -0
- package/dist/src/commands/temporal.js +781 -0
- package/dist/src/commands/temporal.js.map +1 -0
- package/dist/src/commands/tenant.d.ts +56 -0
- package/dist/src/commands/tenant.d.ts.map +1 -0
- package/dist/src/commands/tenant.js +233 -0
- package/dist/src/commands/tenant.js.map +1 -0
- package/dist/src/commands/tunnel/index.d.ts +49 -3
- package/dist/src/commands/tunnel/index.d.ts.map +1 -1
- package/dist/src/commands/tunnel/index.js +331 -8
- package/dist/src/commands/tunnel/index.js.map +1 -1
- package/dist/src/commands/vcs/clone.d.ts +3 -0
- package/dist/src/commands/vcs/clone.d.ts.map +1 -0
- package/dist/src/commands/vcs/clone.js +20 -0
- package/dist/src/commands/vcs/clone.js.map +1 -0
- package/dist/src/commands/vcs/common.d.ts +21 -0
- package/dist/src/commands/vcs/common.d.ts.map +1 -0
- package/dist/src/commands/vcs/common.js +62 -0
- package/dist/src/commands/vcs/common.js.map +1 -0
- package/dist/src/commands/vcs/drafts.d.ts +13 -0
- package/dist/src/commands/vcs/drafts.d.ts.map +1 -0
- package/dist/src/commands/vcs/drafts.js +45 -0
- package/dist/src/commands/vcs/drafts.js.map +1 -0
- package/dist/src/commands/vcs/get.d.ts +8 -0
- package/dist/src/commands/vcs/get.d.ts.map +1 -0
- package/dist/src/commands/vcs/get.js +61 -0
- package/dist/src/commands/vcs/get.js.map +1 -0
- package/dist/src/commands/vcs/index.d.ts +3 -0
- package/dist/src/commands/vcs/index.d.ts.map +1 -0
- package/dist/src/commands/vcs/index.js +58 -0
- package/dist/src/commands/vcs/index.js.map +1 -0
- package/dist/src/commands/vcs/propose.d.ts +23 -0
- package/dist/src/commands/vcs/propose.d.ts.map +1 -0
- package/dist/src/commands/vcs/propose.js +94 -0
- package/dist/src/commands/vcs/propose.js.map +1 -0
- package/dist/src/commands/vcs/review.d.ts +15 -0
- package/dist/src/commands/vcs/review.d.ts.map +1 -0
- package/dist/src/commands/vcs/review.js +35 -0
- package/dist/src/commands/vcs/review.js.map +1 -0
- package/dist/src/commands/vcs-enrich.d.ts +15 -0
- package/dist/src/commands/vcs-enrich.d.ts.map +1 -0
- package/dist/src/commands/vcs-enrich.js +28 -0
- package/dist/src/commands/vcs-enrich.js.map +1 -0
- package/dist/src/commands/vpn/index.d.ts +24 -0
- package/dist/src/commands/vpn/index.d.ts.map +1 -0
- package/dist/src/commands/vpn/index.js +543 -0
- package/dist/src/commands/vpn/index.js.map +1 -0
- package/dist/src/commands/vpn/tunnel.d.ts +11 -0
- package/dist/src/commands/vpn/tunnel.d.ts.map +1 -0
- package/dist/src/commands/vpn/tunnel.js +188 -0
- package/dist/src/commands/vpn/tunnel.js.map +1 -0
- package/dist/src/commands/workflow.d.ts +24 -0
- package/dist/src/commands/workflow.d.ts.map +1 -0
- package/dist/src/commands/workflow.js +577 -0
- package/dist/src/commands/workflow.js.map +1 -0
- package/dist/src/docs/assemble.d.ts +217 -0
- package/dist/src/docs/assemble.d.ts.map +1 -0
- package/dist/src/docs/assemble.js +739 -0
- package/dist/src/docs/assemble.js.map +1 -0
- package/dist/src/docs/cli-reference.d.ts +93 -0
- package/dist/src/docs/cli-reference.d.ts.map +1 -0
- package/dist/src/docs/cli-reference.js +256 -0
- package/dist/src/docs/cli-reference.js.map +1 -0
- package/dist/src/docs/discover.d.ts +60 -0
- package/dist/src/docs/discover.d.ts.map +1 -0
- package/dist/src/docs/discover.js +233 -0
- package/dist/src/docs/discover.js.map +1 -0
- package/dist/src/docs/portal.d.ts +79 -0
- package/dist/src/docs/portal.d.ts.map +1 -0
- package/dist/src/docs/portal.js +242 -0
- package/dist/src/docs/portal.js.map +1 -0
- package/dist/src/docs/registry-docs.d.ts +43 -0
- package/dist/src/docs/registry-docs.d.ts.map +1 -0
- package/dist/src/docs/registry-docs.js +138 -0
- package/dist/src/docs/registry-docs.js.map +1 -0
- package/dist/src/docs/schema.d.ts +48 -0
- package/dist/src/docs/schema.d.ts.map +1 -0
- package/dist/src/docs/schema.js +96 -0
- package/dist/src/docs/schema.js.map +1 -0
- package/dist/src/docs/serve.d.ts +27 -0
- package/dist/src/docs/serve.d.ts.map +1 -0
- package/dist/src/docs/serve.js +102 -0
- package/dist/src/docs/serve.js.map +1 -0
- package/dist/src/docs/start.d.ts +80 -0
- package/dist/src/docs/start.d.ts.map +1 -0
- package/dist/src/docs/start.js +313 -0
- package/dist/src/docs/start.js.map +1 -0
- package/dist/src/eval/agent-eval.d.mts +14 -0
- package/dist/src/eval/agent-eval.d.mts.map +1 -0
- package/dist/src/eval/agent-eval.mjs +273 -0
- package/dist/src/eval/agent-eval.mjs.map +1 -0
- package/dist/src/index.js +624 -7
- package/dist/src/index.js.map +7 -1
- package/dist/src/program.d.ts +26 -0
- package/dist/src/program.d.ts.map +1 -0
- package/dist/src/program.js +76 -0
- package/dist/src/program.js.map +1 -0
- package/dist/src/utils/auth-preflight.d.ts +159 -0
- package/dist/src/utils/auth-preflight.d.ts.map +1 -0
- package/dist/src/utils/auth-preflight.js +298 -0
- package/dist/src/utils/auth-preflight.js.map +1 -0
- package/dist/src/utils/aws-auth.d.ts +181 -0
- package/dist/src/utils/aws-auth.d.ts.map +1 -0
- package/dist/src/utils/aws-auth.js +527 -0
- package/dist/src/utils/aws-auth.js.map +1 -0
- package/dist/src/utils/bastion.d.ts +1 -1
- package/dist/src/utils/bastion.d.ts.map +1 -1
- package/dist/src/utils/bastion.js +29 -8
- package/dist/src/utils/bastion.js.map +1 -1
- package/dist/src/utils/build-info.d.ts +33 -0
- package/dist/src/utils/build-info.d.ts.map +1 -0
- package/dist/src/utils/build-info.js +102 -0
- package/dist/src/utils/build-info.js.map +1 -0
- package/dist/src/utils/capture-history.d.ts +62 -0
- package/dist/src/utils/capture-history.d.ts.map +1 -0
- package/dist/src/utils/capture-history.js +94 -0
- package/dist/src/utils/capture-history.js.map +1 -0
- package/dist/src/utils/deploy-preflight.d.ts +52 -0
- package/dist/src/utils/deploy-preflight.d.ts.map +1 -0
- package/dist/src/utils/deploy-preflight.js +183 -0
- package/dist/src/utils/deploy-preflight.js.map +1 -0
- package/dist/src/utils/errors.d.ts +75 -0
- package/dist/src/utils/errors.d.ts.map +1 -0
- package/dist/src/utils/errors.js +106 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/first-party-contexts.d.ts +40 -0
- package/dist/src/utils/first-party-contexts.d.ts.map +1 -0
- package/dist/src/utils/first-party-contexts.js +53 -0
- package/dist/src/utils/first-party-contexts.js.map +1 -0
- package/dist/src/utils/index.d.ts +2 -0
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +2 -0
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/kubeconfig.d.ts +62 -0
- package/dist/src/utils/kubeconfig.d.ts.map +1 -0
- package/dist/src/utils/kubeconfig.js +118 -0
- package/dist/src/utils/kubeconfig.js.map +1 -0
- package/dist/src/utils/log.d.ts +27 -1
- package/dist/src/utils/log.d.ts.map +1 -1
- package/dist/src/utils/log.js +59 -5
- package/dist/src/utils/log.js.map +1 -1
- package/dist/src/utils/pid.d.ts +47 -0
- package/dist/src/utils/pid.d.ts.map +1 -0
- package/dist/src/utils/pid.js +83 -0
- package/dist/src/utils/pid.js.map +1 -0
- package/dist/src/utils/pulumi-run.d.ts +23 -0
- package/dist/src/utils/pulumi-run.d.ts.map +1 -0
- package/dist/src/utils/pulumi-run.js +112 -0
- package/dist/src/utils/pulumi-run.js.map +1 -0
- package/dist/src/utils/pulumi.d.ts +15 -0
- package/dist/src/utils/pulumi.d.ts.map +1 -1
- package/dist/src/utils/pulumi.js +35 -0
- package/dist/src/utils/pulumi.js.map +1 -1
- package/dist/src/utils/reachability.d.ts +29 -0
- package/dist/src/utils/reachability.d.ts.map +1 -0
- package/dist/src/utils/reachability.js +81 -0
- package/dist/src/utils/reachability.js.map +1 -0
- package/dist/src/utils/recover-conversation.d.ts +154 -0
- package/dist/src/utils/recover-conversation.d.ts.map +1 -0
- package/dist/src/utils/recover-conversation.js +314 -0
- package/dist/src/utils/recover-conversation.js.map +1 -0
- package/dist/src/utils/registry-broker.d.ts +148 -0
- package/dist/src/utils/registry-broker.d.ts.map +1 -0
- package/dist/src/utils/registry-broker.js +180 -0
- package/dist/src/utils/registry-broker.js.map +1 -0
- package/dist/src/utils/socks-forward.d.ts +40 -0
- package/dist/src/utils/socks-forward.d.ts.map +1 -0
- package/dist/src/utils/socks-forward.js +97 -0
- package/dist/src/utils/socks-forward.js.map +1 -0
- package/dist/src/utils/stack-flag.d.ts +23 -0
- package/dist/src/utils/stack-flag.d.ts.map +1 -0
- package/dist/src/utils/stack-flag.js +41 -0
- package/dist/src/utils/stack-flag.js.map +1 -0
- package/dist/src/utils/tailscale-targets.d.ts +52 -0
- package/dist/src/utils/tailscale-targets.d.ts.map +1 -0
- package/dist/src/utils/tailscale-targets.js +93 -0
- package/dist/src/utils/tailscale-targets.js.map +1 -0
- package/dist/src/utils/tailscale.d.ts +277 -0
- package/dist/src/utils/tailscale.d.ts.map +1 -0
- package/dist/src/utils/tailscale.js +1007 -0
- package/dist/src/utils/tailscale.js.map +1 -0
- package/dist/src/utils/temporal-auth.d.ts +43 -0
- package/dist/src/utils/temporal-auth.d.ts.map +1 -0
- package/dist/src/utils/temporal-auth.js +176 -0
- package/dist/src/utils/temporal-auth.js.map +1 -0
- package/dist/src/utils/temporal-codec.d.ts +101 -0
- package/dist/src/utils/temporal-codec.d.ts.map +1 -0
- package/dist/src/utils/temporal-codec.js +319 -0
- package/dist/src/utils/temporal-codec.js.map +1 -0
- package/dist/src/utils/tunnel-ownership.d.ts +130 -0
- package/dist/src/utils/tunnel-ownership.d.ts.map +1 -0
- package/dist/src/utils/tunnel-ownership.js +274 -0
- package/dist/src/utils/tunnel-ownership.js.map +1 -0
- package/dist/src/utils/vpn-join.d.ts +32 -0
- package/dist/src/utils/vpn-join.d.ts.map +1 -0
- package/dist/src/utils/vpn-join.js +62 -0
- package/dist/src/utils/vpn-join.js.map +1 -0
- package/dist/src/utils/vpn.d.ts +62 -0
- package/dist/src/utils/vpn.d.ts.map +1 -0
- package/dist/src/utils/vpn.js +183 -0
- package/dist/src/utils/vpn.js.map +1 -0
- package/dist/src/utils/workflow-fingerprint.d.ts +49 -0
- package/dist/src/utils/workflow-fingerprint.d.ts.map +1 -0
- package/dist/src/utils/workflow-fingerprint.js +135 -0
- package/dist/src/utils/workflow-fingerprint.js.map +1 -0
- package/dist/src/utils/worktree-identity.d.ts +86 -0
- package/dist/src/utils/worktree-identity.d.ts.map +1 -0
- package/dist/src/utils/worktree-identity.js +164 -0
- package/dist/src/utils/worktree-identity.js.map +1 -0
- package/fragments/agents/AGENTS.md.hbs +92 -0
- package/fragments/agents/CLAUDE.md.hbs +8 -0
- package/fragments/base/Pulumi.dev.yaml.hbs +10 -0
- package/fragments/base/Pulumi.yaml.hbs +9 -0
- package/fragments/base/index.ts.hbs +107 -0
- package/fragments/base/package.json.hbs +22 -0
- package/{templates/api-web-db/api → fragments/base}/tsconfig.json +3 -4
- package/fragments/bucket/api/src/storage.ts.hbs +81 -0
- package/fragments/database/api/src/db.ts.hbs +23 -0
- package/fragments/database/prisma/schema.prisma.hbs +18 -0
- package/{templates/api-web-db → fragments/service}/api/.dockerignore +2 -0
- package/fragments/service/api/package.json.hbs +40 -0
- package/fragments/service/api/src/index.ts.hbs +58 -0
- package/{templates/api-web-db → fragments/service/api}/tsconfig.json +5 -3
- package/fragments/temporal/worker/.dockerignore +4 -0
- package/fragments/temporal/worker/Dockerfile +15 -0
- package/{templates/temporal-api-worker → fragments/temporal}/worker/package.json.hbs +3 -2
- package/fragments/temporal/worker/src/activities.ts.hbs +14 -0
- package/fragments/temporal/worker/src/worker.ts.hbs +27 -0
- package/fragments/temporal/worker/src/workflows.ts.hbs +24 -0
- package/fragments/temporal/worker/tsconfig.json +13 -0
- package/package.json +36 -22
- package/skills/core/SKILL.md +365 -0
- package/skills/pull-remote-agent-context/SKILL.md +194 -0
- package/stack/docker-compose.hub.yml +134 -0
- package/stack/docker-compose.yml +447 -0
- package/stack/hub/Dockerfile.api +18 -0
- package/stack/hub/Dockerfile.auth +10 -0
- package/stack/hub/Dockerfile.ui +10 -0
- package/stack/init/01-databases.sql +12 -0
- package/stack/observability/blackbox.yml +20 -0
- package/stack/observability/otel-collector.yaml +73 -0
- package/stack/observability/prometheus.yml +36 -0
- package/stack/observability/tempo.yaml +25 -0
- package/stack/temporal/local.yaml +44 -0
- package/templates/api-auth/AGENTS.md.hbs +16 -0
- package/templates/api-auth/Pulumi.dev.yaml.hbs +8 -0
- package/templates/api-auth/Pulumi.yaml.hbs +8 -0
- package/templates/api-auth/README.md.hbs +67 -0
- package/templates/api-auth/api/package.json.hbs +28 -0
- package/templates/api-auth/api/src/index.ts.hbs +96 -0
- package/templates/api-auth/api/src/schema.ts.hbs +35 -0
- package/templates/api-auth/api/src/seed-authz.ts.hbs +48 -0
- package/templates/api-auth/api/src/spicedb-http-provider.ts.hbs +89 -0
- package/templates/api-auth/index.ts.hbs +65 -0
- package/templates/api-auth/package.json.hbs +20 -0
- package/templates/api-auth/skills/develop/SKILL.md.hbs +32 -0
- package/templates/api-role-gating/AGENTS.md.hbs +20 -0
- package/templates/api-role-gating/Pulumi.dev.yaml.hbs +8 -0
- package/templates/api-role-gating/Pulumi.yaml.hbs +8 -0
- package/templates/api-role-gating/README.md.hbs +64 -0
- package/templates/api-role-gating/api/Dockerfile +17 -0
- package/templates/api-role-gating/api/package.json.hbs +28 -0
- package/templates/api-role-gating/api/src/authn.ts.hbs +29 -0
- package/templates/api-role-gating/api/src/authz.ts.hbs +12 -0
- package/templates/api-role-gating/api/src/main.ts.hbs +58 -0
- package/templates/api-role-gating/api/src/schema.ts.hbs +22 -0
- package/templates/api-role-gating/api/tsconfig.json +13 -0
- package/templates/api-role-gating/index.ts.hbs +107 -0
- package/templates/api-role-gating/package.json.hbs +21 -0
- package/templates/api-role-gating/skills/develop/SKILL.md.hbs +60 -0
- package/templates/api-role-gating/tsconfig.json +10 -0
- package/templates/apps-repo/README.md.hbs +24 -0
- package/templates/apps-repo/gitignore +41 -0
- package/templates/apps-repo/npmrc.hbs +7 -0
- package/templates/apps-repo/package.json.hbs +15 -0
- package/templates/apps-repo/pnpm-workspace.yaml +3 -0
- package/templates/apps-repo/tsconfig.json +18 -0
- package/templates/external-service/AGENTS.md.hbs +20 -0
- package/templates/external-service/Pulumi.dev.yaml.hbs +8 -0
- package/templates/external-service/Pulumi.yaml.hbs +8 -0
- package/templates/external-service/README.md.hbs +56 -0
- package/templates/external-service/api/Dockerfile +15 -0
- package/templates/external-service/api/package.json.hbs +25 -0
- package/templates/external-service/api/src/index.ts.hbs +81 -0
- package/templates/external-service/index.ts.hbs +82 -0
- package/templates/external-service/mocks/vendorpay/package.json.hbs +9 -0
- package/templates/external-service/mocks/vendorpay/server.mjs.hbs +61 -0
- package/templates/external-service/package.json.hbs +34 -0
- package/templates/external-service/skills/develop/SKILL.md.hbs +55 -0
- package/templates/external-service/tsconfig.json +10 -0
- package/templates/platform-repo/AGENTS.md.hbs +18 -0
- package/templates/platform-repo/README.md.hbs +38 -0
- package/templates/platform-repo/core/Pulumi.yaml.hbs +12 -0
- package/templates/platform-repo/core/Pulumi.{{tenant}}-{{env}}.yaml.hbs +57 -0
- package/templates/platform-repo/core/index.ts +62 -0
- package/templates/platform-repo/core/package.json.hbs +22 -0
- package/templates/platform-repo/core/tsconfig.json +8 -0
- package/templates/platform-repo/package.json.hbs +15 -0
- package/templates/platform-repo/platform/Pulumi.yaml.hbs +12 -0
- package/templates/platform-repo/platform/Pulumi.{{tenant}}-{{env}}.yaml.hbs +59 -0
- package/templates/platform-repo/platform/index.ts +95 -0
- package/templates/platform-repo/platform/package.json.hbs +26 -0
- package/templates/platform-repo/platform/tsconfig.json +8 -0
- package/templates/platform-repo/pnpm-workspace.yaml +3 -0
- package/templates/workflow/AGENTS.md.hbs +15 -0
- package/templates/workflow/Pulumi.dev.yaml.hbs +8 -0
- package/templates/workflow/Pulumi.yaml.hbs +8 -0
- package/templates/workflow/README.md.hbs +45 -0
- package/templates/workflow/api/.dockerignore +4 -0
- package/templates/workflow/api/Dockerfile +15 -0
- package/templates/{temporal-api-worker → workflow}/api/package.json.hbs +8 -6
- package/templates/workflow/api/src/index.ts.hbs +130 -0
- package/templates/workflow/api/tsconfig.json +14 -0
- package/templates/workflow/index.ts.hbs +67 -0
- package/templates/workflow/package.json.hbs +20 -0
- package/templates/workflow/skills/develop/SKILL.md.hbs +32 -0
- package/templates/workflow/tsconfig.json +10 -0
- package/templates/workflow/worker/.dockerignore +4 -0
- package/templates/workflow/worker/Dockerfile +13 -0
- package/templates/workflow/worker/package.json.hbs +25 -0
- package/templates/workflow/worker/src/worker.ts.hbs +24 -0
- package/templates/workflow/worker/tsconfig.json +14 -0
- package/dist/src/commands/devbox.d.ts +0 -22
- package/dist/src/commands/devbox.d.ts.map +0 -1
- package/dist/src/commands/devbox.js +0 -463
- package/dist/src/commands/devbox.js.map +0 -1
- package/templates/api-web-db/api/Dockerfile +0 -16
- package/templates/api-web-db/api/package.json.hbs +0 -21
- package/templates/api-web-db/api/src/index.ts.hbs +0 -123
- package/templates/api-web-db/package.json.hbs +0 -27
- package/templates/api-web-db/sst.config.ts.hbs +0 -151
- package/templates/api-web-db/web/.dockerignore +0 -3
- package/templates/api-web-db/web/Dockerfile +0 -17
- package/templates/api-web-db/web/app/lib/db.server.ts +0 -36
- package/templates/api-web-db/web/app/root.tsx +0 -29
- package/templates/api-web-db/web/app/routes/home.tsx.hbs +0 -114
- package/templates/api-web-db/web/app/routes.ts +0 -3
- package/templates/api-web-db/web/package.json.hbs +0 -30
- package/templates/api-web-db/web/prisma/schema.prisma +0 -25
- package/templates/api-web-db/web/prisma.config.ts +0 -18
- package/templates/api-web-db/web/react-router.config.ts +0 -5
- package/templates/api-web-db/web/tsconfig.json +0 -19
- package/templates/api-web-db/web/vite.config.ts +0 -9
- package/templates/temporal-api-worker/README.md.hbs +0 -133
- package/templates/temporal-api-worker/api/src/index.ts.hbs +0 -145
- package/templates/temporal-api-worker/package.json.hbs +0 -29
- package/templates/temporal-api-worker/sst.config.ts.hbs +0 -161
- package/templates/temporal-api-worker/worker/Dockerfile +0 -11
- package/templates/temporal-api-worker/worker/src/bundle-workflows.ts +0 -38
- package/templates/temporal-api-worker/worker/src/worker.ts.hbs +0 -93
- /package/templates/{temporal-api-worker → api-auth}/api/.dockerignore +0 -0
- /package/templates/{temporal-api-worker → api-auth}/api/Dockerfile +0 -0
- /package/templates/{temporal-api-worker → api-auth}/api/tsconfig.json +0 -0
- /package/templates/{temporal-api-worker → api-auth}/tsconfig.json +0 -0
- /package/templates/{temporal-api-worker/worker → api-role-gating/api}/.dockerignore +0 -0
- /package/templates/{temporal-api-worker/worker → external-service/api}/tsconfig.json +0 -0
- /package/templates/{temporal-api-worker → workflow}/api/src/encryption-codec.ts +0 -0
- /package/templates/{temporal-api-worker → workflow}/worker/src/activities.ts.hbs +0 -0
- /package/templates/{temporal-api-worker → workflow}/worker/src/encryption-codec.ts +0 -0
- /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,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,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,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,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`.
|