@timekast/factory 2.3.0 → 2.3.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.
@@ -1376,7 +1376,7 @@ const VAULT_PER_ENV_MINTED = ['AUTH_SECRET'];
1376
1376
  * Which keys each destination gets depends on the services the run includes: `neon` writes the
1377
1377
  * connection strings and the CI keys, `vercel` the runtime values, `backlog` its local creds.
1378
1378
  */
1379
- export function buildVaultPlan(projectName, services) {
1379
+ export function buildVaultPlan(projectName, services, target) {
1380
1380
  const keys = {};
1381
1381
  const references = {};
1382
1382
  const add = (loc, names, asRef = false) => {
@@ -1416,7 +1416,9 @@ export function buildVaultPlan(projectName, services) {
1416
1416
  if (services.includes('backlog')) {
1417
1417
  add(VAULT_LOCAL_ROOT, ['BACKLOG_API_KEY', 'BACKLOG_PROJECT_ID']);
1418
1418
  }
1419
- const railway = services.includes('railway');
1419
+ // The syncs follow the DESTINATION, not this run's steps: a run with `vault` but without the
1420
+ // `railway` step still deploys to Railway, and never gets the Vercel syncs.
1421
+ const railway = services.includes('railway') || target === 'railway';
1420
1422
  return {
1421
1423
  project: projectName,
1422
1424
  environments: VAULT_LAYOUT_ENVIRONMENTS.map((env) => env.slug),
@@ -5436,12 +5438,17 @@ function goLiveRetryHint(mailDomain) {
5436
5438
  const client = mailDomain.startsWith(prefix) ? mailDomain.slice(prefix.length) : '<tu dominio>';
5437
5439
  return `repite el go-live (\`factory provision --domain=${client}\`)`;
5438
5440
  }
5441
+ /** Whether the state records a kit domain in that Railway environment (created, or found by adopt). */
5442
+ function hasRailwayKitDomain(state, role) {
5443
+ const rw = state?.railway;
5444
+ return Boolean(rw?.customDomains?.[role] || rw?.adoptedDomains?.some((d) => d.role === role));
5445
+ }
5439
5446
  /**
5440
5447
  * Print the resolved client-domain operation tree for `--domain --dry-run`
5441
5448
  * (PROV-006 §8): the exact domain, the DNS route, whether the CNAME is created or
5442
5449
  * printed, the interim-retire intent, and the env updates — mutating NOTHING.
5443
5450
  */
5444
- function printClientDomainPlan(domain, interim, route, confirm, target, clientMail = false) {
5451
+ function printClientDomainPlan(domain, hosts, route, confirm, target, clientMail = false) {
5445
5452
  console.log(`\nPlan de \`--domain=${domain}\` (ruta DNS: ${route}):`);
5446
5453
  if (target === 'railway') {
5447
5454
  // RWAY-005: the CNAME's destination and the TXT are what Railway returns for the domain.
@@ -5466,8 +5473,11 @@ function printClientDomainPlan(domain, interim, route, confirm, target, clientMa
5466
5473
  }
5467
5474
  console.log(` … sondea GET /v9/projects/.../domains/${domain} hasta verified:true (o timeout)`);
5468
5475
  }
5469
- console.log(` ${confirm ? '-' : '? (requiere --confirm o prompt)'} retira el interino ${interim} ` +
5470
- `(el dev ${domain}-dev se conserva)`);
5476
+ const { interim, dev } = hosts;
5477
+ console.log(interim
5478
+ ? ` ${confirm ? '-' : '? (requiere --confirm o prompt)'} retira el interino ${interim}` +
5479
+ (dev ? ` (el dev ${dev} se conserva)` : '')
5480
+ : ' · sin dominio interino registrado: no hay nada que retirar');
5471
5481
  console.log(clientMail
5472
5482
  ? ` ↻ EMAIL_FROM=noreply@${mailDomainFor(domain)} · NEXT_PUBLIC_APP_URL=https://${domain}`
5473
5483
  : ` ↻ NEXT_PUBLIC_APP_URL=https://${domain}`);
@@ -8923,7 +8933,7 @@ export async function runProvision(flags, deps = {}) {
8923
8933
  };
8924
8934
  }
8925
8935
  if (flags.services.includes('vault')) {
8926
- result.vault = buildVaultPlan(projectName, flags.services);
8936
+ result.vault = buildVaultPlan(projectName, flags.services, target);
8927
8937
  }
8928
8938
  if (vaultDecision.skipped) {
8929
8939
  result.vaultSkipped = vaultDecision.skipped;
@@ -8956,8 +8966,12 @@ export async function runProvision(flags, deps = {}) {
8956
8966
  if (hasDomain) {
8957
8967
  // Same rule as the real retire (DOM-001): the plan must print the interim the
8958
8968
  // project ACTUALLY has, not one re-derived in the current org zone.
8959
- const interim = existingProvisionDomains(projectName, state?.dns).prod;
8960
- printClientDomainPlan(flags.domain, interim, flags.dns, flags.confirm, target, flags.clientMail === true);
8969
+ const hosts = existingProvisionDomains(projectName, state?.dns);
8970
+ // Railway records its kit domains by environment: without one there is nothing to retire.
8971
+ const onRailway = target === 'railway';
8972
+ const interim = onRailway && !hasRailwayKitDomain(state, 'main') ? undefined : hosts.prod;
8973
+ const dev = onRailway && !hasRailwayKitDomain(state, 'develop') ? undefined : hosts.dev;
8974
+ printClientDomainPlan(flags.domain, { interim, dev }, flags.dns, flags.confirm, target, flags.clientMail === true);
8961
8975
  }
8962
8976
  }
8963
8977
  return result;
@@ -8968,7 +8982,9 @@ export async function runProvision(flags, deps = {}) {
8968
8982
  const preflight = await runProvisionPreflight({
8969
8983
  services: preflightServices,
8970
8984
  teamId: flags.team,
8971
- repoSlug: `${FACTORY_ORG}/${projectName}`,
8985
+ // The repo the steps target (state → `--repo` → `origin` → default), never one re-derived
8986
+ // from the slug: a repo named apart from its slug would fail a check the run would pass.
8987
+ ...(repoSlug ? { repoSlug } : {}),
8972
8988
  rootDir,
8973
8989
  ...(target ? { target } : {}),
8974
8990
  }, { rail });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timekast/factory",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "Public, thin CLI to bootstrap and maintain TimeKast Factory derived projects.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",