@revturbine/cli 0.5.1 → 0.6.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 (2) hide show
  1. package/dist/cli.js +64 -4
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3979,6 +3979,13 @@ var RevTurbineConfigSchema = z19.object({
3979
3979
  // The change set this export represents: the active change set by default,
3980
3980
  // or a specific change set when one is requested. Null for an unscoped export.
3981
3981
  change_set_id: z19.string().nullable().default(null).meta({ ...Unrestricted16, readOnly: true }),
3982
+ // Origin target identity (plan 131 TASK-10, cli.md "Target-aware, portable"):
3983
+ // stamped by the server on export so a downloaded Config File records where
3984
+ // it came from; upload tooling targets these by default and flags a tenant
3985
+ // mismatch against the session before sending. Optional — hand-authored and
3986
+ // pre-existing configs carry no target.
3987
+ tenant_id: z19.string().optional().meta({ ...Unrestricted16, readOnly: true }),
3988
+ environment_id: z19.string().optional().meta({ ...Unrestricted16, readOnly: true }),
3982
3989
  plans: z19.array(RevTurbineConfigPlansItemSchema).meta(Unrestricted16),
3983
3990
  // Optional for back-compat: pre-plan-88 configs (and the live export until web
3984
3991
  // adopts the new @revt-eng/schema) omit it. Add-on definitions only; pricing
@@ -5562,7 +5569,7 @@ function evaluate(graph, opts = {}) {
5562
5569
  }
5563
5570
 
5564
5571
  // src/schema/version.ts
5565
- var SCHEMA_VERSION = "0.1.107";
5572
+ var SCHEMA_VERSION = "0.1.108";
5566
5573
 
5567
5574
  // src/lib/credentials.ts
5568
5575
  import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
@@ -6024,6 +6031,36 @@ function requireSelectors(opts, positionalFiles, {
6024
6031
  return found;
6025
6032
  }
6026
6033
 
6034
+ // src/lib/target.ts
6035
+ function resolveUploadTarget(params) {
6036
+ const embedded = params.embedded ?? void 0;
6037
+ const explicit = params.explicit ?? void 0;
6038
+ if (explicit) {
6039
+ return {
6040
+ ok: true,
6041
+ tenantId: explicit,
6042
+ note: embedded && embedded !== explicit ? `retargeting deliberately: config was exported from ${embedded}, sending to ${explicit} (-t)` : void 0
6043
+ };
6044
+ }
6045
+ if (!embedded || embedded === params.session) {
6046
+ return { ok: true, tenantId: params.session };
6047
+ }
6048
+ return {
6049
+ ok: false,
6050
+ error: `this config was exported from tenant ${embedded}, but the session targets ${params.session}. Pass -t ${embedded} to send it back where it came from, or -t ${params.session} to retarget it deliberately.`
6051
+ };
6052
+ }
6053
+
6054
+ // src/lib/version-trail.ts
6055
+ function serverSchemaIsNewer(config, bundledVersion) {
6056
+ const server = config?.schema_version;
6057
+ if (typeof server !== "string" || !server) return null;
6058
+ const parse = (v) => v.split(".").map((n) => Number.parseInt(n, 10) || 0);
6059
+ const [a, b] = [parse(server), parse(bundledVersion)];
6060
+ const newer = a[0] !== b[0] ? a[0] > b[0] : a[1] !== b[1] ? a[1] > b[1] : (a[2] ?? 0) > (b[2] ?? 0);
6061
+ return newer ? server : null;
6062
+ }
6063
+
6027
6064
  // src/cli.ts
6028
6065
  var DOCS_URL = "https://github.com/revt-eng/revturbine-cli#readme";
6029
6066
  var DEFAULT_URL = "https://revturbine.com/app";
@@ -6076,6 +6113,17 @@ function connect(rawUrl, explicitTenantId) {
6076
6113
  }
6077
6114
  };
6078
6115
  }
6116
+ function uploadTenantFor(rawUrl, config, explicit) {
6117
+ const cred = getCredential(normalizeBaseUrl(rawUrl));
6118
+ const target = resolveUploadTarget({
6119
+ embedded: config?.tenant_id,
6120
+ explicit,
6121
+ session: cred?.tenant_id ?? "dev-tenant-001"
6122
+ });
6123
+ if (!target.ok) fail(EXIT.VALIDATION, target.error);
6124
+ if (target.note) diag(target.note);
6125
+ return target.tenantId;
6126
+ }
6079
6127
  function authHint(url, status) {
6080
6128
  if (status === 401 || status === 403) {
6081
6129
  diag(`Authentication required for ${url}. Log in with:
@@ -6104,11 +6152,21 @@ async function getJson(conn, pathname) {
6104
6152
  const json = await res.json().catch(() => ({}));
6105
6153
  return { res, json };
6106
6154
  }
6155
+ function warnIfSchemaBehind(config) {
6156
+ const server = serverSchemaIsNewer(config, SCHEMA_VERSION);
6157
+ if (server) {
6158
+ diag(
6159
+ `WARNING: the server's schema (${server}) is newer than this CLI's bundled snapshot (${SCHEMA_VERSION}) \u2014 offline validation may be missing rules. Update: npm i -g @revturbine/cli`
6160
+ );
6161
+ }
6162
+ }
6107
6163
  async function downloadConfig(conn, playbookVersionId) {
6108
6164
  const qs = playbookVersionId ? `?playbookVersionId=${encodeURIComponent(playbookVersionId)}` : "";
6109
6165
  const res = await request(conn, `/api/config/export${qs}`);
6110
6166
  if (!res.ok) httpFail(conn, "download", res.status);
6111
- return res.json().catch(() => ({}));
6167
+ const config = await res.json().catch(() => ({}));
6168
+ warnIfSchemaBehind(config);
6169
+ return config;
6112
6170
  }
6113
6171
  async function requireOpenDraft(conn) {
6114
6172
  const { ok, status, draft } = await resolveActiveDraft(conn.url, conn.headers);
@@ -6506,7 +6564,7 @@ program.command("show").description(`Render a summary view of a config version.
6506
6564
  program.command("upload").description("Stage a Config File as the open draft (POST /api/config/import).").argument("<config>", "Path to a Config File").option("-u, --url <url>", "RevTurbine instance URL", DEFAULT_URL).option("-t, --tenant-id <id>", "x-tenant-id (defaults to the stored token tenant)").action(async (configFile2, opts) => {
6507
6565
  const config = verifyConfig(configFile2);
6508
6566
  if (config === null) fail(EXIT.VALIDATION, `Fix the issues above in ${configFile2}, then re-run.`);
6509
- const conn = connect(opts.url, opts.tenantId);
6567
+ const conn = connect(opts.url, uploadTenantFor(opts.url, config, opts.tenantId));
6510
6568
  diag(`Staging ${configFile2} as the open draft (${conn.url}/api/config/import) \u2026`);
6511
6569
  const { res, json } = await postJson(conn, "/api/config/import", config);
6512
6570
  if (!res.ok) {
@@ -6526,11 +6584,12 @@ program.command("upload").description("Stage a Config File as the open draft (PO
6526
6584
  });
6527
6585
  program.command("launch").description("Take a config live as a new Release: validate (launch gate), then submit \u2192 approve \u2192 deploy. Synchronous.").argument("[file]", "Config File to upload and launch directly").option("--draft", "Launch the already-open draft").option("-u, --url <url>", "RevTurbine instance URL", DEFAULT_URL).option("-t, --tenant-id <id>", "x-tenant-id (defaults to the stored token tenant)").option("--yes", "Accepted for parity with discard/restore; launch has no confirmation prompt").action(async (file, opts) => {
6528
6586
  const [sel] = requireSelectors(opts, file ? [file] : [], { count: 1, allowed: ["file", "draft"], command: "launch" });
6529
- const conn = connect(opts.url, opts.tenantId);
6587
+ let conn;
6530
6588
  let playbookVersionId;
6531
6589
  if (sel.kind === "file") {
6532
6590
  const config = verifyConfig(sel.path);
6533
6591
  if (config === null) fail(EXIT.VALIDATION, `Fix the issues above in ${sel.path}, then re-run.`);
6592
+ conn = connect(opts.url, uploadTenantFor(opts.url, config, opts.tenantId));
6534
6593
  diag(`Staging ${sel.path} as the open draft \u2026`);
6535
6594
  const { res, json } = await postJson(conn, "/api/config/import", config);
6536
6595
  if (!res.ok) {
@@ -6541,6 +6600,7 @@ program.command("launch").description("Take a config live as a new Release: vali
6541
6600
  if (!playbookVersionId) fail(EXIT.SERVER, "No playbook_version_id returned by the import \u2014 cannot launch.");
6542
6601
  diag(`\u2713 Staged (${playbookVersionId})`);
6543
6602
  } else {
6603
+ conn = connect(opts.url, opts.tenantId);
6544
6604
  playbookVersionId = await requireOpenDraft(conn);
6545
6605
  }
6546
6606
  await launchDraft(conn, playbookVersionId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revturbine/cli",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "revturbine — verify RevTurbine ExportedConfig files and ship them to a RevTurbine instance through the Change Set lifecycle.",
5
5
  "license": "MIT",
6
6
  "repository": {