@mesh-tech/mesh-cli 0.33.0 → 0.34.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/README.md +3 -2
- package/dist/bin/mesh.js +27 -16
- package/dist/bin/mesh.js.map +3 -3
- package/dist/build-info.json +2 -2
- package/dist/src/commands/dev.js +2 -1
- package/dist/src/commands/init/platform-setup.js +3 -3
- package/dist/src/commands/init.js +2 -2
- package/dist/src/commands/local/helpers.js +2 -1
- package/dist/src/commands/secrets/migrate-config.js +4 -11
- package/dist/src/commands/secrets/set.js +2 -6
- package/dist/src/commands/temporal.js +8 -0
- package/dist/src/commands/temporal.js.map +2 -2
- package/dist/src/utils/aws-errors.d.ts +1 -0
- package/dist/src/utils/aws-errors.js +8 -0
- package/fragments/base/index.ts.hbs +4 -0
- package/package.json +2 -2
- package/skills/core/SKILL.md +9 -6
- package/templates/api-auth/README.md.hbs +6 -1
- package/templates/api-auth/index.ts.hbs +7 -0
- package/templates/platform-repo/README.md.hbs +3 -2
- package/templates/platform-repo/core/Pulumi.{{tenant}}-{{env}}.yaml.hbs +22 -3
package/README.md
CHANGED
|
@@ -92,8 +92,9 @@ It writes a tenant **platform** repo (the core + platform Pulumi layers on
|
|
|
92
92
|
`@mesh-tech/infra-components`) that deploys with `mesh deploy` unmodified, asks
|
|
93
93
|
for the per-install values, offers to create the Pulumi state bucket, and prints
|
|
94
94
|
the deploy sequence — including the one manual step in the middle: **delegating
|
|
95
|
-
the NS records** of the new public zone
|
|
96
|
-
ACM certificate
|
|
95
|
+
the NS records** of the new public zone. The deploy stops at the mesh-gateway
|
|
96
|
+
Ingress until ACM issues the wildcard certificate, which it does on its own once
|
|
97
|
+
that delegation resolves.
|
|
97
98
|
|
|
98
99
|
The platform layer builds service images with Docker by default, so it needs a
|
|
99
100
|
working Docker daemon; the core layer does not. On a machine without Docker (a
|
package/dist/bin/mesh.js
CHANGED
|
@@ -1110,6 +1110,17 @@ var init_seed = __esm({
|
|
|
1110
1110
|
}
|
|
1111
1111
|
});
|
|
1112
1112
|
|
|
1113
|
+
// libs/mesh-cli/src/utils/aws-errors.ts
|
|
1114
|
+
function isAwsErrorCode(err, code) {
|
|
1115
|
+
const e = err;
|
|
1116
|
+
return e?.name === code || e?.__type === code || e?.Code === code || e?.code === code || typeof e?.message === "string" && e.message.includes(code);
|
|
1117
|
+
}
|
|
1118
|
+
var init_aws_errors = __esm({
|
|
1119
|
+
"libs/mesh-cli/src/utils/aws-errors.ts"() {
|
|
1120
|
+
"use strict";
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1113
1124
|
// libs/mesh-cli/src/commands/local/helpers.ts
|
|
1114
1125
|
import * as net from "net";
|
|
1115
1126
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
@@ -1120,7 +1131,7 @@ async function upsertLocalSecret(secretId, value, client) {
|
|
|
1120
1131
|
try {
|
|
1121
1132
|
await sm.send(new CreateSecretCommand4({ Name: secretId, SecretString: secretString }));
|
|
1122
1133
|
} catch (err) {
|
|
1123
|
-
if (err
|
|
1134
|
+
if (isAwsErrorCode(err, "ResourceExistsException")) {
|
|
1124
1135
|
await sm.send(new PutSecretValueCommand4({ SecretId: secretId, SecretString: secretString }));
|
|
1125
1136
|
} else {
|
|
1126
1137
|
throw err;
|
|
@@ -1202,6 +1213,7 @@ var init_helpers = __esm({
|
|
|
1202
1213
|
"libs/mesh-cli/src/commands/local/helpers.ts"() {
|
|
1203
1214
|
"use strict";
|
|
1204
1215
|
init_seed();
|
|
1216
|
+
init_aws_errors();
|
|
1205
1217
|
defaultPortConflictIo = {
|
|
1206
1218
|
dockerPs: () => {
|
|
1207
1219
|
try {
|
|
@@ -10442,7 +10454,9 @@ function registerDevCommand(program2) {
|
|
|
10442
10454
|
{ remediation: { command: `docker compose -f ${decl.compose} up # debug it directly` } }
|
|
10443
10455
|
);
|
|
10444
10456
|
}
|
|
10445
|
-
logWarn(
|
|
10457
|
+
logWarn(
|
|
10458
|
+
`External '${name}' credential seeding failed: ${err instanceof Error ? err.message : err} \u2014 the app will resolve whatever was seeded previously, which may point at a stale port.`
|
|
10459
|
+
);
|
|
10446
10460
|
}
|
|
10447
10461
|
}
|
|
10448
10462
|
if (dockerRunner) {
|
|
@@ -17521,7 +17535,7 @@ function validateDomain(value) {
|
|
|
17521
17535
|
return "a public domain you control, e.g. q2poc.pub";
|
|
17522
17536
|
}
|
|
17523
17537
|
if (/(^|\.)(example\.(com|org|net)|invalid|localhost|test)$/.test(domain)) {
|
|
17524
|
-
return `${domain} is a placeholder \u2014
|
|
17538
|
+
return `${domain} is a placeholder \u2014 its ACM certificate can never validate, because nobody can delegate that zone to you. Use a domain you control.`;
|
|
17525
17539
|
}
|
|
17526
17540
|
return true;
|
|
17527
17541
|
}
|
|
@@ -17633,7 +17647,7 @@ function renderPlatformNextSteps(setup, opts = {}) {
|
|
|
17633
17647
|
`aws sso login --profile ${setup.profile} # if this profile is SSO`,
|
|
17634
17648
|
exportCredentialsCommand(setup.profile),
|
|
17635
17649
|
`cd core && mesh deploy up # the VPC, EKS, RDS and the public zone ${setup.env}.${setup.domain}`,
|
|
17636
|
-
`# \u2192 then delegate the NS records of ${setup.env}.${setup.domain} from ${setup.domain}; the deploy
|
|
17650
|
+
`# \u2192 then delegate the NS records of ${setup.env}.${setup.domain} from ${setup.domain} at your registrar; the deploy stops at the mesh-gateway Ingress until ACM issues the certificate, then continues`,
|
|
17637
17651
|
"cd ../platform && mesh deploy up # Temporal, Zitadel, the Hub (needs Docker \u2014 it builds service images)",
|
|
17638
17652
|
`mesh login ${setup.tenant}.${setup.env} # your platform sign-in, once it is up`,
|
|
17639
17653
|
"",
|
|
@@ -17675,7 +17689,7 @@ var init_platform_setup = __esm({
|
|
|
17675
17689
|
region: "us-east-2",
|
|
17676
17690
|
profile: "default"
|
|
17677
17691
|
};
|
|
17678
|
-
DOMAIN_REQUIRED_MESSAGE = "--domain is required: the core stack creates the public Route 53 zone <env>.<domain>, and a placeholder domain scaffolds a zone
|
|
17692
|
+
DOMAIN_REQUIRED_MESSAGE = "--domain is required: the core stack creates the public Route 53 zone <env>.<domain>, and a placeholder domain scaffolds a zone whose certificate can never validate, so ingress never serves HTTPS.";
|
|
17679
17693
|
realStateBucketDeps = {
|
|
17680
17694
|
headBucket(setup) {
|
|
17681
17695
|
try {
|
|
@@ -19182,7 +19196,7 @@ function registerInitCommands(program2) {
|
|
|
19182
19196
|
).option("--tenant <name>", "app tenant this repo belongs to (prompted when omitted on a TTY)").option("--local", "local only \u2014 mesh start / mesh dev, no deployed platform (the default)").option("--platform <env>", "a deployed platform's environment; signs in to `<tenant>.<env>`").option(
|
|
19183
19197
|
"--new-platform [env]",
|
|
19184
19198
|
`nothing deployed yet \u2014 scaffold a tenant platform repo for \`<tenant>.<env>\` (default env: ${PLATFORM_SETUP_DEFAULTS.env}) and print its deploy sequence`
|
|
19185
|
-
).option("--region <region>", `--new-platform: AWS region (default: ${PLATFORM_SETUP_DEFAULTS.region})`).option("--domain <domain>", "--new-platform: base public domain you control; the core stack creates the zone {env}.{domain}. No default \u2014 a placeholder scaffolds a zone that can never validate").option("--state-bucket <bucket>", "--new-platform: Pulumi state S3 bucket (default: {tenant}-mesh-platform-pulumi-state)").option("--create-state-bucket", "--new-platform: create the state bucket (versioned) if it does not exist").option("--no-create-state-bucket", "--new-platform: never create the state bucket; print the aws command instead").option("--dir <path>", "--new-platform: where to scaffold the platform repo (default: ./{tenant}-mesh-platform)").option("--device", "device-code sign-in for the registry and platform steps (headless / SSH)").option("--profile <aws-profile>", "AWS profile this machine uses: read the registry without the broker (deployers only), and the profile a --new-platform stack config references").option("--skip-repo", "do not bootstrap, check or record anything in the current repo", false).option("--yes", "accept every default and never prompt", false).option("--json", "one JSON document on stdout ({tenant, mode, steps, next}); human output on stderr", false).action(
|
|
19199
|
+
).option("--region <region>", `--new-platform: AWS region (default: ${PLATFORM_SETUP_DEFAULTS.region})`).option("--domain <domain>", "--new-platform: base public domain you control; the core stack creates the zone {env}.{domain} and stops at the mesh-gateway Ingress until you delegate its NS records. No default \u2014 a placeholder scaffolds a zone that can never validate").option("--state-bucket <bucket>", "--new-platform: Pulumi state S3 bucket (default: {tenant}-mesh-platform-pulumi-state)").option("--create-state-bucket", "--new-platform: create the state bucket (versioned) if it does not exist").option("--no-create-state-bucket", "--new-platform: never create the state bucket; print the aws command instead").option("--dir <path>", "--new-platform: where to scaffold the platform repo (default: ./{tenant}-mesh-platform)").option("--device", "device-code sign-in for the registry and platform steps (headless / SSH)").option("--profile <aws-profile>", "AWS profile this machine uses: read the registry without the broker (deployers only), and the profile a --new-platform stack config references").option("--skip-repo", "do not bootstrap, check or record anything in the current repo", false).option("--yes", "accept every default and never prompt", false).option("--json", "one JSON document on stdout ({tenant, mode, steps, next}); human output on stderr", false).action(
|
|
19186
19200
|
async (opts) => {
|
|
19187
19201
|
const { runInitWizard: runInitWizard2 } = await Promise.resolve().then(() => (init_wizard(), wizard_exports));
|
|
19188
19202
|
const code = await runInitWizard2(opts);
|
|
@@ -19193,7 +19207,7 @@ function registerInitCommands(program2) {
|
|
|
19193
19207
|
"Scaffold a tenant PLATFORM repo (core + platform Pulumi layers on @mesh-tech/infra-components) that deploys with `mesh deploy` unmodified \u2014 the proven mesh-sandbox shape, annotated. On a terminal it ASKS for the values that differ per install (env, region, domain, state bucket, AWS profile), each pre-filled with its default; every answer is also a flag."
|
|
19194
19208
|
).option("--env <env>", `environment the first stack targets (default: ${PLATFORM_SETUP_DEFAULTS.env})`).option("--region <region>", `AWS region (default: ${PLATFORM_SETUP_DEFAULTS.region})`).option(
|
|
19195
19209
|
"--domain <domain>",
|
|
19196
|
-
"base public domain you control \u2014 the core stack creates the Route 53 zone {env}.{domain}
|
|
19210
|
+
"base public domain you control \u2014 the core stack creates the Route 53 zone {env}.{domain}, whose NS records you then delegate at your registrar; the deploy stops at the mesh-gateway Ingress until that lets ACM issue the certificate. Required: it has no default, because a placeholder scaffolds a zone nobody can delegate to you"
|
|
19197
19211
|
).option("--profile <profile>", `AWS profile the stack config references (default: ${PLATFORM_SETUP_DEFAULTS.profile})`).option("--state-bucket <bucket>", "Pulumi state S3 bucket (default: {tenant}-mesh-platform-pulumi-state)").option("--create-state-bucket", "create the state bucket (versioned) if it does not exist \u2014 prompted on a terminal").option("--no-create-state-bucket", "never create the state bucket; print the aws command instead").option("--dir <path>", "target directory (default: ./{tenant}-mesh-platform)").option("--yes", "accept every default and never prompt", false).action(
|
|
19198
19212
|
async (tenant, opts) => {
|
|
19199
19213
|
if (!/^[a-z][a-z0-9-]*$/.test(tenant)) {
|
|
@@ -20676,8 +20690,7 @@ Usage: mesh secrets set external/<name>`);
|
|
|
20676
20690
|
console.error("");
|
|
20677
20691
|
}
|
|
20678
20692
|
function isResourceNotFound(err) {
|
|
20679
|
-
|
|
20680
|
-
return e?.name === "ResourceNotFoundException" || e?.__type === "ResourceNotFoundException" || e?.Code === "ResourceNotFoundException" || e?.code === "ResourceNotFoundException" || typeof e?.message === "string" && e.message.includes("ResourceNotFoundException");
|
|
20693
|
+
return isAwsErrorCode(err, "ResourceNotFoundException");
|
|
20681
20694
|
}
|
|
20682
20695
|
function deepMerge(target, source) {
|
|
20683
20696
|
const result = { ...target };
|
|
@@ -20813,6 +20826,7 @@ var init_set = __esm({
|
|
|
20813
20826
|
init_context2();
|
|
20814
20827
|
init_pulumi();
|
|
20815
20828
|
init_aws_auth();
|
|
20829
|
+
init_aws_errors();
|
|
20816
20830
|
}
|
|
20817
20831
|
});
|
|
20818
20832
|
|
|
@@ -21041,16 +21055,12 @@ function extractNonSecretFields2(fields, values) {
|
|
|
21041
21055
|
}
|
|
21042
21056
|
return result;
|
|
21043
21057
|
}
|
|
21044
|
-
function isResourceNotFound2(err) {
|
|
21045
|
-
const e = err;
|
|
21046
|
-
return e?.name === "ResourceNotFoundException" || e?.__type === "ResourceNotFoundException" || e?.Code === "ResourceNotFoundException" || e?.code === "ResourceNotFoundException" || typeof e?.message === "string" && e.message.includes("ResourceNotFoundException");
|
|
21047
|
-
}
|
|
21048
21058
|
async function readSecret(client, secretId) {
|
|
21049
21059
|
try {
|
|
21050
21060
|
const res = await client.send(new GetSecretValueCommand8({ SecretId: secretId }));
|
|
21051
21061
|
return res.SecretString ? JSON.parse(res.SecretString) : null;
|
|
21052
21062
|
} catch (err) {
|
|
21053
|
-
if (
|
|
21063
|
+
if (isAwsErrorCode(err, "ResourceNotFoundException")) return null;
|
|
21054
21064
|
throw err;
|
|
21055
21065
|
}
|
|
21056
21066
|
}
|
|
@@ -21059,7 +21069,7 @@ async function writeSecret2(client, secretId, values, description) {
|
|
|
21059
21069
|
try {
|
|
21060
21070
|
await client.send(new PutSecretValueCommand3({ SecretId: secretId, SecretString: secretString }));
|
|
21061
21071
|
} catch (err) {
|
|
21062
|
-
if (
|
|
21072
|
+
if (isAwsErrorCode(err, "ResourceNotFoundException")) {
|
|
21063
21073
|
await client.send(new CreateSecretCommand3({
|
|
21064
21074
|
Name: secretId,
|
|
21065
21075
|
Description: description,
|
|
@@ -21076,7 +21086,7 @@ async function secretExists(client, secretId) {
|
|
|
21076
21086
|
await client.send(new GetSecretValueCommand8({ SecretId: secretId }));
|
|
21077
21087
|
return true;
|
|
21078
21088
|
} catch (err) {
|
|
21079
|
-
if (
|
|
21089
|
+
if (isAwsErrorCode(err, "ResourceNotFoundException")) return false;
|
|
21080
21090
|
throw err;
|
|
21081
21091
|
}
|
|
21082
21092
|
}
|
|
@@ -21191,6 +21201,7 @@ var init_migrate_config = __esm({
|
|
|
21191
21201
|
"use strict";
|
|
21192
21202
|
init_log();
|
|
21193
21203
|
init_context2();
|
|
21204
|
+
init_aws_errors();
|
|
21194
21205
|
}
|
|
21195
21206
|
});
|
|
21196
21207
|
|