@treeseed/sdk 0.6.27 → 0.6.29

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.
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ export { resolveSdkRecordVersion } from './sdk-version.ts';
22
22
  export { normalizeAliasedRecord, preprocessAliasedRecord, resolveAliasedField, } from './field-aliases.ts';
23
23
  export { canonicalizeFrontmatter, normalizeFilterFields, normalizeMutationData, normalizeRecordToCanonicalShape, normalizeSortFields, readCanonicalFieldValue, resolveModelField, validateModelFieldAliases, } from './sdk-fields.ts';
24
24
  export { RemoteTemplateCatalogClient, parseTemplateCatalogResponse } from './template-catalog.ts';
25
+ export { MarketClient, MarketApiError, DEFAULT_TREESEED_MARKET_BASE_URL, TREESEED_CATALOG_MARKET_API_BASE_URLS_ENV, TREESEED_CENTRAL_MARKET_API_BASE_URL_ENV, TREESEED_MARKET_API_BASE_URL_ENV, addMarketProfile, clearMarketSession, listIntegratedMarketCatalog, loadMarketRegistryState, removeMarketProfile, resolveCatalogMarketProfiles, resolveDefaultCentralMarketBaseUrl, resolveIntegratedCatalogArtifactDownload, resolveMarketProfile, resolveMarketSession, setActiveMarketProfile, setMarketSession, verifyArtifactBytes, writeMarketRegistryState, } from './market-client.ts';
25
26
  export { TREESEED_REMOTE_CONTRACT_HEADER, TREESEED_REMOTE_CONTRACT_VERSION, CloudflareQueuePullClient, CloudflareQueuePushClient, RemoteTreeseedClient, RemoteTreeseedAuthClient, RemoteTreeseedDispatchClient, RemoteTreeseedJobsClient, RemoteTreeseedRunnerClient, RemoteTreeseedSdkClient, RemoteTreeseedOperationsClient, } from './remote.ts';
26
27
  export { TRESEED_OPERATION_SPECS, findTreeseedOperation, listTreeseedOperationNames, } from './operations-registry.ts';
27
28
  export { TreeseedOperationsSdk } from './operations/runtime.ts';
package/dist/index.js CHANGED
@@ -123,6 +123,28 @@ import {
123
123
  validateModelFieldAliases
124
124
  } from "./sdk-fields.js";
125
125
  import { RemoteTemplateCatalogClient, parseTemplateCatalogResponse } from "./template-catalog.js";
126
+ import {
127
+ MarketClient,
128
+ MarketApiError,
129
+ DEFAULT_TREESEED_MARKET_BASE_URL,
130
+ TREESEED_CATALOG_MARKET_API_BASE_URLS_ENV,
131
+ TREESEED_CENTRAL_MARKET_API_BASE_URL_ENV,
132
+ TREESEED_MARKET_API_BASE_URL_ENV,
133
+ addMarketProfile,
134
+ clearMarketSession,
135
+ listIntegratedMarketCatalog,
136
+ loadMarketRegistryState,
137
+ removeMarketProfile,
138
+ resolveCatalogMarketProfiles,
139
+ resolveDefaultCentralMarketBaseUrl,
140
+ resolveIntegratedCatalogArtifactDownload,
141
+ resolveMarketProfile,
142
+ resolveMarketSession,
143
+ setActiveMarketProfile,
144
+ setMarketSession,
145
+ verifyArtifactBytes,
146
+ writeMarketRegistryState
147
+ } from "./market-client.js";
126
148
  import {
127
149
  TREESEED_REMOTE_CONTRACT_HEADER,
128
150
  TREESEED_REMOTE_CONTRACT_VERSION,
@@ -164,6 +186,7 @@ export {
164
186
  ContentGraphRuntime,
165
187
  ControlPlaneClient,
166
188
  DEFAULT_GRAPH_RANKING_PROVIDER,
189
+ DEFAULT_TREESEED_MARKET_BASE_URL,
167
190
  EDITORIAL_PREVIEW_COOKIE,
168
191
  KNOWLEDGE_COOP_AGENT_MESSAGE_KINDS,
169
192
  KNOWLEDGE_COOP_JOB_STATUSES,
@@ -172,6 +195,8 @@ export {
172
195
  KNOWLEDGE_COOP_TEAM_CAPABILITIES,
173
196
  KNOWLEDGE_COOP_WORKSTREAM_STATES,
174
197
  MODEL_REGISTRY,
198
+ MarketApiError,
199
+ MarketClient,
175
200
  PUBLISHED_CONTENT_MANIFEST_SCHEMA_VERSION,
176
201
  RemoteTemplateCatalogClient,
177
202
  RemoteTreeseedAuthClient,
@@ -182,6 +207,9 @@ export {
182
207
  RemoteTreeseedRunnerClient,
183
208
  RemoteTreeseedSdkClient,
184
209
  ScopedAgentSdk,
210
+ TREESEED_CATALOG_MARKET_API_BASE_URLS_ENV,
211
+ TREESEED_CENTRAL_MARKET_API_BASE_URL_ENV,
212
+ TREESEED_MARKET_API_BASE_URL_ENV,
185
213
  TREESEED_REMOTE_CONTRACT_HEADER,
186
214
  TREESEED_REMOTE_CONTRACT_VERSION,
187
215
  TRESEED_OPERATION_SPECS,
@@ -189,6 +217,7 @@ export {
189
217
  TeamScopedR2OverlayContentRuntimeProvider,
190
218
  TreeseedOperationsSdk,
191
219
  TreeseedWorkflowSdk,
220
+ addMarketProfile,
192
221
  buildBuiltinModelRegistry,
193
222
  buildCopilotAllowToolArgs,
194
223
  buildKnowledgeCoopKnowledgePackPackage,
@@ -196,6 +225,7 @@ export {
196
225
  buildModelRegistry,
197
226
  buildScopedModelRegistry,
198
227
  canonicalizeFrontmatter,
228
+ clearMarketSession,
199
229
  collectTreeseedDependencyStatus,
200
230
  collectTreeseedReconcileStatus,
201
231
  collectTreeseedToolStatus,
@@ -224,6 +254,7 @@ export {
224
254
  importKnowledgeCoopKnowledgePack,
225
255
  installTreeseedDependencies,
226
256
  isTeamScopedR2ContentEnabled,
257
+ listIntegratedMarketCatalog,
227
258
  listRailwayEnvironments,
228
259
  listRailwayProjects,
229
260
  listRailwayServices,
@@ -232,6 +263,7 @@ export {
232
263
  listSdkOperationNames,
233
264
  listTreeseedOperationNames,
234
265
  listWorkflowDispatchCapabilities,
266
+ loadMarketRegistryState,
235
267
  loadTreeseedManifest,
236
268
  loadTreeseedTenantManifest,
237
269
  mergeModelRegistries,
@@ -257,8 +289,14 @@ export {
257
289
  readPublishedContentManifest,
258
290
  readPublishedOverlayManifest,
259
291
  reconcileTreeseedTarget,
292
+ removeMarketProfile,
260
293
  resolveAliasedField,
294
+ resolveCatalogMarketProfiles,
261
295
  resolveCloudflareR2Bucket,
296
+ resolveDefaultCentralMarketBaseUrl,
297
+ resolveIntegratedCatalogArtifactDownload,
298
+ resolveMarketProfile,
299
+ resolveMarketSession,
262
300
  resolveModelDefinition,
263
301
  resolveModelField,
264
302
  resolvePublishedContentBucketBinding,
@@ -276,11 +314,15 @@ export {
276
314
  resolveTreeseedToolCommand,
277
315
  runTreeseedCopilotTask,
278
316
  runTreeseedVerifyDriver,
317
+ setActiveMarketProfile,
318
+ setMarketSession,
279
319
  signEditorialPreviewToken,
280
320
  tenantFeatureEnabled,
281
321
  tenantModelRendered,
282
322
  upsertRailwayVariables,
283
323
  validateKnowledgeCoopManagedLaunchPrerequisites,
284
324
  validateModelFieldAliases,
285
- verifyEditorialPreviewToken
325
+ verifyArtifactBytes,
326
+ verifyEditorialPreviewToken,
327
+ writeMarketRegistryState
286
328
  };
@@ -0,0 +1,195 @@
1
+ import type { ApiPrincipal, DeviceCodePollRequest, DeviceCodePollResponse, DeviceCodeStartRequest, DeviceCodeStartResponse, TokenRefreshRequest, TokenRefreshResponse } from './remote.ts';
2
+ export declare const DEFAULT_TREESEED_MARKET_BASE_URL = "https://api.treeseed.ai";
3
+ export declare const TREESEED_CENTRAL_MARKET_API_BASE_URL_ENV = "TREESEED_CENTRAL_MARKET_API_BASE_URL";
4
+ export declare const TREESEED_MARKET_API_BASE_URL_ENV = "TREESEED_MARKET_API_BASE_URL";
5
+ export declare const TREESEED_CATALOG_MARKET_API_BASE_URLS_ENV = "TREESEED_CATALOG_MARKET_API_BASE_URLS";
6
+ export type MarketProfileKind = 'central' | 'specialized';
7
+ export interface MarketProfile {
8
+ id: string;
9
+ label: string;
10
+ baseUrl: string;
11
+ kind: MarketProfileKind;
12
+ teamId?: string | null;
13
+ alwaysAvailable?: boolean;
14
+ }
15
+ export interface MarketSession {
16
+ marketId: string;
17
+ accessToken: string;
18
+ refreshToken?: string;
19
+ expiresAt?: string;
20
+ principal?: ApiPrincipal | null;
21
+ }
22
+ export interface MarketRegistryState {
23
+ version: 1;
24
+ activeMarketId: string;
25
+ profiles: MarketProfile[];
26
+ }
27
+ export interface TeamAccessSummary {
28
+ teamId: string;
29
+ roles: string[];
30
+ permissions: string[];
31
+ summary: {
32
+ canAdminStaging: boolean;
33
+ canAdminProduction: boolean;
34
+ canDownloadTemplates: boolean;
35
+ canDownloadKnowledgePacks: boolean;
36
+ };
37
+ }
38
+ export interface ProjectEnvironmentAccess {
39
+ projectId: string;
40
+ environment: 'staging' | 'prod' | string;
41
+ subjectType: 'user' | 'team_role' | 'api_key' | string;
42
+ subjectId: string;
43
+ role: 'viewer' | 'operator' | 'admin' | string;
44
+ }
45
+ export interface CatalogArtifactDownload {
46
+ itemId: string;
47
+ slug?: string;
48
+ kind: string;
49
+ version: string;
50
+ contentType: string;
51
+ sha256?: string | null;
52
+ downloadUrl: string;
53
+ expiresAt?: string | null;
54
+ installStrategy?: string | null;
55
+ }
56
+ export interface MarketCatalogSource {
57
+ id: string;
58
+ label: string;
59
+ baseUrl: string;
60
+ kind: MarketProfileKind;
61
+ teamId?: string | null;
62
+ }
63
+ export type MarketSourcedCatalogItem<T extends Record<string, unknown> = Record<string, unknown>> = T & {
64
+ sourceMarket: MarketCatalogSource;
65
+ };
66
+ export type MarketSourcedCatalogArtifactDownload = CatalogArtifactDownload & {
67
+ sourceMarket: MarketCatalogSource;
68
+ };
69
+ export interface IntegratedMarketCatalogResult<T extends Record<string, unknown> = Record<string, unknown>> {
70
+ ok: true;
71
+ payload: Array<MarketSourcedCatalogItem<T>>;
72
+ errors: Array<{
73
+ market: MarketCatalogSource;
74
+ status?: number;
75
+ error: string;
76
+ }>;
77
+ }
78
+ export interface MarketClientOptions {
79
+ profile: MarketProfile;
80
+ accessToken?: string | null;
81
+ fetchImpl?: typeof fetch;
82
+ userAgent?: string;
83
+ }
84
+ export declare function resolveDefaultCentralMarketBaseUrl(env?: Record<string, string | undefined>): string;
85
+ export declare function loadMarketRegistryState(): MarketRegistryState;
86
+ export declare function writeMarketRegistryState(state: MarketRegistryState): MarketRegistryState;
87
+ export declare function addMarketProfile(profile: MarketProfile): MarketRegistryState;
88
+ export declare function removeMarketProfile(id: string): MarketRegistryState;
89
+ export declare function setActiveMarketProfile(id: string): MarketRegistryState;
90
+ export declare function resolveMarketProfile(selector?: string | null): MarketProfile;
91
+ export declare function resolveMarketSession(tenantRoot: string, marketId: string): MarketSession | null;
92
+ export declare function setMarketSession(tenantRoot: string, session: MarketSession): {
93
+ accessToken: string;
94
+ refreshToken: string;
95
+ expiresAt: any;
96
+ principal: any;
97
+ };
98
+ export declare function clearMarketSession(tenantRoot: string, marketId?: string | null): {
99
+ version: number;
100
+ sessions: {
101
+ [k: string]: {
102
+ accessToken: string;
103
+ refreshToken: string;
104
+ expiresAt: any;
105
+ principal: any;
106
+ };
107
+ };
108
+ };
109
+ export declare function resolveCatalogMarketProfiles(selector?: string | null, env?: Record<string, string | undefined>): MarketProfile[];
110
+ export declare class MarketApiError extends Error {
111
+ readonly status: number;
112
+ readonly payload: unknown;
113
+ constructor(message: string, status: number, payload: unknown);
114
+ }
115
+ export declare class MarketClient {
116
+ readonly options: MarketClientOptions;
117
+ private readonly baseUrl;
118
+ private readonly accessToken;
119
+ private readonly fetchImpl;
120
+ private readonly userAgent?;
121
+ constructor(options: MarketClientOptions);
122
+ private request;
123
+ startDeviceLogin(request: DeviceCodeStartRequest): Promise<DeviceCodeStartResponse>;
124
+ pollDeviceLogin(request: DeviceCodePollRequest): Promise<DeviceCodePollResponse>;
125
+ refreshToken(request: TokenRefreshRequest): Promise<TokenRefreshResponse>;
126
+ logout(): Promise<{
127
+ ok: true;
128
+ }>;
129
+ me(): Promise<{
130
+ ok: true;
131
+ payload: {
132
+ principal: ApiPrincipal;
133
+ teams: unknown[];
134
+ };
135
+ }>;
136
+ markets(): Promise<{
137
+ ok: true;
138
+ payload: MarketProfile[];
139
+ }>;
140
+ currentMarket(): Promise<{
141
+ ok: true;
142
+ payload: MarketProfile;
143
+ }>;
144
+ teams(): Promise<{
145
+ ok: true;
146
+ payload: unknown[];
147
+ }>;
148
+ teamMembers(teamId: string): Promise<{
149
+ ok: true;
150
+ payload: unknown[];
151
+ }>;
152
+ teamPermissions(teamId: string): Promise<{
153
+ ok: true;
154
+ payload: TeamAccessSummary;
155
+ }>;
156
+ projects(teamId?: string | null): Promise<{
157
+ ok: true;
158
+ payload: unknown[];
159
+ }>;
160
+ projectAccess(projectId: string): Promise<{
161
+ ok: true;
162
+ payload: {
163
+ projectId: string;
164
+ team: TeamAccessSummary;
165
+ environments: ProjectEnvironmentAccess[];
166
+ };
167
+ }>;
168
+ catalog(kind?: string | null): Promise<{
169
+ ok: true;
170
+ payload: unknown[];
171
+ }>;
172
+ artifactDownload(itemId: string, version: string): Promise<{
173
+ ok: true;
174
+ payload: CatalogArtifactDownload;
175
+ }>;
176
+ }
177
+ export declare function listIntegratedMarketCatalog<T extends Record<string, unknown> = Record<string, unknown>>({ kind, selector, authRoot, fetchImpl, userAgent, }: {
178
+ kind?: string | null;
179
+ selector?: string | null;
180
+ authRoot?: string | null;
181
+ fetchImpl?: typeof fetch;
182
+ userAgent?: string;
183
+ }): Promise<IntegratedMarketCatalogResult<T>>;
184
+ export declare function resolveIntegratedCatalogArtifactDownload({ itemId, version, selector, authRoot, fetchImpl, userAgent, }: {
185
+ itemId: string;
186
+ version: string;
187
+ selector?: string | null;
188
+ authRoot?: string | null;
189
+ fetchImpl?: typeof fetch;
190
+ userAgent?: string;
191
+ }): Promise<{
192
+ ok: true;
193
+ payload: MarketSourcedCatalogArtifactDownload;
194
+ }>;
195
+ export declare function verifyArtifactBytes(response: Response, expectedSha256?: string | null): Promise<Uint8Array<ArrayBuffer>>;
@@ -0,0 +1,431 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { dirname, resolve } from "node:path";
5
+ import {
6
+ TREESEED_REMOTE_CONTRACT_HEADER,
7
+ TREESEED_REMOTE_CONTRACT_VERSION
8
+ } from "./remote.js";
9
+ import {
10
+ resolveTreeseedRemoteSession,
11
+ setTreeseedRemoteSession,
12
+ clearTreeseedRemoteSession
13
+ } from "./operations/services/config-runtime.js";
14
+ const DEFAULT_TREESEED_MARKET_BASE_URL = "https://api.treeseed.ai";
15
+ const TREESEED_CENTRAL_MARKET_API_BASE_URL_ENV = "TREESEED_CENTRAL_MARKET_API_BASE_URL";
16
+ const TREESEED_MARKET_API_BASE_URL_ENV = "TREESEED_MARKET_API_BASE_URL";
17
+ const TREESEED_CATALOG_MARKET_API_BASE_URLS_ENV = "TREESEED_CATALOG_MARKET_API_BASE_URLS";
18
+ const MARKET_REGISTRY_RELATIVE_PATH = ".treeseed/config/markets.json";
19
+ function envValue(name, env = process.env) {
20
+ return typeof env[name] === "string" && env[name].trim().length > 0 ? env[name].trim() : null;
21
+ }
22
+ function resolveDefaultCentralMarketBaseUrl(env = process.env) {
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
25
+ );
26
+ }
27
+ function defaultCentralMarket() {
28
+ return {
29
+ id: "central",
30
+ label: "TreeSeed Central Market",
31
+ baseUrl: resolveDefaultCentralMarketBaseUrl(),
32
+ kind: "central",
33
+ alwaysAvailable: true
34
+ };
35
+ }
36
+ function homeConfigPath() {
37
+ const homeRoot = process.env.HOME && process.env.HOME.trim().length > 0 ? process.env.HOME : homedir();
38
+ return resolve(homeRoot, MARKET_REGISTRY_RELATIVE_PATH);
39
+ }
40
+ function normalizeBaseUrl(baseUrl) {
41
+ return baseUrl.trim().replace(/\/+$/u, "");
42
+ }
43
+ function normalizeProfile(profile) {
44
+ return {
45
+ ...profile,
46
+ id: profile.id.trim(),
47
+ label: profile.label.trim() || profile.id.trim(),
48
+ baseUrl: normalizeBaseUrl(profile.baseUrl),
49
+ kind: profile.kind === "specialized" ? "specialized" : "central",
50
+ teamId: profile.teamId ?? null,
51
+ alwaysAvailable: profile.alwaysAvailable === true || profile.id === "central"
52
+ };
53
+ }
54
+ function uniqueProfiles(profiles) {
55
+ const byId = /* @__PURE__ */ new Map();
56
+ for (const profile of [defaultCentralMarket(), ...profiles].map(normalizeProfile)) {
57
+ if (profile.id === "central") {
58
+ profile.baseUrl = resolveDefaultCentralMarketBaseUrl();
59
+ profile.label = profile.label || "TreeSeed Central Market";
60
+ profile.kind = "central";
61
+ profile.alwaysAvailable = true;
62
+ }
63
+ byId.set(profile.id, profile);
64
+ }
65
+ return [...byId.values()].sort((left, right) => {
66
+ if (left.id === "central") return -1;
67
+ if (right.id === "central") return 1;
68
+ return left.id.localeCompare(right.id);
69
+ });
70
+ }
71
+ function loadMarketRegistryState() {
72
+ const path = homeConfigPath();
73
+ if (!existsSync(path)) {
74
+ return {
75
+ version: 1,
76
+ activeMarketId: "central",
77
+ profiles: [defaultCentralMarket()]
78
+ };
79
+ }
80
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
81
+ const profiles = uniqueProfiles(Array.isArray(parsed.profiles) ? parsed.profiles : []);
82
+ const activeMarketId = typeof parsed.activeMarketId === "string" && profiles.some((profile) => profile.id === parsed.activeMarketId) ? parsed.activeMarketId : "central";
83
+ return {
84
+ version: 1,
85
+ activeMarketId,
86
+ profiles
87
+ };
88
+ }
89
+ function writeMarketRegistryState(state) {
90
+ const path = homeConfigPath();
91
+ mkdirSync(dirname(path), { recursive: true });
92
+ const profiles = uniqueProfiles(state.profiles);
93
+ const activeMarketId = profiles.some((profile) => profile.id === state.activeMarketId) ? state.activeMarketId : "central";
94
+ const next = {
95
+ version: 1,
96
+ activeMarketId,
97
+ profiles
98
+ };
99
+ writeFileSync(path, `${JSON.stringify(next, null, 2)}
100
+ `, "utf8");
101
+ return next;
102
+ }
103
+ function addMarketProfile(profile) {
104
+ const state = loadMarketRegistryState();
105
+ return writeMarketRegistryState({
106
+ ...state,
107
+ profiles: uniqueProfiles([...state.profiles, profile])
108
+ });
109
+ }
110
+ function removeMarketProfile(id) {
111
+ if (id === "central") {
112
+ throw new Error("The central market profile cannot be removed.");
113
+ }
114
+ const state = loadMarketRegistryState();
115
+ return writeMarketRegistryState({
116
+ ...state,
117
+ activeMarketId: state.activeMarketId === id ? "central" : state.activeMarketId,
118
+ profiles: state.profiles.filter((profile) => profile.id !== id)
119
+ });
120
+ }
121
+ function setActiveMarketProfile(id) {
122
+ const state = loadMarketRegistryState();
123
+ if (!state.profiles.some((profile) => profile.id === id)) {
124
+ throw new Error(`Unknown market profile "${id}".`);
125
+ }
126
+ return writeMarketRegistryState({
127
+ ...state,
128
+ activeMarketId: id
129
+ });
130
+ }
131
+ function resolveMarketProfile(selector) {
132
+ const state = loadMarketRegistryState();
133
+ const trimmed = selector?.trim();
134
+ if (trimmed && /^https?:\/\//iu.test(trimmed)) {
135
+ return {
136
+ id: trimmed.replace(/^https?:\/\//iu, "").replace(/[^A-Za-z0-9._-]+/gu, "-").replace(/^-+|-+$/gu, "") || "market",
137
+ label: trimmed,
138
+ baseUrl: normalizeBaseUrl(trimmed),
139
+ kind: "specialized",
140
+ alwaysAvailable: false
141
+ };
142
+ }
143
+ const marketId = trimmed || state.activeMarketId || "central";
144
+ const profile = state.profiles.find((entry) => entry.id === marketId);
145
+ if (!profile) {
146
+ throw new Error(`Unknown market profile "${marketId}".`);
147
+ }
148
+ return profile;
149
+ }
150
+ function resolveMarketSession(tenantRoot, marketId) {
151
+ const session = resolveTreeseedRemoteSession(tenantRoot, marketId);
152
+ return session?.accessToken ? {
153
+ marketId,
154
+ accessToken: session.accessToken,
155
+ refreshToken: session.refreshToken,
156
+ expiresAt: session.expiresAt,
157
+ principal: session.principal ?? null
158
+ } : null;
159
+ }
160
+ function setMarketSession(tenantRoot, session) {
161
+ return setTreeseedRemoteSession(tenantRoot, {
162
+ hostId: session.marketId,
163
+ accessToken: session.accessToken,
164
+ refreshToken: session.refreshToken ?? "",
165
+ expiresAt: session.expiresAt ?? "",
166
+ principal: session.principal ?? null
167
+ });
168
+ }
169
+ function clearMarketSession(tenantRoot, marketId) {
170
+ return clearTreeseedRemoteSession(tenantRoot, marketId ?? void 0);
171
+ }
172
+ function profileToSource(profile) {
173
+ return {
174
+ id: profile.id,
175
+ label: profile.label,
176
+ baseUrl: profile.baseUrl,
177
+ kind: profile.kind,
178
+ teamId: profile.teamId ?? null
179
+ };
180
+ }
181
+ function catalogProfileIdForUrl(baseUrl) {
182
+ const id = normalizeBaseUrl(baseUrl).replace(/^https?:\/\//iu, "").replace(/[^A-Za-z0-9._-]+/gu, "-").replace(/^-+|-+$/gu, "");
183
+ return id ? `catalog-${id}` : "catalog-market";
184
+ }
185
+ function parseCatalogMarketBaseUrls(env = process.env) {
186
+ const raw = envValue(TREESEED_CATALOG_MARKET_API_BASE_URLS_ENV, env);
187
+ if (!raw) return [];
188
+ return raw.split(/[\s,]+/u).map((value) => value.trim()).filter(Boolean);
189
+ }
190
+ function resolveCatalogMarketProfiles(selector, env = process.env) {
191
+ if (selector?.trim()) {
192
+ return [resolveMarketProfile(selector)];
193
+ }
194
+ const state = loadMarketRegistryState();
195
+ const byKey = /* @__PURE__ */ new Map();
196
+ for (const profile of uniqueProfiles(state.profiles)) {
197
+ byKey.set(normalizeBaseUrl(profile.baseUrl), profile);
198
+ }
199
+ for (const baseUrl of parseCatalogMarketBaseUrls(env)) {
200
+ const normalized = normalizeBaseUrl(baseUrl);
201
+ if (!byKey.has(normalized)) {
202
+ byKey.set(normalized, {
203
+ id: catalogProfileIdForUrl(normalized),
204
+ label: normalized,
205
+ baseUrl: normalized,
206
+ kind: normalized === resolveDefaultCentralMarketBaseUrl(env) ? "central" : "specialized",
207
+ alwaysAvailable: normalized === resolveDefaultCentralMarketBaseUrl(env)
208
+ });
209
+ }
210
+ }
211
+ return [...byKey.values()].sort((left, right) => {
212
+ if (left.id === "central") return -1;
213
+ if (right.id === "central") return 1;
214
+ return left.id.localeCompare(right.id);
215
+ });
216
+ }
217
+ class MarketApiError extends Error {
218
+ constructor(message, status, payload) {
219
+ super(message);
220
+ this.status = status;
221
+ this.payload = payload;
222
+ this.name = "MarketApiError";
223
+ }
224
+ status;
225
+ payload;
226
+ }
227
+ class MarketClient {
228
+ constructor(options) {
229
+ this.options = options;
230
+ this.baseUrl = normalizeBaseUrl(options.profile.baseUrl);
231
+ this.accessToken = options.accessToken ?? null;
232
+ this.fetchImpl = options.fetchImpl ?? fetch;
233
+ this.userAgent = options.userAgent;
234
+ }
235
+ options;
236
+ baseUrl;
237
+ accessToken;
238
+ fetchImpl;
239
+ userAgent;
240
+ async request(path, options = {}) {
241
+ const headers = {
242
+ accept: "application/json",
243
+ [TREESEED_REMOTE_CONTRACT_HEADER]: String(TREESEED_REMOTE_CONTRACT_VERSION)
244
+ };
245
+ if (this.userAgent) {
246
+ headers["user-agent"] = this.userAgent;
247
+ }
248
+ if (options.body !== void 0) {
249
+ headers["content-type"] = "application/json";
250
+ }
251
+ if ((options.requireAuth ?? false) && this.accessToken) {
252
+ headers.authorization = `Bearer ${this.accessToken}`;
253
+ }
254
+ const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
255
+ method: options.method ?? "GET",
256
+ headers,
257
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body)
258
+ });
259
+ const payload = await response.json().catch(() => ({}));
260
+ if (!response.ok) {
261
+ const error = typeof payload.error === "string" ? String(payload.error) : `Market request failed with ${response.status}.`;
262
+ throw new MarketApiError(error, response.status, payload);
263
+ }
264
+ return payload;
265
+ }
266
+ startDeviceLogin(request) {
267
+ return this.request("/v1/auth/device/start", {
268
+ method: "POST",
269
+ body: request
270
+ });
271
+ }
272
+ pollDeviceLogin(request) {
273
+ return this.request("/v1/auth/device/poll", {
274
+ method: "POST",
275
+ body: request
276
+ });
277
+ }
278
+ refreshToken(request) {
279
+ return this.request("/v1/auth/token/refresh", {
280
+ method: "POST",
281
+ body: request
282
+ });
283
+ }
284
+ logout() {
285
+ return this.request("/v1/auth/logout", {
286
+ method: "POST",
287
+ requireAuth: true
288
+ });
289
+ }
290
+ me() {
291
+ return this.request("/v1/me", { requireAuth: true });
292
+ }
293
+ markets() {
294
+ return this.request("/v1/me/markets", { requireAuth: true });
295
+ }
296
+ currentMarket() {
297
+ return this.request("/v1/markets/current");
298
+ }
299
+ teams() {
300
+ return this.request("/v1/teams", { requireAuth: true });
301
+ }
302
+ teamMembers(teamId) {
303
+ return this.request(`/v1/teams/${encodeURIComponent(teamId)}/members`, { requireAuth: true });
304
+ }
305
+ teamPermissions(teamId) {
306
+ return this.request(`/v1/teams/${encodeURIComponent(teamId)}/permissions`, { requireAuth: true });
307
+ }
308
+ projects(teamId) {
309
+ const query = teamId ? `?teamId=${encodeURIComponent(teamId)}` : "";
310
+ return this.request(`/v1/projects${query}`, { requireAuth: true });
311
+ }
312
+ projectAccess(projectId) {
313
+ return this.request(
314
+ `/v1/projects/${encodeURIComponent(projectId)}/access`,
315
+ { requireAuth: true }
316
+ );
317
+ }
318
+ catalog(kind) {
319
+ const query = kind ? `?kind=${encodeURIComponent(kind)}` : "";
320
+ return this.request(`/v1/catalog${query}`, { requireAuth: Boolean(this.accessToken) });
321
+ }
322
+ artifactDownload(itemId, version) {
323
+ return this.request(
324
+ `/v1/catalog/${encodeURIComponent(itemId)}/artifacts/${encodeURIComponent(version)}/download`,
325
+ { requireAuth: Boolean(this.accessToken) }
326
+ );
327
+ }
328
+ }
329
+ async function listIntegratedMarketCatalog({
330
+ kind,
331
+ selector,
332
+ authRoot,
333
+ fetchImpl,
334
+ userAgent
335
+ }) {
336
+ const payload = [];
337
+ const errors = [];
338
+ for (const profile of resolveCatalogMarketProfiles(selector)) {
339
+ const session = authRoot ? resolveMarketSession(authRoot, profile.id) : null;
340
+ const client = new MarketClient({
341
+ profile,
342
+ accessToken: session?.accessToken ?? null,
343
+ fetchImpl,
344
+ userAgent
345
+ });
346
+ try {
347
+ const response = await client.catalog(kind);
348
+ for (const item of response.payload) {
349
+ payload.push({
350
+ ...item,
351
+ sourceMarket: profileToSource(profile)
352
+ });
353
+ }
354
+ } catch (error) {
355
+ errors.push({
356
+ market: profileToSource(profile),
357
+ status: error instanceof MarketApiError ? error.status : void 0,
358
+ error: error instanceof Error ? error.message : String(error)
359
+ });
360
+ }
361
+ }
362
+ return { ok: true, payload, errors };
363
+ }
364
+ async function resolveIntegratedCatalogArtifactDownload({
365
+ itemId,
366
+ version,
367
+ selector,
368
+ authRoot,
369
+ fetchImpl,
370
+ userAgent
371
+ }) {
372
+ const errors = [];
373
+ for (const profile of resolveCatalogMarketProfiles(selector)) {
374
+ const session = authRoot ? resolveMarketSession(authRoot, profile.id) : null;
375
+ const client = new MarketClient({
376
+ profile,
377
+ accessToken: session?.accessToken ?? null,
378
+ fetchImpl,
379
+ userAgent
380
+ });
381
+ try {
382
+ const response = await client.artifactDownload(itemId, version);
383
+ return {
384
+ ok: true,
385
+ payload: {
386
+ ...response.payload,
387
+ sourceMarket: profileToSource(profile)
388
+ }
389
+ };
390
+ } catch (error) {
391
+ if (error instanceof MarketApiError && error.status === 404) {
392
+ continue;
393
+ }
394
+ errors.push(`${profile.id}: ${error instanceof Error ? error.message : String(error)}`);
395
+ }
396
+ }
397
+ const suffix = errors.length > 0 ? ` Errors: ${errors.join("; ")}` : "";
398
+ throw new Error(`Catalog artifact "${itemId}" version "${version}" was not found in the selected market catalogs.${suffix}`);
399
+ }
400
+ async function verifyArtifactBytes(response, expectedSha256) {
401
+ const bytes = new Uint8Array(await response.arrayBuffer());
402
+ if (expectedSha256) {
403
+ const actual = createHash("sha256").update(bytes).digest("hex");
404
+ if (actual !== expectedSha256) {
405
+ throw new Error(`Artifact checksum mismatch. Expected ${expectedSha256}, received ${actual}.`);
406
+ }
407
+ }
408
+ return bytes;
409
+ }
410
+ export {
411
+ DEFAULT_TREESEED_MARKET_BASE_URL,
412
+ MarketApiError,
413
+ MarketClient,
414
+ TREESEED_CATALOG_MARKET_API_BASE_URLS_ENV,
415
+ TREESEED_CENTRAL_MARKET_API_BASE_URL_ENV,
416
+ TREESEED_MARKET_API_BASE_URL_ENV,
417
+ addMarketProfile,
418
+ clearMarketSession,
419
+ listIntegratedMarketCatalog,
420
+ loadMarketRegistryState,
421
+ removeMarketProfile,
422
+ resolveCatalogMarketProfiles,
423
+ resolveDefaultCentralMarketBaseUrl,
424
+ resolveIntegratedCatalogArtifactDownload,
425
+ resolveMarketProfile,
426
+ resolveMarketSession,
427
+ setActiveMarketProfile,
428
+ setMarketSession,
429
+ verifyArtifactBytes,
430
+ writeMarketRegistryState
431
+ };
@@ -26,7 +26,9 @@ export declare function buildPublicVars(deployConfig: any): {
26
26
  TREESEED_HUB_MODE: any;
27
27
  TREESEED_RUNTIME_MODE: any;
28
28
  TREESEED_RUNTIME_REGISTRATION: any;
29
+ TREESEED_CENTRAL_MARKET_API_BASE_URL: string;
29
30
  TREESEED_MARKET_API_BASE_URL: any;
31
+ TREESEED_CATALOG_MARKET_API_BASE_URLS: any;
30
32
  TREESEED_HOSTING_TEAM_ID: string;
31
33
  TREESEED_PROJECT_ID: string;
32
34
  TREESEED_AGENT_EXECUTION_PROVIDER: any;
@@ -8,6 +8,7 @@ import { normalizeRailwayEnvironmentName } from "./railway-api.js";
8
8
  import { loadCliDeployConfig, resolveWranglerBin } from "./runtime-tools.js";
9
9
  const DEFAULT_COMPATIBILITY_DATE = "2026-04-05";
10
10
  const DEFAULT_COMPATIBILITY_FLAGS = ["nodejs_compat"];
11
+ const DEFAULT_TREESEED_MARKET_BASE_URL = "https://api.treeseed.ai";
11
12
  const GENERATED_ROOT = ".treeseed/generated";
12
13
  const STATE_ROOT = ".treeseed/state";
13
14
  const WORKTREE_METADATA_RELATIVE_PATH = ".treeseed/worktree.json";
@@ -267,7 +268,9 @@ function buildPublicVars(deployConfig) {
267
268
  TREESEED_HUB_MODE: deployConfig.hub?.mode ?? "treeseed_hosted",
268
269
  TREESEED_RUNTIME_MODE: deployConfig.runtime?.mode ?? "none",
269
270
  TREESEED_RUNTIME_REGISTRATION: deployConfig.runtime?.registration ?? "none",
271
+ TREESEED_CENTRAL_MARKET_API_BASE_URL: envOrNull("TREESEED_CENTRAL_MARKET_API_BASE_URL") ?? DEFAULT_TREESEED_MARKET_BASE_URL,
270
272
  TREESEED_MARKET_API_BASE_URL: resolveConfiguredMarketBaseUrl(deployConfig),
273
+ TREESEED_CATALOG_MARKET_API_BASE_URLS: envOrNull("TREESEED_CATALOG_MARKET_API_BASE_URLS") ?? resolveConfiguredMarketBaseUrl(deployConfig),
271
274
  TREESEED_HOSTING_TEAM_ID: contentDefaultTeamId,
272
275
  TREESEED_PROJECT_ID: identity.projectId,
273
276
  TREESEED_AGENT_EXECUTION_PROVIDER: deployConfig.providers?.agents?.execution ?? "stub",
@@ -1405,7 +1408,7 @@ function resolveConfiguredCloudflareAccountId(deployConfig) {
1405
1408
  return envOrNull("CLOUDFLARE_ACCOUNT_ID") ?? deployConfig.cloudflare.accountId;
1406
1409
  }
1407
1410
  function resolveConfiguredMarketBaseUrl(deployConfig) {
1408
- return envOrNull("TREESEED_MARKET_API_BASE_URL") ?? deployConfig.runtime?.marketBaseUrl ?? deployConfig.hosting?.marketBaseUrl ?? "";
1411
+ return envOrNull("TREESEED_MARKET_API_BASE_URL") ?? envOrNull("TREESEED_CENTRAL_MARKET_API_BASE_URL") ?? deployConfig.runtime?.marketBaseUrl ?? deployConfig.hosting?.marketBaseUrl ?? DEFAULT_TREESEED_MARKET_BASE_URL;
1409
1412
  }
1410
1413
  function resolveConfiguredPagesProjectName(deployConfig) {
1411
1414
  return sharedDeploymentName(resolveTreeseedResourceIdentity(deployConfig, createPersistentDeployTarget("prod")));
@@ -365,11 +365,36 @@ entries:
365
365
  - process-env
366
366
  - treeseed.site.yaml
367
367
  defaultValueRef: hostingRegistrationDefault
368
+ TREESEED_CENTRAL_MARKET_API_BASE_URL:
369
+ label: Treeseed central market API base URL
370
+ group: hosting
371
+ description: Base URL for the always-available central TreeSeed market used when no team-specific specialized market is selected.
372
+ howToGet: The production TreeSeed market defaults to https://api.treeseed.ai. Set this only when an environment should use another central-compatible market endpoint.
373
+ sensitivity: plain
374
+ targets:
375
+ - github-variable
376
+ - railway-var
377
+ - config-file
378
+ scopes:
379
+ - staging
380
+ - prod
381
+ storage: shared
382
+ requirement: optional
383
+ purposes:
384
+ - deploy
385
+ - config
386
+ validation:
387
+ kind: url
388
+ sourcePriority:
389
+ - machine-config
390
+ - process-env
391
+ - treeseed.site.yaml
392
+ defaultValueRef: centralMarketBaseUrlDefault
368
393
  TREESEED_MARKET_API_BASE_URL:
369
- label: Treeseed market API base URL
394
+ label: Treeseed default market API base URL
370
395
  group: hosting
371
- description: Base URL for the market control-plane API used by hosted and optionally registered self-hosted project platforms.
372
- howToGet: Use the hosted market API URL if Treeseed manages the project for you. Self-hosted deployments should only set this when registration with the market control plane is enabled.
396
+ description: Primary market control-plane API URL used by hosted and optionally registered self-hosted project platforms.
397
+ howToGet: The production TreeSeed market defaults to https://api.treeseed.ai. Set this to a staging, enterprise, or specialized market endpoint when that environment should register with a different market.
373
398
  sensitivity: plain
374
399
  targets:
375
400
  - github-variable
@@ -391,6 +416,31 @@ entries:
391
416
  relevanceRef: projectRegistrationEnabled
392
417
  requiredWhenRef: projectRegistrationEnabled
393
418
  defaultValueRef: marketBaseUrlDefault
419
+ TREESEED_CATALOG_MARKET_API_BASE_URLS:
420
+ label: Treeseed catalog market API URLs
421
+ group: hosting
422
+ description: Comma-separated market API base URLs that contribute templates, knowledge packs, and shared resources to the integrated catalog.
423
+ howToGet: Start with the production TreeSeed market at https://api.treeseed.ai and add specialized team or enterprise market API URLs as needed.
424
+ sensitivity: plain
425
+ targets:
426
+ - github-variable
427
+ - railway-var
428
+ - config-file
429
+ scopes:
430
+ - staging
431
+ - prod
432
+ storage: shared
433
+ requirement: optional
434
+ purposes:
435
+ - deploy
436
+ - config
437
+ validation:
438
+ kind: string
439
+ sourcePriority:
440
+ - machine-config
441
+ - process-env
442
+ - treeseed.site.yaml
443
+ defaultValueRef: catalogMarketBaseUrlsDefault
394
444
  TREESEED_HOSTING_TEAM_ID:
395
445
  label: Hosted team ID
396
446
  group: hosting
@@ -36,6 +36,7 @@ function resolveCoreEnvironmentPath() {
36
36
  }
37
37
  const CORE_ENVIRONMENT_PATH = resolveCoreEnvironmentPath();
38
38
  const TENANT_ENVIRONMENT_OVERLAY_PATH = "src/env.yaml";
39
+ const DEFAULT_TREESEED_MARKET_BASE_URL = "https://api.treeseed.ai";
39
40
  function loadOptionalTenantConfig() {
40
41
  try {
41
42
  return loadTreeseedManifest();
@@ -189,7 +190,13 @@ function resolveContentBucketBinding(context) {
189
190
  return context.deployConfig.cloudflare.r2?.binding?.trim() || "TREESEED_CONTENT_BUCKET";
190
191
  }
191
192
  function resolveMarketBaseUrl(context, _scope, values = {}) {
192
- return values.TREESEED_API_BASE_URL?.trim() || context.deployConfig.services?.api?.environments?.prod?.baseUrl?.trim() || "https://api.treeseed.ai";
193
+ return values.TREESEED_MARKET_API_BASE_URL?.trim() || values.TREESEED_CENTRAL_MARKET_API_BASE_URL?.trim() || process.env.TREESEED_MARKET_API_BASE_URL?.trim() || process.env.TREESEED_CENTRAL_MARKET_API_BASE_URL?.trim() || context.deployConfig.runtime?.marketBaseUrl?.trim() || context.deployConfig.hosting?.marketBaseUrl?.trim() || DEFAULT_TREESEED_MARKET_BASE_URL;
194
+ }
195
+ function resolveCentralMarketBaseUrl(context, scope, values = {}) {
196
+ return values.TREESEED_CENTRAL_MARKET_API_BASE_URL?.trim() || process.env.TREESEED_CENTRAL_MARKET_API_BASE_URL?.trim() || resolveMarketBaseUrl(context, scope, values) || DEFAULT_TREESEED_MARKET_BASE_URL;
197
+ }
198
+ function resolveCatalogMarketBaseUrls(context, scope, values = {}) {
199
+ return values.TREESEED_CATALOG_MARKET_API_BASE_URLS?.trim() || values.TREESEED_MARKET_API_BASE_URL?.trim() || values.TREESEED_CENTRAL_MARKET_API_BASE_URL?.trim() || process.env.TREESEED_CATALOG_MARKET_API_BASE_URLS?.trim() || resolveCentralMarketBaseUrl(context, scope, values);
193
200
  }
194
201
  function resolveHostedTeamId(context) {
195
202
  return context.deployConfig.slug;
@@ -248,7 +255,9 @@ const VALUE_RESOLVERS = {
248
255
  hubModeDefault: (context) => resolveHubMode(context),
249
256
  runtimeModeDefault: (context) => resolveRuntimeMode(context),
250
257
  runtimeRegistrationDefault: (context) => resolveRuntimeRegistration(context),
251
- marketBaseUrlDefault: (context) => resolveMarketBaseUrl(context),
258
+ marketBaseUrlDefault: (context, scope, values) => resolveMarketBaseUrl(context, scope, values),
259
+ centralMarketBaseUrlDefault: (context, scope, values) => resolveCentralMarketBaseUrl(context, scope, values),
260
+ catalogMarketBaseUrlsDefault: (context, scope, values) => resolveCatalogMarketBaseUrls(context, scope, values),
252
261
  hostingTeamIdDefault: (context) => resolveHostedTeamId(context),
253
262
  hostingProjectIdDefault: (context) => resolveHostedProjectId(context),
254
263
  railwayWorkspaceDefault: () => resolveRailwayWorkspaceDefault(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.6.27",
3
+ "version": "0.6.29",
4
4
  "description": "Shared Treeseed SDK for content-backed and D1-backed object models.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -113,6 +113,10 @@
113
113
  "types": "./dist/workflow-support.d.ts",
114
114
  "default": "./dist/workflow-support.js"
115
115
  },
116
+ "./market-client": {
117
+ "types": "./dist/market-client.d.ts",
118
+ "default": "./dist/market-client.js"
119
+ },
116
120
  "./reconcile": {
117
121
  "types": "./dist/reconcile/index.d.ts",
118
122
  "default": "./dist/reconcile/index.js"
@@ -233,7 +233,9 @@ __WORKING_DIRECTORY_BLOCK__
233
233
  TREESEED_HOSTING_KIND: ${{ vars.TREESEED_HOSTING_KIND }}
234
234
  TREESEED_HOSTING_REGISTRATION: ${{ vars.TREESEED_HOSTING_REGISTRATION }}
235
235
  TREESEED_HOSTING_TEAM_ID: ${{ vars.TREESEED_HOSTING_TEAM_ID }}
236
- TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
236
+ TREESEED_CENTRAL_MARKET_API_BASE_URL: ${{ vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
237
+ TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
238
+ 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' }}
237
239
  TREESEED_PROJECT_DOMAINS: ${{ vars.TREESEED_PROJECT_DOMAINS }}
238
240
  TREESEED_API_BASE_URL: ${{ vars.TREESEED_API_BASE_URL }}
239
241
  TREESEED_BETTER_AUTH_SECRET: ${{ secrets.TREESEED_BETTER_AUTH_SECRET }}
@@ -379,7 +381,9 @@ __WORKING_DIRECTORY_BLOCK__
379
381
  TREESEED_HOSTING_KIND: ${{ vars.TREESEED_HOSTING_KIND }}
380
382
  TREESEED_HOSTING_REGISTRATION: ${{ vars.TREESEED_HOSTING_REGISTRATION }}
381
383
  TREESEED_HOSTING_TEAM_ID: ${{ vars.TREESEED_HOSTING_TEAM_ID }}
382
- TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
384
+ TREESEED_CENTRAL_MARKET_API_BASE_URL: ${{ vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
385
+ TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
386
+ 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' }}
383
387
  TREESEED_PROJECT_DOMAINS: ${{ vars.TREESEED_PROJECT_DOMAINS }}
384
388
  TREESEED_API_BASE_URL: ${{ vars.TREESEED_API_BASE_URL }}
385
389
  TREESEED_BETTER_AUTH_SECRET: ${{ secrets.TREESEED_BETTER_AUTH_SECRET }}
@@ -521,7 +525,9 @@ __WORKING_DIRECTORY_BLOCK__
521
525
  TREESEED_HOSTING_KIND: ${{ vars.TREESEED_HOSTING_KIND }}
522
526
  TREESEED_HOSTING_REGISTRATION: ${{ vars.TREESEED_HOSTING_REGISTRATION }}
523
527
  TREESEED_HOSTING_TEAM_ID: ${{ vars.TREESEED_HOSTING_TEAM_ID }}
524
- TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
528
+ TREESEED_CENTRAL_MARKET_API_BASE_URL: ${{ vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
529
+ TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
530
+ 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' }}
525
531
  TREESEED_PROJECT_DOMAINS: ${{ vars.TREESEED_PROJECT_DOMAINS }}
526
532
  TREESEED_API_BASE_URL: ${{ vars.TREESEED_API_BASE_URL }}
527
533
  TREESEED_BETTER_AUTH_SECRET: ${{ secrets.TREESEED_BETTER_AUTH_SECRET }}
@@ -652,7 +658,9 @@ __WORKING_DIRECTORY_BLOCK__
652
658
  TREESEED_HOSTING_KIND: ${{ vars.TREESEED_HOSTING_KIND }}
653
659
  TREESEED_HOSTING_REGISTRATION: ${{ vars.TREESEED_HOSTING_REGISTRATION }}
654
660
  TREESEED_HOSTING_TEAM_ID: ${{ vars.TREESEED_HOSTING_TEAM_ID }}
655
- TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL }}
661
+ TREESEED_CENTRAL_MARKET_API_BASE_URL: ${{ vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
662
+ TREESEED_MARKET_API_BASE_URL: ${{ vars.TREESEED_MARKET_API_BASE_URL || vars.TREESEED_CENTRAL_MARKET_API_BASE_URL || 'https://api.treeseed.ai' }}
663
+ 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' }}
656
664
  TREESEED_PROJECT_DOMAINS: ${{ vars.TREESEED_PROJECT_DOMAINS }}
657
665
  TREESEED_API_BASE_URL: ${{ vars.TREESEED_API_BASE_URL }}
658
666
  TREESEED_BETTER_AUTH_SECRET: ${{ secrets.TREESEED_BETTER_AUTH_SECRET }}