@tachyon-gg/railway-deploy 0.2.0 → 0.2.2

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/index.js +248 -251
  2. package/package.json +4 -3
package/dist/index.js CHANGED
@@ -23745,6 +23745,48 @@ var require_graphql2 = __commonJS((exports) => {
23745
23745
  var _index6 = require_utilities();
23746
23746
  });
23747
23747
 
23748
+ // node_modules/fast-deep-equal/index.js
23749
+ var require_fast_deep_equal = __commonJS((exports, module) => {
23750
+ module.exports = function equal(a, b) {
23751
+ if (a === b)
23752
+ return true;
23753
+ if (a && b && typeof a == "object" && typeof b == "object") {
23754
+ if (a.constructor !== b.constructor)
23755
+ return false;
23756
+ var length, i, keys;
23757
+ if (Array.isArray(a)) {
23758
+ length = a.length;
23759
+ if (length != b.length)
23760
+ return false;
23761
+ for (i = length;i-- !== 0; )
23762
+ if (!equal(a[i], b[i]))
23763
+ return false;
23764
+ return true;
23765
+ }
23766
+ if (a.constructor === RegExp)
23767
+ return a.source === b.source && a.flags === b.flags;
23768
+ if (a.valueOf !== Object.prototype.valueOf)
23769
+ return a.valueOf() === b.valueOf();
23770
+ if (a.toString !== Object.prototype.toString)
23771
+ return a.toString() === b.toString();
23772
+ keys = Object.keys(a);
23773
+ length = keys.length;
23774
+ if (length !== Object.keys(b).length)
23775
+ return false;
23776
+ for (i = length;i-- !== 0; )
23777
+ if (!Object.prototype.hasOwnProperty.call(b, keys[i]))
23778
+ return false;
23779
+ for (i = length;i-- !== 0; ) {
23780
+ var key = keys[i];
23781
+ if (!equal(a[key], b[key]))
23782
+ return false;
23783
+ }
23784
+ return true;
23785
+ }
23786
+ return a !== a && b !== b;
23787
+ };
23788
+ });
23789
+
23748
23790
  // node_modules/commander/esm.mjs
23749
23791
  var import__ = __toESM(require_commander(), 1);
23750
23792
  var {
@@ -37549,19 +37591,21 @@ ${issues}`);
37549
37591
  // src/config/variables.ts
37550
37592
  var import_dotenv = __toESM(require_main(), 1);
37551
37593
  import { readFileSync } from "fs";
37552
- function resolveEnvVars(variables, env = process.env) {
37594
+ function resolveEnvVars(variables, env = process.env, lenient = false) {
37553
37595
  const resolved = {};
37554
37596
  for (const [key, value] of Object.entries(variables)) {
37555
37597
  if (value === null)
37556
37598
  continue;
37557
- resolved[key] = resolveEnvVarString(value, env);
37599
+ resolved[key] = resolveEnvVarString(value, env, lenient);
37558
37600
  }
37559
37601
  return resolved;
37560
37602
  }
37561
- function resolveEnvVarString(input, env = process.env) {
37562
- return input.replace(/\$\{(?!\{)([^}]+)\}/g, (_match, name) => {
37603
+ function resolveEnvVarString(input, env = process.env, lenient = false) {
37604
+ return input.replace(/\$\{(?!\{)([^}]+)\}/g, (match, name) => {
37563
37605
  const value = env[name];
37564
37606
  if (value === undefined) {
37607
+ if (lenient)
37608
+ return match;
37565
37609
  throw new Error(`Environment variable "${name}" is not set (referenced as \${${name}})`);
37566
37610
  }
37567
37611
  return value;
@@ -37590,7 +37634,7 @@ function normalizeDomains(domains) {
37590
37634
  return [];
37591
37635
  return domains.map(normalizeDomainEntry);
37592
37636
  }
37593
- function loadEnvironmentConfig(envFilePath) {
37637
+ function loadEnvironmentConfig(envFilePath, options) {
37594
37638
  const absPath = resolve(envFilePath);
37595
37639
  if (!existsSync(absPath)) {
37596
37640
  throw new Error(`Config file not found: ${absPath}`);
@@ -37612,14 +37656,15 @@ function loadEnvironmentConfig(envFilePath) {
37612
37656
  const config2 = parsed;
37613
37657
  const services = {};
37614
37658
  const deletedVars = {};
37659
+ const lenient = options?.lenient ?? false;
37615
37660
  for (const [name, entry] of Object.entries(config2.services)) {
37616
- const { service, deleted } = resolveService(name, entry, envDir);
37661
+ const { service, deleted } = resolveService(name, entry, envDir, lenient);
37617
37662
  services[name] = service;
37618
37663
  if (deleted.length > 0) {
37619
37664
  deletedVars[name] = deleted;
37620
37665
  }
37621
37666
  }
37622
- const resolvedSharedVars = config2.shared_variables ? resolveEnvVars(config2.shared_variables) : {};
37667
+ const resolvedSharedVars = config2.shared_variables ? resolveEnvVars(config2.shared_variables, process.env, lenient) : {};
37623
37668
  const deletedSharedVars = config2.shared_variables ? getDeletedVariables(config2.shared_variables) : [];
37624
37669
  const buckets = {};
37625
37670
  if (config2.buckets) {
@@ -37641,7 +37686,7 @@ function loadEnvironmentConfig(envFilePath) {
37641
37686
  environmentName: config2.environment
37642
37687
  };
37643
37688
  }
37644
- function resolveService(name, entry, envDir) {
37689
+ function resolveService(name, entry, envDir, lenient = false) {
37645
37690
  let template;
37646
37691
  if (entry.template) {
37647
37692
  const templatePath = resolve(envDir, entry.template);
@@ -37708,9 +37753,9 @@ function resolveService(name, entry, envDir) {
37708
37753
  ...entry.variables || {}
37709
37754
  };
37710
37755
  const deleted = getDeletedVariables(mergedVars);
37711
- const resolvedVars = resolveEnvVars(mergedVars);
37756
+ const resolvedVars = resolveEnvVars(mergedVars, process.env, lenient);
37712
37757
  const resolvedDomainsRaw = domains.map((d) => ({
37713
- domain: resolveEnvVarString(d.domain),
37758
+ domain: resolveEnvVarString(d.domain, process.env, lenient),
37714
37759
  ...d.targetPort !== undefined ? { targetPort: d.targetPort } : {}
37715
37760
  }));
37716
37761
  const seenDomains = new Set;
@@ -37776,8 +37821,8 @@ function resolveService(name, entry, envDir) {
37776
37821
  service.checkSuites = checkSuites;
37777
37822
  if (registryCredentials) {
37778
37823
  service.registryCredentials = {
37779
- username: resolveEnvVarString(registryCredentials.username),
37780
- password: resolveEnvVarString(registryCredentials.password)
37824
+ username: resolveEnvVarString(registryCredentials.username, process.env, lenient),
37825
+ password: resolveEnvVarString(registryCredentials.password, process.env, lenient)
37781
37826
  };
37782
37827
  }
37783
37828
  if (railwayDomain !== undefined) {
@@ -38853,62 +38898,162 @@ function isSensitive(key) {
38853
38898
  function maskValue(key, value) {
38854
38899
  return isSensitive(key) ? "***" : value;
38855
38900
  }
38856
- function changeLabel(change) {
38901
+ function describeChange(change) {
38857
38902
  switch (change.type) {
38858
- case "create-service":
38859
- return `create-service: ${change.name}`;
38903
+ case "create-service": {
38904
+ const src = change.source?.image || change.source?.repo || "empty";
38905
+ const details = [src];
38906
+ if (change.branch)
38907
+ details.push(`branch: ${change.branch}`);
38908
+ if (change.volume)
38909
+ details.push(`volume: ${change.volume.mount}`);
38910
+ if (change.cronSchedule)
38911
+ details.push(`cron: ${change.cronSchedule}`);
38912
+ return {
38913
+ category: "Services",
38914
+ action: "create",
38915
+ summary: `${change.name} (${details.join(", ")})`
38916
+ };
38917
+ }
38860
38918
  case "delete-service":
38861
- return `delete-service: ${change.name}`;
38862
- case "upsert-variables":
38863
- return `upsert-variables: ${change.serviceName} (${Object.keys(change.variables).length} vars)`;
38864
- case "delete-variables":
38865
- return `delete-variables: ${change.serviceName} (${change.variableNames.length} vars)`;
38866
- case "upsert-shared-variables":
38867
- return `upsert-shared-variables (${Object.keys(change.variables).length} vars)`;
38868
- case "delete-shared-variables":
38869
- return `delete-shared-variables (${change.variableNames.length} vars)`;
38870
- case "create-domain":
38871
- return `create-domain: ${change.serviceName} → ${change.domain}`;
38872
- case "delete-domain":
38873
- return `delete-domain: ${change.serviceName} → ${change.domain}`;
38919
+ return {
38920
+ category: "Services",
38921
+ action: "delete",
38922
+ summary: `${change.name} (${change.serviceId})`
38923
+ };
38874
38924
  case "update-service-settings":
38875
- return `update-settings: ${change.serviceName} (${Object.keys(change.settings).join(", ")})`;
38876
- case "create-volume":
38877
- return `create-volume: ${change.serviceName} (${change.mount})`;
38878
- case "delete-volume":
38879
- return `delete-volume: ${change.serviceName}`;
38925
+ return {
38926
+ category: "Service settings",
38927
+ action: "update",
38928
+ summary: `${change.serviceName}: ${Object.keys(change.settings).join(", ")}`
38929
+ };
38880
38930
  case "update-deployment-trigger": {
38881
38931
  const parts = [];
38882
38932
  if (change.branch)
38883
- parts.push(`branch: ${change.branch}`);
38933
+ parts.push(`branch ${change.branch}`);
38884
38934
  if (change.checkSuites !== undefined)
38885
- parts.push(`checkSuites: ${change.checkSuites}`);
38886
- return `update-deployment-trigger: ${change.serviceName} → ${parts.join(", ")}`;
38935
+ parts.push(`checkSuites ${change.checkSuites}`);
38936
+ return {
38937
+ category: "Deployment triggers",
38938
+ action: "update",
38939
+ summary: `${change.serviceName}: ${parts.join(", ")}`
38940
+ };
38941
+ }
38942
+ case "upsert-variables":
38943
+ return {
38944
+ category: "Service variables",
38945
+ action: "update",
38946
+ summary: `${change.serviceName}: set ${Object.keys(change.variables).length} var(s) — ${Object.keys(change.variables).join(", ")}`
38947
+ };
38948
+ case "delete-variables":
38949
+ return {
38950
+ category: "Service variables",
38951
+ action: "delete",
38952
+ summary: `${change.serviceName}: delete ${change.variableNames.length} var(s) — ${change.variableNames.join(", ")}`
38953
+ };
38954
+ case "upsert-shared-variables":
38955
+ return {
38956
+ category: "Shared variables",
38957
+ action: "update",
38958
+ summary: `set ${Object.keys(change.variables).length} var(s) — ${Object.keys(change.variables).join(", ")}`
38959
+ };
38960
+ case "delete-shared-variables":
38961
+ return {
38962
+ category: "Shared variables",
38963
+ action: "delete",
38964
+ summary: `delete ${change.variableNames.length} var(s) — ${change.variableNames.join(", ")}`
38965
+ };
38966
+ case "create-domain": {
38967
+ const port = change.targetPort ? ` (port ${change.targetPort})` : "";
38968
+ return {
38969
+ category: "Domains",
38970
+ action: "create",
38971
+ summary: `${change.serviceName}: ${change.domain}${port}`
38972
+ };
38973
+ }
38974
+ case "delete-domain":
38975
+ return {
38976
+ category: "Domains",
38977
+ action: "delete",
38978
+ summary: `${change.serviceName}: ${change.domain}`
38979
+ };
38980
+ case "create-service-domain": {
38981
+ const port = change.targetPort ? ` (port ${change.targetPort})` : "";
38982
+ return {
38983
+ category: "Railway domains",
38984
+ action: "create",
38985
+ summary: `${change.serviceName}${port}`
38986
+ };
38887
38987
  }
38888
- case "create-service-domain":
38889
- return `create-service-domain: ${change.serviceName}`;
38890
38988
  case "delete-service-domain":
38891
- return `delete-service-domain: ${change.serviceName}`;
38989
+ return { category: "Railway domains", action: "delete", summary: change.serviceName };
38990
+ case "create-volume":
38991
+ return {
38992
+ category: "Volumes",
38993
+ action: "create",
38994
+ summary: `${change.serviceName}: ${change.mount}`
38995
+ };
38996
+ case "delete-volume":
38997
+ return {
38998
+ category: "Volumes",
38999
+ action: "delete",
39000
+ summary: `${change.serviceName} (${change.volumeId})`
39001
+ };
38892
39002
  case "create-tcp-proxy":
38893
- return `create-tcp-proxy: ${change.serviceName} (port ${change.applicationPort})`;
39003
+ return {
39004
+ category: "TCP proxies",
39005
+ action: "create",
39006
+ summary: `${change.serviceName}: port ${change.applicationPort}`
39007
+ };
38894
39008
  case "delete-tcp-proxy":
38895
- return `delete-tcp-proxy: ${change.serviceName}`;
38896
- case "update-service-limits":
38897
- return `update-service-limits: ${change.serviceName}`;
39009
+ return {
39010
+ category: "TCP proxies",
39011
+ action: "delete",
39012
+ summary: `${change.serviceName}: proxy ${change.proxyId}`
39013
+ };
39014
+ case "update-service-limits": {
39015
+ const parts = [];
39016
+ if (change.limits.memoryGB !== undefined)
39017
+ parts.push(`memory: ${change.limits.memoryGB ?? "unset"}GB`);
39018
+ if (change.limits.vCPUs !== undefined)
39019
+ parts.push(`vCPUs: ${change.limits.vCPUs ?? "unset"}`);
39020
+ return {
39021
+ category: "Resource limits",
39022
+ action: "update",
39023
+ summary: `${change.serviceName}: ${parts.join(", ")}`
39024
+ };
39025
+ }
38898
39026
  case "enable-static-ips":
38899
- return `enable-static-ips: ${change.serviceName}`;
39027
+ return {
39028
+ category: "Static outbound IPs",
39029
+ action: "create",
39030
+ summary: `${change.serviceName}: enable`
39031
+ };
38900
39032
  case "disable-static-ips":
38901
- return `disable-static-ips: ${change.serviceName}`;
39033
+ return {
39034
+ category: "Static outbound IPs",
39035
+ action: "delete",
39036
+ summary: `${change.serviceName}: disable`
39037
+ };
38902
39038
  case "create-bucket":
38903
- return `create-bucket: ${change.bucketName}`;
39039
+ return { category: "Buckets", action: "create", summary: change.bucketName };
38904
39040
  case "delete-bucket":
38905
- return `delete-bucket: ${change.name}`;
39041
+ return { category: "Buckets", action: "delete", summary: change.name };
38906
39042
  default: {
38907
39043
  const _exhaustive = change;
38908
- return `unknown: ${_exhaustive.type}`;
39044
+ return { category: "Unknown", action: "update", summary: _exhaustive.type };
38909
39045
  }
38910
39046
  }
38911
39047
  }
39048
+ function changeLabel(change) {
39049
+ const desc = describeChange(change);
39050
+ return `${change.type}: ${desc.summary}`;
39051
+ }
39052
+ var ACTION_ICON = {
39053
+ create: (nc) => green("+", nc),
39054
+ update: (nc) => yellow("~", nc),
39055
+ delete: (nc) => red("-", nc)
39056
+ };
38912
39057
  function printChangeset(changeset, options) {
38913
39058
  const noColor = options?.noColor ?? false;
38914
39059
  const verbose = options?.verbose ?? false;
@@ -38921,214 +39066,65 @@ ${green("No changes needed", noColor)} — Railway matches desired state.
38921
39066
  console.log(`
38922
39067
  Changeset (${changeset.changes.length} changes):
38923
39068
  `);
38924
- const creates = changeset.changes.filter((c) => c.type === "create-service");
38925
- const deletes = changeset.changes.filter((c) => c.type === "delete-service");
38926
- const upsertVars = changeset.changes.filter((c) => c.type === "upsert-variables");
38927
- const deleteVars = changeset.changes.filter((c) => c.type === "delete-variables");
38928
- const sharedUpsert = changeset.changes.filter((c) => c.type === "upsert-shared-variables");
38929
- const sharedDelete = changeset.changes.filter((c) => c.type === "delete-shared-variables");
38930
- const domainChanges = changeset.changes.filter((c) => c.type === "create-domain" || c.type === "delete-domain");
38931
- const settingsChanges = changeset.changes.filter((c) => c.type === "update-service-settings");
38932
- const triggerChanges = changeset.changes.filter((c) => c.type === "update-deployment-trigger");
38933
- const volumeCreates = changeset.changes.filter((c) => c.type === "create-volume");
38934
- const volumeDeletes = changeset.changes.filter((c) => c.type === "delete-volume");
38935
- const serviceDomainChanges = changeset.changes.filter((c) => c.type === "create-service-domain" || c.type === "delete-service-domain");
38936
- const tcpProxyChanges = changeset.changes.filter((c) => c.type === "create-tcp-proxy" || c.type === "delete-tcp-proxy");
38937
- const limitsChanges = changeset.changes.filter((c) => c.type === "update-service-limits");
38938
- const staticIpChanges = changeset.changes.filter((c) => c.type === "enable-static-ips" || c.type === "disable-static-ips");
38939
- const bucketCreates = changeset.changes.filter((c) => c.type === "create-bucket");
38940
- const bucketDeletes = changeset.changes.filter((c) => c.type === "delete-bucket");
38941
- if (creates.length > 0) {
38942
- console.log(` ${green("+", noColor)} CREATE services:`);
38943
- for (const c of creates) {
38944
- if (c.type === "create-service") {
38945
- const src = c.source?.image || c.source?.repo || "empty";
38946
- console.log(` ${green("+", noColor)} ${c.name} (${src})`);
38947
- }
38948
- }
38949
- console.log();
38950
- }
38951
- if (deletes.length > 0) {
38952
- console.log(` ${red("-", noColor)} DELETE services:`);
38953
- for (const c of deletes) {
38954
- if (c.type === "delete-service") {
38955
- console.log(` ${red("-", noColor)} ${c.name} ${dim(`(${c.serviceId})`, noColor)}`);
38956
- }
38957
- }
38958
- console.log();
38959
- }
38960
- if (settingsChanges.length > 0) {
38961
- console.log(` ${yellow("~", noColor)} UPDATE service settings:`);
38962
- for (const c of settingsChanges) {
38963
- if (c.type === "update-service-settings") {
38964
- const keys = Object.keys(c.settings).join(", ");
38965
- console.log(` ${yellow("~", noColor)} ${c.serviceName}: ${keys}`);
38966
- if (verbose) {
38967
- for (const [key, value] of Object.entries(c.settings)) {
38968
- const currentSvc = options?.currentState?.services[c.serviceName];
38969
- const oldVal = currentSvc ? currentSvc[key] : undefined;
38970
- const oldStr = oldVal !== undefined ? JSON.stringify(oldVal) : "(unset)";
38971
- const newStr = value === null ? "(unset)" : JSON.stringify(value);
38972
- console.log(` ${key}: ${oldStr} → ${newStr}`);
38973
- }
38974
- }
38975
- }
38976
- }
38977
- console.log();
38978
- }
38979
- if (triggerChanges.length > 0) {
38980
- console.log(` ${yellow("~", noColor)} DEPLOYMENT TRIGGERS:`);
38981
- for (const c of triggerChanges) {
38982
- if (c.type === "update-deployment-trigger") {
38983
- const parts2 = [];
38984
- if (c.branch)
38985
- parts2.push(`branch → ${c.branch}`);
38986
- if (c.checkSuites !== undefined)
38987
- parts2.push(`checkSuites → ${c.checkSuites}`);
38988
- console.log(` ${yellow("~", noColor)} ${c.serviceName}: ${parts2.join(", ")}`);
38989
- }
38990
- }
38991
- console.log();
38992
- }
38993
- if (sharedUpsert.length > 0 || sharedDelete.length > 0) {
38994
- console.log(` ${yellow("~", noColor)} SHARED variables:`);
38995
- for (const c of sharedUpsert) {
38996
- if (c.type === "upsert-shared-variables") {
38997
- for (const [key, value] of Object.entries(c.variables)) {
38998
- if (verbose) {
38999
- const oldVal = options?.currentState?.sharedVariables[key];
39000
- const oldStr = oldVal !== undefined ? maskValue(key, oldVal) : "(unset)";
39001
- console.log(` ${green("+", noColor)} ${key}: ${dim(`"${oldStr}"`, noColor)} → ${dim(`"${maskValue(key, value)}"`, noColor)}`);
39002
- } else {
39003
- console.log(` ${green("+", noColor)} ${key}`);
39004
- }
39069
+ const groups = new Map;
39070
+ for (const change of changeset.changes) {
39071
+ const desc = describeChange(change);
39072
+ let group = groups.get(desc.category);
39073
+ if (!group) {
39074
+ group = [];
39075
+ groups.set(desc.category, group);
39076
+ }
39077
+ group.push({ change, desc });
39078
+ }
39079
+ for (const [category, entries] of groups) {
39080
+ const actions = new Set(entries.map((e) => e.desc.action));
39081
+ const headerAction = actions.size === 1 ? [...actions][0] : "update";
39082
+ const headerIcon = ACTION_ICON[headerAction](noColor);
39083
+ console.log(` ${headerIcon} ${category.toUpperCase()}:`);
39084
+ for (const { change, desc } of entries) {
39085
+ const icon = ACTION_ICON[desc.action](noColor);
39086
+ if (verbose && change.type === "update-service-settings") {
39087
+ console.log(` ${icon} ${change.serviceName}:`);
39088
+ for (const [key, value] of Object.entries(change.settings)) {
39089
+ const currentSvc = options?.currentState?.services[change.serviceName];
39090
+ const oldVal = currentSvc ? currentSvc[key] : undefined;
39091
+ const oldStr = oldVal !== undefined ? JSON.stringify(oldVal) : "(unset)";
39092
+ const newStr = value === null ? "(unset)" : JSON.stringify(value);
39093
+ console.log(` ${key}: ${oldStr} → ${newStr}`);
39094
+ }
39095
+ } else if (verbose && change.type === "upsert-variables") {
39096
+ console.log(` ${change.serviceName}:`);
39097
+ for (const [key, value] of Object.entries(change.variables)) {
39098
+ const currentSvc = options?.currentState?.services[change.serviceName];
39099
+ const oldVal = currentSvc?.variables[key];
39100
+ const oldStr = oldVal !== undefined ? maskValue(key, oldVal) : "(unset)";
39101
+ console.log(` ${icon} ${key}: ${dim(`"${oldStr}"`, noColor)} → ${dim(`"${maskValue(key, value)}"`, noColor)}`);
39102
+ }
39103
+ } else if (verbose && change.type === "upsert-shared-variables") {
39104
+ for (const [key, value] of Object.entries(change.variables)) {
39105
+ const oldVal = options?.currentState?.sharedVariables[key];
39106
+ const oldStr = oldVal !== undefined ? maskValue(key, oldVal) : "(unset)";
39107
+ console.log(` ${icon} ${key}: ${dim(`"${oldStr}"`, noColor)} ${dim(`"${maskValue(key, value)}"`, noColor)}`);
39005
39108
  }
39006
- }
39007
- }
39008
- for (const c of sharedDelete) {
39009
- if (c.type === "delete-shared-variables") {
39010
- for (const name of c.variableNames) {
39011
- console.log(` ${red("-", noColor)} ${name}`);
39012
- }
39013
- }
39014
- }
39015
- console.log();
39016
- }
39017
- if (upsertVars.length > 0 || deleteVars.length > 0) {
39018
- console.log(` ${yellow("~", noColor)} SERVICE variables:`);
39019
- for (const c of upsertVars) {
39020
- if (c.type === "upsert-variables") {
39021
- const keys = Object.keys(c.variables);
39022
- if (verbose) {
39023
- console.log(` ${c.serviceName}:`);
39024
- for (const [key, value] of Object.entries(c.variables)) {
39025
- const currentSvc = options?.currentState?.services[c.serviceName];
39026
- const oldVal = currentSvc?.variables[key];
39027
- const oldStr = oldVal !== undefined ? maskValue(key, oldVal) : "(unset)";
39028
- console.log(` ${green("+", noColor)} ${key}: ${dim(`"${oldStr}"`, noColor)} → ${dim(`"${maskValue(key, value)}"`, noColor)}`);
39029
- }
39030
- } else {
39031
- console.log(` ${c.serviceName}: set ${keys.length} var(s) — ${keys.join(", ")}`);
39032
- }
39033
- }
39034
- }
39035
- for (const c of deleteVars) {
39036
- if (c.type === "delete-variables") {
39037
- console.log(` ${c.serviceName}: ${red("delete", noColor)} ${c.variableNames.length} var(s) — ${c.variableNames.join(", ")}`);
39038
- }
39039
- }
39040
- console.log();
39041
- }
39042
- if (domainChanges.length > 0) {
39043
- console.log(` ${yellow("~", noColor)} DOMAINS:`);
39044
- for (const c of domainChanges) {
39045
- if (c.type === "create-domain") {
39046
- console.log(` ${green("+", noColor)} ${c.serviceName}: ${c.domain}`);
39047
- } else if (c.type === "delete-domain") {
39048
- console.log(` ${red("-", noColor)} ${c.serviceName}: ${c.domain}`);
39049
- }
39050
- }
39051
- console.log();
39052
- }
39053
- if (volumeCreates.length > 0 || volumeDeletes.length > 0) {
39054
- console.log(` ${yellow("~", noColor)} VOLUMES:`);
39055
- for (const c of volumeCreates) {
39056
- if (c.type === "create-volume") {
39057
- console.log(` ${green("+", noColor)} ${c.serviceName}: ${c.mount}`);
39058
- }
39059
- }
39060
- for (const c of volumeDeletes) {
39061
- if (c.type === "delete-volume") {
39062
- console.log(` ${red("-", noColor)} ${c.serviceName}`);
39063
- }
39064
- }
39065
- console.log();
39066
- }
39067
- if (serviceDomainChanges.length > 0) {
39068
- console.log(` ${yellow("~", noColor)} RAILWAY DOMAINS:`);
39069
- for (const c of serviceDomainChanges) {
39070
- if (c.type === "create-service-domain") {
39071
- const port = c.targetPort ? ` (port ${c.targetPort})` : "";
39072
- console.log(` ${green("+", noColor)} ${c.serviceName}${port}`);
39073
- } else if (c.type === "delete-service-domain") {
39074
- console.log(` ${red("-", noColor)} ${c.serviceName}`);
39075
- }
39076
- }
39077
- console.log();
39078
- }
39079
- if (tcpProxyChanges.length > 0) {
39080
- console.log(` ${yellow("~", noColor)} TCP PROXIES:`);
39081
- for (const c of tcpProxyChanges) {
39082
- if (c.type === "create-tcp-proxy") {
39083
- console.log(` ${green("+", noColor)} ${c.serviceName}: port ${c.applicationPort}`);
39084
- } else if (c.type === "delete-tcp-proxy") {
39085
- console.log(` ${red("-", noColor)} ${c.serviceName}`);
39086
- }
39087
- }
39088
- console.log();
39089
- }
39090
- if (limitsChanges.length > 0) {
39091
- console.log(` ${yellow("~", noColor)} RESOURCE LIMITS:`);
39092
- for (const c of limitsChanges) {
39093
- if (c.type === "update-service-limits") {
39094
- const parts2 = [];
39095
- if (c.limits.memoryGB !== undefined)
39096
- parts2.push(`memory: ${c.limits.memoryGB ?? "unset"}GB`);
39097
- if (c.limits.vCPUs !== undefined)
39098
- parts2.push(`vCPUs: ${c.limits.vCPUs ?? "unset"}`);
39099
- console.log(` ${yellow("~", noColor)} ${c.serviceName}: ${parts2.join(", ")}`);
39100
- }
39101
- }
39102
- console.log();
39103
- }
39104
- if (staticIpChanges.length > 0) {
39105
- console.log(` ${yellow("~", noColor)} STATIC OUTBOUND IPS:`);
39106
- for (const c of staticIpChanges) {
39107
- if (c.type === "enable-static-ips") {
39108
- console.log(` ${green("+", noColor)} ${c.serviceName}: enable`);
39109
- } else if (c.type === "disable-static-ips") {
39110
- console.log(` ${red("-", noColor)} ${c.serviceName}: disable`);
39109
+ } else {
39110
+ console.log(` ${icon} ${desc.summary}`);
39111
39111
  }
39112
39112
  }
39113
39113
  console.log();
39114
39114
  }
39115
- if (bucketCreates.length > 0 || bucketDeletes.length > 0) {
39116
- console.log(` ${yellow("~", noColor)} BUCKETS:`);
39117
- for (const c of bucketCreates) {
39118
- if (c.type === "create-bucket") {
39119
- console.log(` ${green("+", noColor)} ${c.bucketName}`);
39120
- }
39121
- }
39122
- for (const c of bucketDeletes) {
39123
- if (c.type === "delete-bucket") {
39124
- console.log(` ${red("-", noColor)} ${c.name}`);
39125
- }
39115
+ let createCount = 0;
39116
+ let updateCount = 0;
39117
+ let deleteCount = 0;
39118
+ for (const entries of groups.values()) {
39119
+ for (const { desc } of entries) {
39120
+ if (desc.action === "create")
39121
+ createCount++;
39122
+ else if (desc.action === "update")
39123
+ updateCount++;
39124
+ else
39125
+ deleteCount++;
39126
39126
  }
39127
- console.log();
39128
39127
  }
39129
- const createCount = creates.length + volumeCreates.length + bucketCreates.length + serviceDomainChanges.filter((c) => c.type === "create-service-domain").length + tcpProxyChanges.filter((c) => c.type === "create-tcp-proxy").length + staticIpChanges.filter((c) => c.type === "enable-static-ips").length;
39130
- const updateCount = settingsChanges.length + triggerChanges.length + limitsChanges.length + upsertVars.length + sharedUpsert.length + domainChanges.filter((c) => c.type === "create-domain").length;
39131
- const deleteCount = deletes.length + deleteVars.length + sharedDelete.length + volumeDeletes.length + bucketDeletes.length + domainChanges.filter((c) => c.type === "delete-domain").length + serviceDomainChanges.filter((c) => c.type === "delete-service-domain").length + tcpProxyChanges.filter((c) => c.type === "delete-tcp-proxy").length + staticIpChanges.filter((c) => c.type === "disable-static-ips").length;
39132
39128
  const parts = [];
39133
39129
  if (createCount > 0)
39134
39130
  parts.push(green(`${createCount} to create`, noColor));
@@ -39381,8 +39377,9 @@ async function applyChange(client, change, projectId, environmentId, createdServ
39381
39377
  }
39382
39378
 
39383
39379
  // src/util.ts
39380
+ var import_fast_deep_equal = __toESM(require_fast_deep_equal(), 1);
39384
39381
  function deepEqual(a, b) {
39385
- return Bun.deepEquals(a, b);
39382
+ return import_fast_deep_equal.default(a, b);
39386
39383
  }
39387
39384
 
39388
39385
  // src/reconcile/diff.ts
@@ -39868,7 +39865,7 @@ async function run(configPath, opts) {
39868
39865
  const raw = readFileSync3(absPath, "utf-8");
39869
39866
  const parsed = $parse(raw);
39870
39867
  validateEnvironmentConfig(parsed);
39871
- loadEnvironmentConfig(configPath);
39868
+ loadEnvironmentConfig(configPath, { lenient: true });
39872
39869
  console.log("Config is valid.");
39873
39870
  process.exit(0);
39874
39871
  }
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@tachyon-gg/railway-deploy",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "https://github.com/tachyon-gg/railway-deploy"
7
+ "url": "git+https://github.com/tachyon-gg/railway-deploy.git"
8
8
  },
9
9
  "main": "./dist/index.js",
10
10
  "exports": {
11
11
  ".": "./dist/index.js"
12
12
  },
13
13
  "bin": {
14
- "railway-deploy": "./dist/index.js"
14
+ "railway-deploy": "dist/index.js"
15
15
  },
16
16
  "files": [
17
17
  "dist/"
@@ -35,6 +35,7 @@
35
35
  "@graphql-typed-document-node/core": "^3.2.0",
36
36
  "commander": "^14.0.3",
37
37
  "dotenv": "^17.3.1",
38
+ "fast-deep-equal": "^3.1.3",
38
39
  "graphql": "^16.10.0",
39
40
  "graphql-request": "^7.1.2",
40
41
  "yaml": "^2.7.0",