@treeseed/sdk 0.12.29 → 0.12.31

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.
@@ -8,6 +8,15 @@ function sleep(ms) {
8
8
  function normalizedBaseUrl(value2) {
9
9
  return value2.trim().replace(/\/+$/u, "");
10
10
  }
11
+ function isLoopbackBaseUrl(value2) {
12
+ if (!value2) return false;
13
+ try {
14
+ const url = new URL(value2);
15
+ return ["localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]"].includes(url.hostname);
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
11
20
  function value(name, values, env) {
12
21
  const candidate = env[name] ?? values[name];
13
22
  return typeof candidate === "string" && candidate.trim() ? candidate.trim() : null;
@@ -27,7 +36,8 @@ function manifestApiBaseUrl(tenantRoot, environment) {
27
36
  const config = loadTreeseedDeployConfigFromPath(candidate);
28
37
  const connectionUrl = config.connections?.api?.environments?.[environment]?.baseUrl;
29
38
  const serviceUrl = config.services?.api?.environments?.[environment]?.baseUrl;
30
- const baseUrl = connectionUrl ?? serviceUrl;
39
+ const apiDomain = config.surfaces?.api?.environments?.[environment]?.domain;
40
+ const baseUrl = connectionUrl ?? serviceUrl ?? (typeof apiDomain === "string" && apiDomain.trim() ? `https://${apiDomain.trim()}` : null);
31
41
  if (typeof baseUrl === "string" && baseUrl.trim()) {
32
42
  return baseUrl.trim();
33
43
  }
@@ -108,8 +118,11 @@ async function runTreeseedOperationsRunnerSmoke(options) {
108
118
  values = {};
109
119
  }
110
120
  const baseUrl = normalizedBaseUrl(
111
- options.baseUrl ?? manifestApiBaseUrl(options.tenantRoot, options.environment) ?? value("TREESEED_API_BASE_URL", values, env) ?? value("TREESEED_CENTRAL_MARKET_API_BASE_URL", values, env) ?? defaultBaseUrl(options.environment)
121
+ options.baseUrl ?? manifestApiBaseUrl(options.tenantRoot, options.environment) ?? (options.environment === "local" ? value("TREESEED_API_BASE_URL", values, env) : null) ?? (options.environment === "local" ? value("TREESEED_CENTRAL_MARKET_API_BASE_URL", values, env) : null) ?? defaultBaseUrl(options.environment)
112
122
  );
123
+ if (options.environment !== "local" && isLoopbackBaseUrl(baseUrl)) {
124
+ return failure(baseUrl, options.environment, [`Operations runner smoke for ${options.environment} must target a live hosted API URL, not ${baseUrl}.`], []);
125
+ }
113
126
  const serviceId = options.serviceId ?? value("TREESEED_ACCEPTANCE_SERVICE_ID", values, env) ?? value("TREESEED_WEB_SERVICE_ID", values, env) ?? value("TREESEED_API_WEB_SERVICE_ID", values, env) ?? "web";
114
127
  const localServiceSecret = options.environment === "local" ? envValue("TREESEED_ACCEPTANCE_SERVICE_SECRET", env) ?? envValue("TREESEED_WEB_SERVICE_SECRET", env) ?? envValue("TREESEED_API_WEB_SERVICE_SECRET", env) ?? localManagedDevServiceSecret(options.environment) : null;
115
128
  const serviceSecret = options.serviceSecret ?? localServiceSecret ?? value("TREESEED_ACCEPTANCE_SERVICE_SECRET", values, env) ?? value("TREESEED_WEB_SERVICE_SECRET", values, env) ?? value("TREESEED_API_WEB_SERVICE_SECRET", values, env);
@@ -1679,25 +1679,27 @@ mutation TreeseedRailwayVariableCollectionUpsert($input: VariableCollectionUpser
1679
1679
  await upsertOne(key, value);
1680
1680
  }
1681
1681
  }
1682
+ const expectedKeys = Object.keys(variables);
1683
+ const mismatchedKeys = (observed2) => expectedKeys.filter((key) => observed2[key] !== variables[key]);
1682
1684
  const observed = await listRailwayVariables({ projectId, environmentId, serviceId, env, fetchImpl }).catch(() => ({}));
1683
- const missing = Object.keys(variables).filter((key) => observed[key] == null);
1684
- for (const key of missing) {
1685
+ const missingOrMismatched = mismatchedKeys(observed);
1686
+ for (const key of missingOrMismatched) {
1685
1687
  await upsertOne(key, variables[key]);
1686
1688
  }
1687
- let retried = missing.length > 0 ? await listRailwayVariables({ projectId, environmentId, serviceId, env, fetchImpl }).catch(() => ({})) : observed;
1688
- let stillMissing = Object.keys(variables).filter((key) => retried[key] == null);
1689
- for (let attempt = 0; stillMissing.length > 0 && attempt < 12; attempt += 1) {
1689
+ let retried = missingOrMismatched.length > 0 ? await listRailwayVariables({ projectId, environmentId, serviceId, env, fetchImpl }).catch(() => ({})) : observed;
1690
+ let stillMismatched = mismatchedKeys(retried);
1691
+ for (let attempt = 0; stillMismatched.length > 0 && attempt < 12; attempt += 1) {
1690
1692
  await new Promise((resolve) => setTimeout(resolve, 2500));
1691
1693
  retried = await listRailwayVariables({ projectId, environmentId, serviceId, env, fetchImpl }).catch(() => ({}));
1692
- stillMissing = Object.keys(variables).filter((key) => retried[key] == null);
1693
- if (stillMissing.length > 0 && attempt === 5) {
1694
- for (const key of stillMissing) {
1694
+ stillMismatched = mismatchedKeys(retried);
1695
+ if (stillMismatched.length > 0 && attempt === 5) {
1696
+ for (const key of stillMismatched) {
1695
1697
  await upsertOne(key, variables[key]);
1696
1698
  }
1697
1699
  }
1698
1700
  }
1699
- if (stillMissing.length > 0) {
1700
- throw new Error(`Railway variable upsert did not persist: ${stillMissing.join(", ")}.`);
1701
+ if (stillMismatched.length > 0) {
1702
+ throw new Error(`Railway variable upsert did not persist expected values: ${stillMismatched.join(", ")}.`);
1701
1703
  }
1702
1704
  }
1703
1705
  async function listRailwayVolumes({
@@ -5030,8 +5030,9 @@ async function verifyRailwayUnit(input) {
5030
5030
  serviceId: entry.service.id,
5031
5031
  env: topology.env
5032
5032
  }).catch(() => entry.currentVariables);
5033
- const expectedKeys = [...Object.keys(sync.variables), ...Object.keys(sync.secrets)];
5034
- if (expectedKeys.every((key) => Object.hasOwn(currentVariables, key))) {
5033
+ const expectedVariablesMatch = Object.entries(sync.variables).every(([key, value]) => currentVariables[key] === value);
5034
+ const expectedSecretsExist = Object.keys(sync.secrets).every((key) => Object.hasOwn(currentVariables, key));
5035
+ if (expectedVariablesMatch && expectedSecretsExist) {
5035
5036
  break;
5036
5037
  }
5037
5038
  sleepMs(1e3);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.12.29",
3
+ "version": "0.12.31",
4
4
  "description": "Shared Treeseed SDK for content-backed and D1-backed object models.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {