@treeseed/sdk 0.6.26 → 0.6.28
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 +1 -0
- package/dist/index.js +43 -1
- package/dist/market-client.d.ts +195 -0
- package/dist/market-client.js +431 -0
- package/dist/operations/services/deploy.d.ts +2 -0
- package/dist/operations/services/deploy.js +4 -1
- package/dist/platform/env.yaml +53 -3
- package/dist/platform/environment.js +11 -2
- package/package.json +5 -1
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
|
-
|
|
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")));
|
package/dist/platform/env.yaml
CHANGED
|
@@ -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:
|
|
372
|
-
howToGet:
|
|
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.
|
|
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.
|
|
3
|
+
"version": "0.6.28",
|
|
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"
|