@treeseed/sdk 0.8.14 → 0.8.16

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.
@@ -120,6 +120,8 @@ export declare class MarketClient {
120
120
  private readonly userAgent?;
121
121
  constructor(options: MarketClientOptions);
122
122
  private request;
123
+ private localAuthPaths;
124
+ private requestFirst;
123
125
  startDeviceLogin(request: DeviceCodeStartRequest): Promise<DeviceCodeStartResponse>;
124
126
  pollDeviceLogin(request: DeviceCodePollRequest): Promise<DeviceCodePollResponse>;
125
127
  refreshToken(request: TokenRefreshRequest): Promise<TokenRefreshResponse>;
@@ -21,7 +21,7 @@ function envValue(name, env = process.env) {
21
21
  }
22
22
  function resolveDefaultCentralMarketBaseUrl(env = process.env) {
23
23
  return normalizeBaseUrl(
24
- envValue(TREESEED_CENTRAL_MARKET_API_BASE_URL_ENV, env) ?? envValue(TREESEED_MARKET_API_BASE_URL_ENV, env) ?? DEFAULT_TREESEED_MARKET_BASE_URL
24
+ envValue(TREESEED_CENTRAL_MARKET_API_BASE_URL_ENV, env) ?? DEFAULT_TREESEED_MARKET_BASE_URL
25
25
  );
26
26
  }
27
27
  function defaultCentralMarket() {
@@ -33,6 +33,17 @@ function defaultCentralMarket() {
33
33
  alwaysAvailable: true
34
34
  };
35
35
  }
36
+ function defaultLocalMarket(env = process.env) {
37
+ return {
38
+ id: "local",
39
+ label: "Local TreeSeed Market",
40
+ baseUrl: normalizeBaseUrl(
41
+ envValue(TREESEED_MARKET_API_BASE_URL_ENV, env) ?? "http://127.0.0.1:3000"
42
+ ),
43
+ kind: "specialized",
44
+ alwaysAvailable: true
45
+ };
46
+ }
36
47
  function homeConfigPath() {
37
48
  const homeRoot = process.env.HOME && process.env.HOME.trim().length > 0 ? process.env.HOME : homedir();
38
49
  return resolve(homeRoot, MARKET_REGISTRY_RELATIVE_PATH);
@@ -140,6 +151,9 @@ function resolveMarketProfile(selector) {
140
151
  alwaysAvailable: false
141
152
  };
142
153
  }
154
+ if (trimmed === "local") {
155
+ return defaultLocalMarket();
156
+ }
143
157
  const marketId = trimmed || state.activeMarketId || "central";
144
158
  const profile = state.profiles.find((entry) => entry.id === marketId);
145
159
  if (!profile) {
@@ -263,20 +277,38 @@ class MarketClient {
263
277
  }
264
278
  return payload;
265
279
  }
280
+ localAuthPaths(v1Path, legacyPath) {
281
+ return this.options.profile.id === "local" ? [legacyPath, v1Path] : [v1Path];
282
+ }
283
+ async requestFirst(paths, options = {}) {
284
+ let notFound = null;
285
+ for (const path of paths) {
286
+ try {
287
+ return await this.request(path, options);
288
+ } catch (error) {
289
+ if (error instanceof MarketApiError && error.status === 404) {
290
+ notFound = error;
291
+ continue;
292
+ }
293
+ throw error;
294
+ }
295
+ }
296
+ throw notFound ?? new MarketApiError("Market request failed with 404.", 404, {});
297
+ }
266
298
  startDeviceLogin(request) {
267
- return this.request("/v1/auth/device/start", {
299
+ return this.requestFirst(this.localAuthPaths("/v1/auth/device/start", "/auth/device/start"), {
268
300
  method: "POST",
269
301
  body: request
270
302
  });
271
303
  }
272
304
  pollDeviceLogin(request) {
273
- return this.request("/v1/auth/device/poll", {
305
+ return this.requestFirst(this.localAuthPaths("/v1/auth/device/poll", "/auth/device/poll"), {
274
306
  method: "POST",
275
307
  body: request
276
308
  });
277
309
  }
278
310
  refreshToken(request) {
279
- return this.request("/v1/auth/token/refresh", {
311
+ return this.requestFirst(this.localAuthPaths("/v1/auth/token/refresh", "/auth/token/refresh"), {
280
312
  method: "POST",
281
313
  body: request
282
314
  });
@@ -1261,6 +1261,36 @@ function buildRailwayCliContextEnv(env, service) {
1261
1261
  RAILWAY_SERVICE_ID: configuredEnvValue(service, "serviceId") || configuredEnvValue(env, "RAILWAY_SERVICE_ID") || void 0
1262
1262
  };
1263
1263
  }
1264
+ async function syncRailwayApiDeviceLoginVariables(service, env, write, prefix) {
1265
+ if (service.key !== "api") {
1266
+ return null;
1267
+ }
1268
+ const projectId = configuredEnvValue(service, "projectId");
1269
+ const environmentId = configuredEnvValue(service, "environmentId");
1270
+ const serviceId = configuredEnvValue(service, "serviceId");
1271
+ if (!projectId || !environmentId || !serviceId) {
1272
+ return null;
1273
+ }
1274
+ const variables = Object.fromEntries(
1275
+ [
1276
+ "TREESEED_API_AUTH_APPROVAL_BASE_URL",
1277
+ "TREESEED_SITE_URL",
1278
+ "BETTER_AUTH_URL"
1279
+ ].map((key) => [key, configuredEnvValue(env, key)]).filter(([, value]) => value)
1280
+ );
1281
+ if (Object.keys(variables).length === 0) {
1282
+ return null;
1283
+ }
1284
+ await upsertRailwayVariables({
1285
+ projectId,
1286
+ environmentId,
1287
+ serviceId,
1288
+ variables,
1289
+ env
1290
+ });
1291
+ write ? write(`[${prefix.scope}][${prefix.system}][${prefix.task}][vars] Synced device login approval URL variables for ${service.serviceName ?? serviceId}.`, "stdout") : null;
1292
+ return { variables: Object.keys(variables) };
1293
+ }
1264
1294
  function buildRailwayLinkCommandEnv(env = process.env, service = {}) {
1265
1295
  return buildRailwayCliContextEnv({
1266
1296
  ...buildRailwayDeployCommandEnv({ ...env, RAILWAY_TOKEN: void 0 }),
@@ -1672,6 +1702,7 @@ async function deployRailwayService(tenantRoot, service, {
1672
1702
  serviceName: runtimeConfiguration?.serviceName ?? deployService.serviceName,
1673
1703
  railwayEnvironment: runtimeConfiguration?.environmentName ?? runtimeConfiguration?.environmentId ?? deployService.railwayEnvironment
1674
1704
  };
1705
+ await syncRailwayApiDeviceLoginVariables(cliDeployService, commandEnv, write, taskPrefix);
1675
1706
  railwayDeployEnv = buildRailwayCliContextEnv(railwayDeployEnv, cliDeployService);
1676
1707
  const hasCommandApiToken = Boolean(configuredEnvValue(commandEnv, "RAILWAY_API_TOKEN"));
1677
1708
  let usesProjectToken = Boolean(configuredEnvValue(railwayDeployEnv, "RAILWAY_TOKEN"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.8.14",
3
+ "version": "0.8.16",
4
4
  "description": "Shared Treeseed SDK for content-backed and D1-backed object models.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -58,6 +58,9 @@ __WORKING_DIRECTORY_BLOCK__ processing:
58
58
  TREESEED_API_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_API_WEB_SERVICE_SECRET }}
59
59
  TREESEED_API_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_API_WEB_ASSERTION_SECRET }}
60
60
  TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST: ${{ vars.TREESEED_API_BOOTSTRAP_ADMIN_ALLOWLIST }}
61
+ TREESEED_API_AUTH_APPROVAL_BASE_URL: ${{ vars.TREESEED_API_AUTH_APPROVAL_BASE_URL || vars.TREESEED_SITE_URL }}
62
+ TREESEED_SITE_URL: ${{ vars.TREESEED_SITE_URL }}
63
+ BETTER_AUTH_URL: ${{ vars.BETTER_AUTH_URL || vars.TREESEED_SITE_URL }}
61
64
  TREESEED_PROJECT_ID: ${{ inputs.project_id || vars.TREESEED_PROJECT_ID }}
62
65
  TREESEED_PROJECT_RUNNER_TOKEN: ${{ secrets.TREESEED_PROJECT_RUNNER_TOKEN }}
63
66
  TREESEED_WORKER_POOL_SCALER: ${{ vars.TREESEED_WORKER_POOL_SCALER }}
@@ -68,6 +68,8 @@ __WORKING_DIRECTORY_BLOCK__ web:
68
68
  TREESEED_WEB_SERVICE_SECRET: ${{ secrets.TREESEED_WEB_SERVICE_SECRET }}
69
69
  TREESEED_WEB_ASSERTION_SECRET: ${{ secrets.TREESEED_WEB_ASSERTION_SECRET }}
70
70
  TREESEED_WEB_CSRF_SECRET: ${{ secrets.TREESEED_WEB_CSRF_SECRET }}
71
+ TREESEED_SITE_URL: ${{ vars.TREESEED_SITE_URL }}
72
+ BETTER_AUTH_URL: ${{ vars.BETTER_AUTH_URL || vars.TREESEED_SITE_URL }}
71
73
  TREESEED_CENTRAL_MARKET_API_BASE_URL: ${{ vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
72
74
  TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
73
75
  TREESEED_CATALOG_MARKET_API_BASE_URLS: ${{ vars.TREESEED_CATALOG_MARKET_API_BASE_URLS || vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}