@triedotdev/mcp 1.0.173 → 1.0.174

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.
@@ -5,7 +5,7 @@ import {
5
5
  fetchLedger,
6
6
  fetchSignals,
7
7
  sessionCache
8
- } from "./chunk-QR64Y5TI.js";
8
+ } from "./chunk-7VFBLI2G.js";
9
9
 
10
10
  // src/server/mcp-server.ts
11
11
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -616,4 +616,4 @@ export {
616
616
  MCPServer,
617
617
  startServer
618
618
  };
619
- //# sourceMappingURL=chunk-2YXOBNKW.js.map
619
+ //# sourceMappingURL=chunk-2MIBCCPX.js.map
@@ -264,8 +264,15 @@ async function refreshAccessToken(apiBaseUrl, refreshToken) {
264
264
  if (!res.ok) {
265
265
  if (res.status === 401 || res.status === 403) {
266
266
  await clearCredentials();
267
+ throw new Error("Session expired. Run `trie login`.");
267
268
  }
268
- throw new Error("Session expired. Run `trie login`.");
269
+ let detail = `status ${res.status}`;
270
+ try {
271
+ const body = await res.json();
272
+ if (body?.error) detail = body.error;
273
+ } catch {
274
+ }
275
+ throw new Error(`Token refresh failed (${detail}). Try again or run \`trie login\`.`);
269
276
  }
270
277
  const data = await res.json();
271
278
  setAccessToken(data.access_token, data.expires_in);
@@ -360,4 +367,4 @@ export {
360
367
  fetchDocuments,
361
368
  fetchLedger
362
369
  };
363
- //# sourceMappingURL=chunk-QR64Y5TI.js.map
370
+ //# sourceMappingURL=chunk-7VFBLI2G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cache/session-cache.ts","../src/config/store.ts","../src/auth/session.ts","../src/auth/keychain.ts","../src/config/api-base-url.ts","../src/cloud/client.ts","../src/cloud/graph.ts","../src/cloud/signals.ts","../src/cloud/documents.ts","../src/cloud/ledger.ts"],"sourcesContent":["type CacheEntry<T> = {\n fetchedAt: number;\n data: T;\n};\n\nexport class SessionCache {\n private readonly cache = new Map<string, CacheEntry<unknown>>();\n\n async get<T>(key: string, ttlMs: number, fetcher: () => Promise<T>): Promise<T> {\n const hit = this.cache.get(key) as CacheEntry<T> | undefined;\n if (hit && Date.now() - hit.fetchedAt < ttlMs) {\n return hit.data;\n }\n const data = await fetcher();\n this.cache.set(key, { fetchedAt: Date.now(), data });\n return data;\n }\n\n invalidate(key: string): void {\n this.cache.delete(key);\n }\n\n invalidateAll(): void {\n this.cache.clear();\n }\n\n stats(): { size: number; keys: string[] } {\n return { size: this.cache.size, keys: [...this.cache.keys()] };\n }\n}\n\nexport const sessionCache = new SessionCache();\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport interface LocalConfig {\n apiBaseUrl: string;\n activeTeamId?: string;\n activeTeamName?: string;\n userEmail?: string;\n}\n\nconst DEFAULT_CONFIG: LocalConfig = {\n apiBaseUrl: process.env.TRIE_API_BASE_URL || \"https://trie-api.vercel.app\",\n};\n\nexport function getConfigDir(): string {\n return join(homedir(), \".trie\");\n}\n\nexport function getConfigPath(): string {\n return join(getConfigDir(), \"config.json\");\n}\n\nexport async function ensureConfigDir(): Promise<void> {\n await mkdir(getConfigDir(), { recursive: true });\n}\n\nexport async function loadLocalConfig(): Promise<LocalConfig> {\n const path = getConfigPath();\n if (!existsSync(path)) {\n return { ...DEFAULT_CONFIG };\n }\n try {\n const raw = await readFile(path, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<LocalConfig>;\n return { ...DEFAULT_CONFIG, ...parsed };\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport async function saveLocalConfig(next: LocalConfig): Promise<void> {\n await ensureConfigDir();\n const path = getConfigPath();\n await writeFile(path, `${JSON.stringify(next, null, 2)}\\n`, \"utf-8\");\n}\n","import { createHash } from \"node:crypto\";\nimport { hostname, platform, userInfo } from \"node:os\";\nimport { clearCredentials, loadCredentials, saveCredentials } from \"./keychain.js\";\nimport type { CliAuthTokens } from \"../types/index.js\";\nimport { loadLocalConfig, saveLocalConfig } from \"../config/store.js\";\nimport { normalizeAndValidateApiBaseUrl } from \"../config/api-base-url.js\";\n\nlet accessTokenCache: { token: string; expiresAt: number } | null = null;\nlet refreshAttempts: number[] = [];\n\nexport function getMachineFingerprint(): string {\n return createHash(\"sha256\")\n .update(`${hostname()}:${userInfo().username}:${platform()}:${process.arch}`)\n .digest(\"hex\");\n}\n\nfunction allowRefreshAttempt(): boolean {\n const now = Date.now();\n refreshAttempts = refreshAttempts.filter((t) => now - t < 60_000);\n if (refreshAttempts.length >= 5) return false;\n refreshAttempts.push(now);\n return true;\n}\n\nexport function setAccessToken(token: string, expiresIn: number): void {\n accessTokenCache = {\n token,\n expiresAt: Date.now() + Math.max(10, expiresIn - 300) * 1000,\n };\n}\n\nexport async function persistAuthTokens(tokens: CliAuthTokens): Promise<void> {\n if (tokens.refresh_token) {\n const credentialsPayload: {\n refreshToken: string;\n teamId?: string;\n teamName?: string;\n userEmail?: string;\n } = {\n refreshToken: tokens.refresh_token,\n };\n if (tokens.team?.id) credentialsPayload.teamId = tokens.team.id;\n if (tokens.team?.name) credentialsPayload.teamName = tokens.team.name;\n if (tokens.user?.email) credentialsPayload.userEmail = tokens.user.email;\n\n await saveCredentials({\n ...credentialsPayload,\n });\n }\n setAccessToken(tokens.access_token, tokens.expires_in);\n const cfg = await loadLocalConfig();\n const nextConfig = {\n ...cfg,\n };\n if (tokens.team?.id) nextConfig.activeTeamId = tokens.team.id;\n if (tokens.team?.name) nextConfig.activeTeamName = tokens.team.name;\n if (tokens.user?.email) nextConfig.userEmail = tokens.user.email;\n await saveLocalConfig({\n ...nextConfig,\n });\n}\n\nexport async function getAccessToken(apiBaseUrl: string): Promise<string> {\n if (accessTokenCache && Date.now() < accessTokenCache.expiresAt) {\n return accessTokenCache.token;\n }\n const creds = await loadCredentials();\n if (!creds) throw new Error(\"Not authenticated. Run `trie login`.\");\n const refreshed = await refreshAccessToken(apiBaseUrl, creds.refreshToken);\n return refreshed.access_token;\n}\n\nexport async function refreshAccessToken(\n apiBaseUrl: string,\n refreshToken: string,\n): Promise<CliAuthTokens> {\n const safeApiBaseUrl = normalizeAndValidateApiBaseUrl(apiBaseUrl);\n if (!allowRefreshAttempt()) {\n throw new Error(\"Refresh rate limited. Try again in a minute.\");\n }\n const res = await fetch(`${safeApiBaseUrl}/api/auth/cli/refresh`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n refresh_token: refreshToken,\n machine_fingerprint: getMachineFingerprint(),\n }),\n });\n if (!res.ok) {\n if (res.status === 401 || res.status === 403) {\n await clearCredentials();\n throw new Error(\"Session expired. Run `trie login`.\");\n }\n let detail = `status ${res.status}`;\n try {\n const body = (await res.json()) as { error?: string };\n if (body?.error) detail = body.error;\n } catch {}\n throw new Error(`Token refresh failed (${detail}). Try again or run \\`trie login\\`.`);\n }\n const data = (await res.json()) as CliAuthTokens;\n setAccessToken(data.access_token, data.expires_in);\n return data;\n}\n\nexport async function revokeSession(apiBaseUrl: string): Promise<void> {\n const safeApiBaseUrl = normalizeAndValidateApiBaseUrl(apiBaseUrl);\n const creds = await loadCredentials();\n if (creds) {\n await fetch(`${safeApiBaseUrl}/api/auth/cli/revoke`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: creds.refreshToken }),\n }).catch(() => undefined);\n }\n accessTokenCache = null;\n await clearCredentials();\n}\n","import { chmod, lstat, mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getConfigDir } from \"../config/store.js\";\n\nexport interface StoredCredentials {\n refreshToken: string;\n teamId?: string;\n teamName?: string;\n userEmail?: string;\n}\n\nconst SERVICE = \"dev.trie.cli\";\nconst ACCOUNT = \"default\";\nconst FALLBACK_FILE = \"credentials.json\";\nconst PERMS_PRIVATE = 0o600;\n\nfunction serialize(value: StoredCredentials): string {\n return JSON.stringify(value);\n}\n\nfunction parse(value: string): StoredCredentials | null {\n try {\n return JSON.parse(value) as StoredCredentials;\n } catch {\n return null;\n }\n}\n\nfunction getFallbackPath(): string {\n return join(getConfigDir(), FALLBACK_FILE);\n}\n\nasync function ensureSafeCredentialFile(path: string): Promise<void> {\n if (!existsSync(path)) return;\n const stats = await lstat(path);\n if (!stats.isFile() || stats.isSymbolicLink()) {\n throw new Error(\"Unsafe credentials file path detected.\");\n }\n}\n\nasync function loadKeytar() {\n try {\n const mod = await import(\"keytar\");\n return mod.default;\n } catch {\n return null;\n }\n}\n\nasync function saveFallback(value: StoredCredentials): Promise<void> {\n const configDir = getConfigDir();\n await mkdir(configDir, { recursive: true });\n const path = getFallbackPath();\n await ensureSafeCredentialFile(path);\n const tempPath = `${path}.tmp-${process.pid}-${Date.now()}`;\n await writeFile(tempPath, serialize(value), { encoding: \"utf-8\", mode: PERMS_PRIVATE, flag: \"w\" });\n await rename(tempPath, path);\n await chmod(path, PERMS_PRIVATE);\n}\n\nasync function loadFallback(): Promise<StoredCredentials | null> {\n const path = getFallbackPath();\n if (!existsSync(path)) return null;\n await ensureSafeCredentialFile(path);\n const stats = await lstat(path);\n if ((stats.mode & 0o077) !== 0) {\n await chmod(path, PERMS_PRIVATE);\n }\n const raw = await readFile(path, \"utf-8\");\n return parse(raw);\n}\n\nasync function clearFallback(): Promise<void> {\n const path = getFallbackPath();\n if (!existsSync(path)) return;\n await unlink(path).catch(() => undefined);\n}\n\nexport async function saveCredentials(value: StoredCredentials): Promise<void> {\n const keytar = await loadKeytar();\n if (keytar) {\n await keytar.setPassword(SERVICE, ACCOUNT, serialize(value));\n return;\n }\n await saveFallback(value);\n}\n\nexport async function loadCredentials(): Promise<StoredCredentials | null> {\n const keytar = await loadKeytar();\n if (keytar) {\n const raw = await keytar.getPassword(SERVICE, ACCOUNT);\n if (!raw) return null;\n return parse(raw);\n }\n return loadFallback();\n}\n\nexport async function clearCredentials(): Promise<void> {\n const keytar = await loadKeytar();\n if (keytar) {\n await keytar.deletePassword(SERVICE, ACCOUNT);\n return;\n }\n await clearFallback();\n}\n","const DEFAULT_ALLOWED_HOSTS = new Set([\n \"trie-api.vercel.app\",\n]);\n\nfunction readAllowedHosts(): Set<string> {\n const raw = process.env.TRIE_API_BASE_ALLOWLIST;\n if (!raw) return DEFAULT_ALLOWED_HOSTS;\n const hosts = raw\n .split(\",\")\n .map((part) => part.trim().toLowerCase())\n .filter(Boolean);\n return hosts.length > 0 ? new Set(hosts) : DEFAULT_ALLOWED_HOSTS;\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n return hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"::1\";\n}\n\nfunction allowInsecureLoopback(): boolean {\n return process.env.TRIE_ALLOW_INSECURE_LOCALHOST === \"1\";\n}\n\nexport function normalizeAndValidateApiBaseUrl(rawUrl: string): string {\n let parsed: URL;\n try {\n parsed = new URL(rawUrl);\n } catch {\n throw new Error(\"Invalid API base URL.\");\n }\n\n const protocol = parsed.protocol.toLowerCase();\n const hostname = parsed.hostname.toLowerCase();\n const hasPath = parsed.pathname !== \"/\" || parsed.search || parsed.hash;\n if (hasPath) {\n throw new Error(\"API base URL must not include path, query, or hash.\");\n }\n if (parsed.username || parsed.password) {\n throw new Error(\"API base URL must not include credentials.\");\n }\n\n if (protocol === \"https:\") {\n const allowedHosts = readAllowedHosts();\n if (!allowedHosts.has(hostname) && !isLoopbackHost(hostname)) {\n throw new Error(\"API base URL host is not in allowlist.\");\n }\n return parsed.origin;\n }\n\n if (protocol === \"http:\" && isLoopbackHost(hostname) && allowInsecureLoopback()) {\n return parsed.origin;\n }\n\n throw new Error(\"Refusing insecure API base URL.\");\n}\n","import { getAccessToken } from \"../auth/session.js\";\nimport { loadLocalConfig } from \"../config/store.js\";\nimport { normalizeAndValidateApiBaseUrl } from \"../config/api-base-url.js\";\n\nexport class CloudClient {\n private async base(): Promise<{ apiBaseUrl: string; teamId?: string }> {\n const cfg = await loadLocalConfig();\n const apiBaseUrl = normalizeAndValidateApiBaseUrl(cfg.apiBaseUrl);\n return cfg.activeTeamId ? { apiBaseUrl, teamId: cfg.activeTeamId } : { apiBaseUrl };\n }\n\n async request<T>(path: string, init?: RequestInit): Promise<T> {\n const { apiBaseUrl, teamId } = await this.base();\n const token = await getAccessToken(apiBaseUrl);\n const headers = new Headers(init?.headers || {});\n headers.set(\"Authorization\", `Bearer ${token}`);\n headers.set(\"Content-Type\", \"application/json\");\n if (teamId) headers.set(\"X-Trie-Team-Id\", teamId);\n\n let res = await fetch(`${apiBaseUrl}${path}`, { ...init, headers });\n if (res.status === 401) {\n const retryToken = await getAccessToken(apiBaseUrl);\n headers.set(\"Authorization\", `Bearer ${retryToken}`);\n res = await fetch(`${apiBaseUrl}${path}`, { ...init, headers });\n }\n if (!res.ok) {\n throw new Error(`Cloud API error ${res.status}: ${path}`);\n }\n return (await res.json()) as T;\n }\n}\n\nexport const cloudClient = new CloudClient();\n","import { cloudClient } from \"./client.js\";\nimport type { CloudGraphResponse } from \"./types.js\";\n\nexport interface GraphQuery {\n view?: string;\n types?: string[];\n since?: string;\n until?: string;\n}\n\nexport async function fetchGraph(query: GraphQuery = {}): Promise<CloudGraphResponse> {\n const params = new URLSearchParams();\n if (query.view) params.set(\"view\", query.view);\n if (query.types?.length) params.set(\"types\", query.types.join(\",\"));\n if (query.since) params.set(\"since\", query.since);\n if (query.until) params.set(\"until\", query.until);\n const qs = params.toString();\n return cloudClient.request<CloudGraphResponse>(`/api/cloud/ledger/graph${qs ? `?${qs}` : \"\"}`);\n}\n","import { cloudClient } from \"./client.js\";\nimport type { SignalItem } from \"./types.js\";\n\nexport async function fetchSignals(limit = 20): Promise<SignalItem[]> {\n const data = await cloudClient.request<{ items?: SignalItem[]; signals?: SignalItem[] }>(\n `/api/cloud/signals?limit=${limit}`,\n );\n return data.items || data.signals || [];\n}\n","import { cloudClient } from \"./client.js\";\nimport type { CloudDocument } from \"./types.js\";\n\nexport async function fetchDocuments(): Promise<CloudDocument[]> {\n const data = await cloudClient.request<{ items?: CloudDocument[]; documents?: CloudDocument[] }>(\n \"/api/cloud/documents\",\n );\n return data.items || data.documents || [];\n}\n","import type { CloudLedgerResponse } from \"./types.js\";\nimport { cloudClient } from \"./client.js\";\n\nexport async function fetchLedger(project?: string): Promise<CloudLedgerResponse> {\n const qs = project ? `?project=${encodeURIComponent(project)}` : \"\";\n return cloudClient.request<CloudLedgerResponse>(`/api/cloud/ledger${qs}`);\n}\n"],"mappings":";AAKO,IAAM,eAAN,MAAmB;AAAA,EACP,QAAQ,oBAAI,IAAiC;AAAA,EAE9D,MAAM,IAAO,KAAa,OAAe,SAAuC;AAC9E,UAAM,MAAM,KAAK,MAAM,IAAI,GAAG;AAC9B,QAAI,OAAO,KAAK,IAAI,IAAI,IAAI,YAAY,OAAO;AAC7C,aAAO,IAAI;AAAA,IACb;AACA,UAAM,OAAO,MAAM,QAAQ;AAC3B,SAAK,MAAM,IAAI,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,KAAK,CAAC;AACnD,WAAO;AAAA,EACT;AAAA,EAEA,WAAW,KAAmB;AAC5B,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA,EAEA,gBAAsB;AACpB,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA,EAEA,QAA0C;AACxC,WAAO,EAAE,MAAM,KAAK,MAAM,MAAM,MAAM,CAAC,GAAG,KAAK,MAAM,KAAK,CAAC,EAAE;AAAA,EAC/D;AACF;AAEO,IAAM,eAAe,IAAI,aAAa;;;AC/B7C,SAAS,OAAO,UAAU,iBAAiB;AAC3C,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,YAAY;AASrB,IAAM,iBAA8B;AAAA,EAClC,YAAY,QAAQ,IAAI,qBAAqB;AAC/C;AAEO,SAAS,eAAuB;AACrC,SAAO,KAAK,QAAQ,GAAG,OAAO;AAChC;AAEO,SAAS,gBAAwB;AACtC,SAAO,KAAK,aAAa,GAAG,aAAa;AAC3C;AAEA,eAAsB,kBAAiC;AACrD,QAAM,MAAM,aAAa,GAAG,EAAE,WAAW,KAAK,CAAC;AACjD;AAEA,eAAsB,kBAAwC;AAC5D,QAAM,OAAO,cAAc;AAC3B,MAAI,CAAC,WAAW,IAAI,GAAG;AACrB,WAAO,EAAE,GAAG,eAAe;AAAA,EAC7B;AACA,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,MAAM,OAAO;AACxC,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO,EAAE,GAAG,gBAAgB,GAAG,OAAO;AAAA,EACxC,QAAQ;AACN,WAAO,EAAE,GAAG,eAAe;AAAA,EAC7B;AACF;AAEA,eAAsB,gBAAgB,MAAkC;AACtE,QAAM,gBAAgB;AACtB,QAAM,OAAO,cAAc;AAC3B,QAAM,UAAU,MAAM,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,GAAM,OAAO;AACrE;;;AC9CA,SAAS,kBAAkB;AAC3B,SAAS,UAAU,UAAU,gBAAgB;;;ACD7C,SAAS,OAAO,OAAO,SAAAA,QAAO,YAAAC,WAAU,QAAQ,QAAQ,aAAAC,kBAAiB;AACzE,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,aAAY;AAUrB,IAAM,UAAU;AAChB,IAAM,UAAU;AAChB,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AAEtB,SAAS,UAAU,OAAkC;AACnD,SAAO,KAAK,UAAU,KAAK;AAC7B;AAEA,SAAS,MAAM,OAAyC;AACtD,MAAI;AACF,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,kBAA0B;AACjC,SAAOC,MAAK,aAAa,GAAG,aAAa;AAC3C;AAEA,eAAe,yBAAyB,MAA6B;AACnE,MAAI,CAACC,YAAW,IAAI,EAAG;AACvB,QAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,MAAI,CAAC,MAAM,OAAO,KAAK,MAAM,eAAe,GAAG;AAC7C,UAAM,IAAI,MAAM,wCAAwC;AAAA,EAC1D;AACF;AAEA,eAAe,aAAa;AAC1B,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,QAAQ;AACjC,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,aAAa,OAAyC;AACnE,QAAM,YAAY,aAAa;AAC/B,QAAMC,OAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,QAAM,OAAO,gBAAgB;AAC7B,QAAM,yBAAyB,IAAI;AACnC,QAAM,WAAW,GAAG,IAAI,QAAQ,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;AACzD,QAAMC,WAAU,UAAU,UAAU,KAAK,GAAG,EAAE,UAAU,SAAS,MAAM,eAAe,MAAM,IAAI,CAAC;AACjG,QAAM,OAAO,UAAU,IAAI;AAC3B,QAAM,MAAM,MAAM,aAAa;AACjC;AAEA,eAAe,eAAkD;AAC/D,QAAM,OAAO,gBAAgB;AAC7B,MAAI,CAACF,YAAW,IAAI,EAAG,QAAO;AAC9B,QAAM,yBAAyB,IAAI;AACnC,QAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,OAAK,MAAM,OAAO,QAAW,GAAG;AAC9B,UAAM,MAAM,MAAM,aAAa;AAAA,EACjC;AACA,QAAM,MAAM,MAAMG,UAAS,MAAM,OAAO;AACxC,SAAO,MAAM,GAAG;AAClB;AAEA,eAAe,gBAA+B;AAC5C,QAAM,OAAO,gBAAgB;AAC7B,MAAI,CAACH,YAAW,IAAI,EAAG;AACvB,QAAM,OAAO,IAAI,EAAE,MAAM,MAAM,MAAS;AAC1C;AAEA,eAAsB,gBAAgB,OAAyC;AAC7E,QAAM,SAAS,MAAM,WAAW;AAChC,MAAI,QAAQ;AACV,UAAM,OAAO,YAAY,SAAS,SAAS,UAAU,KAAK,CAAC;AAC3D;AAAA,EACF;AACA,QAAM,aAAa,KAAK;AAC1B;AAEA,eAAsB,kBAAqD;AACzE,QAAM,SAAS,MAAM,WAAW;AAChC,MAAI,QAAQ;AACV,UAAM,MAAM,MAAM,OAAO,YAAY,SAAS,OAAO;AACrD,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO,MAAM,GAAG;AAAA,EAClB;AACA,SAAO,aAAa;AACtB;AAEA,eAAsB,mBAAkC;AACtD,QAAM,SAAS,MAAM,WAAW;AAChC,MAAI,QAAQ;AACV,UAAM,OAAO,eAAe,SAAS,OAAO;AAC5C;AAAA,EACF;AACA,QAAM,cAAc;AACtB;;;ACzGA,IAAM,wBAAwB,oBAAI,IAAI;AAAA,EACpC;AACF,CAAC;AAED,SAAS,mBAAgC;AACvC,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,QAAQ,IACX,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,EAAE,YAAY,CAAC,EACvC,OAAO,OAAO;AACjB,SAAO,MAAM,SAAS,IAAI,IAAI,IAAI,KAAK,IAAI;AAC7C;AAEA,SAAS,eAAeI,WAA2B;AACjD,SAAOA,cAAa,eAAeA,cAAa,eAAeA,cAAa;AAC9E;AAEA,SAAS,wBAAiC;AACxC,SAAO,QAAQ,IAAI,kCAAkC;AACvD;AAEO,SAAS,+BAA+B,QAAwB;AACrE,MAAI;AACJ,MAAI;AACF,aAAS,IAAI,IAAI,MAAM;AAAA,EACzB,QAAQ;AACN,UAAM,IAAI,MAAM,uBAAuB;AAAA,EACzC;AAEA,QAAM,WAAW,OAAO,SAAS,YAAY;AAC7C,QAAMA,YAAW,OAAO,SAAS,YAAY;AAC7C,QAAM,UAAU,OAAO,aAAa,OAAO,OAAO,UAAU,OAAO;AACnE,MAAI,SAAS;AACX,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,MAAI,OAAO,YAAY,OAAO,UAAU;AACtC,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AAEA,MAAI,aAAa,UAAU;AACzB,UAAM,eAAe,iBAAiB;AACtC,QAAI,CAAC,aAAa,IAAIA,SAAQ,KAAK,CAAC,eAAeA,SAAQ,GAAG;AAC5D,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,aAAa,WAAW,eAAeA,SAAQ,KAAK,sBAAsB,GAAG;AAC/E,WAAO,OAAO;AAAA,EAChB;AAEA,QAAM,IAAI,MAAM,iCAAiC;AACnD;;;AF9CA,IAAI,mBAAgE;AACpE,IAAI,kBAA4B,CAAC;AAE1B,SAAS,wBAAgC;AAC9C,SAAO,WAAW,QAAQ,EACvB,OAAO,GAAG,SAAS,CAAC,IAAI,SAAS,EAAE,QAAQ,IAAI,SAAS,CAAC,IAAI,QAAQ,IAAI,EAAE,EAC3E,OAAO,KAAK;AACjB;AAEA,SAAS,sBAA+B;AACtC,QAAM,MAAM,KAAK,IAAI;AACrB,oBAAkB,gBAAgB,OAAO,CAAC,MAAM,MAAM,IAAI,GAAM;AAChE,MAAI,gBAAgB,UAAU,EAAG,QAAO;AACxC,kBAAgB,KAAK,GAAG;AACxB,SAAO;AACT;AAEO,SAAS,eAAe,OAAe,WAAyB;AACrE,qBAAmB;AAAA,IACjB;AAAA,IACA,WAAW,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,YAAY,GAAG,IAAI;AAAA,EAC1D;AACF;AAEA,eAAsB,kBAAkB,QAAsC;AAC5E,MAAI,OAAO,eAAe;AACxB,UAAM,qBAKF;AAAA,MACF,cAAc,OAAO;AAAA,IACvB;AACA,QAAI,OAAO,MAAM,GAAI,oBAAmB,SAAS,OAAO,KAAK;AAC7D,QAAI,OAAO,MAAM,KAAM,oBAAmB,WAAW,OAAO,KAAK;AACjE,QAAI,OAAO,MAAM,MAAO,oBAAmB,YAAY,OAAO,KAAK;AAEnE,UAAM,gBAAgB;AAAA,MACpB,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACA,iBAAe,OAAO,cAAc,OAAO,UAAU;AACrD,QAAM,MAAM,MAAM,gBAAgB;AAClC,QAAM,aAAa;AAAA,IACjB,GAAG;AAAA,EACL;AACA,MAAI,OAAO,MAAM,GAAI,YAAW,eAAe,OAAO,KAAK;AAC3D,MAAI,OAAO,MAAM,KAAM,YAAW,iBAAiB,OAAO,KAAK;AAC/D,MAAI,OAAO,MAAM,MAAO,YAAW,YAAY,OAAO,KAAK;AAC3D,QAAM,gBAAgB;AAAA,IACpB,GAAG;AAAA,EACL,CAAC;AACH;AAEA,eAAsB,eAAe,YAAqC;AACxE,MAAI,oBAAoB,KAAK,IAAI,IAAI,iBAAiB,WAAW;AAC/D,WAAO,iBAAiB;AAAA,EAC1B;AACA,QAAM,QAAQ,MAAM,gBAAgB;AACpC,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,sCAAsC;AAClE,QAAM,YAAY,MAAM,mBAAmB,YAAY,MAAM,YAAY;AACzE,SAAO,UAAU;AACnB;AAEA,eAAsB,mBACpB,YACA,cACwB;AACxB,QAAM,iBAAiB,+BAA+B,UAAU;AAChE,MAAI,CAAC,oBAAoB,GAAG;AAC1B,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,QAAM,MAAM,MAAM,MAAM,GAAG,cAAc,yBAAyB;AAAA,IAChE,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU;AAAA,MACnB,eAAe;AAAA,MACf,qBAAqB,sBAAsB;AAAA,IAC7C,CAAC;AAAA,EACH,CAAC;AACD,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;AAC5C,YAAM,iBAAiB;AACvB,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,QAAI,SAAS,UAAU,IAAI,MAAM;AACjC,QAAI;AACF,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,UAAI,MAAM,MAAO,UAAS,KAAK;AAAA,IACjC,QAAQ;AAAA,IAAC;AACT,UAAM,IAAI,MAAM,yBAAyB,MAAM,qCAAqC;AAAA,EACtF;AACA,QAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,iBAAe,KAAK,cAAc,KAAK,UAAU;AACjD,SAAO;AACT;AAEA,eAAsB,cAAc,YAAmC;AACrE,QAAM,iBAAiB,+BAA+B,UAAU;AAChE,QAAM,QAAQ,MAAM,gBAAgB;AACpC,MAAI,OAAO;AACT,UAAM,MAAM,GAAG,cAAc,wBAAwB;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,eAAe,MAAM,aAAa,CAAC;AAAA,IAC5D,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,EAC1B;AACA,qBAAmB;AACnB,QAAM,iBAAiB;AACzB;;;AGjHO,IAAM,cAAN,MAAkB;AAAA,EACvB,MAAc,OAAyD;AACrE,UAAM,MAAM,MAAM,gBAAgB;AAClC,UAAM,aAAa,+BAA+B,IAAI,UAAU;AAChE,WAAO,IAAI,eAAe,EAAE,YAAY,QAAQ,IAAI,aAAa,IAAI,EAAE,WAAW;AAAA,EACpF;AAAA,EAEA,MAAM,QAAW,MAAc,MAAgC;AAC7D,UAAM,EAAE,YAAY,OAAO,IAAI,MAAM,KAAK,KAAK;AAC/C,UAAM,QAAQ,MAAM,eAAe,UAAU;AAC7C,UAAM,UAAU,IAAI,QAAQ,MAAM,WAAW,CAAC,CAAC;AAC/C,YAAQ,IAAI,iBAAiB,UAAU,KAAK,EAAE;AAC9C,YAAQ,IAAI,gBAAgB,kBAAkB;AAC9C,QAAI,OAAQ,SAAQ,IAAI,kBAAkB,MAAM;AAEhD,QAAI,MAAM,MAAM,MAAM,GAAG,UAAU,GAAG,IAAI,IAAI,EAAE,GAAG,MAAM,QAAQ,CAAC;AAClE,QAAI,IAAI,WAAW,KAAK;AACtB,YAAM,aAAa,MAAM,eAAe,UAAU;AAClD,cAAQ,IAAI,iBAAiB,UAAU,UAAU,EAAE;AACnD,YAAM,MAAM,MAAM,GAAG,UAAU,GAAG,IAAI,IAAI,EAAE,GAAG,MAAM,QAAQ,CAAC;AAAA,IAChE;AACA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,MAAM,mBAAmB,IAAI,MAAM,KAAK,IAAI,EAAE;AAAA,IAC1D;AACA,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AACF;AAEO,IAAM,cAAc,IAAI,YAAY;;;ACtB3C,eAAsB,WAAW,QAAoB,CAAC,GAAgC;AACpF,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,MAAM,KAAM,QAAO,IAAI,QAAQ,MAAM,IAAI;AAC7C,MAAI,MAAM,OAAO,OAAQ,QAAO,IAAI,SAAS,MAAM,MAAM,KAAK,GAAG,CAAC;AAClE,MAAI,MAAM,MAAO,QAAO,IAAI,SAAS,MAAM,KAAK;AAChD,MAAI,MAAM,MAAO,QAAO,IAAI,SAAS,MAAM,KAAK;AAChD,QAAM,KAAK,OAAO,SAAS;AAC3B,SAAO,YAAY,QAA4B,0BAA0B,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE;AAC/F;;;ACfA,eAAsB,aAAa,QAAQ,IAA2B;AACpE,QAAM,OAAO,MAAM,YAAY;AAAA,IAC7B,4BAA4B,KAAK;AAAA,EACnC;AACA,SAAO,KAAK,SAAS,KAAK,WAAW,CAAC;AACxC;;;ACLA,eAAsB,iBAA2C;AAC/D,QAAM,OAAO,MAAM,YAAY;AAAA,IAC7B;AAAA,EACF;AACA,SAAO,KAAK,SAAS,KAAK,aAAa,CAAC;AAC1C;;;ACLA,eAAsB,YAAY,SAAgD;AAChF,QAAM,KAAK,UAAU,YAAY,mBAAmB,OAAO,CAAC,KAAK;AACjE,SAAO,YAAY,QAA6B,oBAAoB,EAAE,EAAE;AAC1E;","names":["mkdir","readFile","writeFile","existsSync","join","join","existsSync","mkdir","writeFile","readFile","hostname"]}
package/dist/cli/main.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  revokeSession,
13
13
  saveLocalConfig,
14
14
  sessionCache
15
- } from "../chunk-QR64Y5TI.js";
15
+ } from "../chunk-7VFBLI2G.js";
16
16
 
17
17
  // src/cli/main.ts
18
18
  import { mkdir, writeFile } from "fs/promises";
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startServer
4
- } from "./chunk-2YXOBNKW.js";
5
- import "./chunk-QR64Y5TI.js";
4
+ } from "./chunk-2MIBCCPX.js";
5
+ import "./chunk-7VFBLI2G.js";
6
6
 
7
7
  // src/index.ts
8
8
  startServer().catch((error) => {
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  MCPServer,
3
3
  startServer
4
- } from "../chunk-2YXOBNKW.js";
5
- import "../chunk-QR64Y5TI.js";
4
+ } from "../chunk-2MIBCCPX.js";
5
+ import "../chunk-7VFBLI2G.js";
6
6
  export {
7
7
  MCPServer,
8
8
  startServer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@triedotdev/mcp",
3
- "version": "1.0.173",
3
+ "version": "1.0.174",
4
4
  "description": "Trie cloud context bridge for Cursor and Claude Code.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cache/session-cache.ts","../src/config/store.ts","../src/auth/session.ts","../src/auth/keychain.ts","../src/config/api-base-url.ts","../src/cloud/client.ts","../src/cloud/graph.ts","../src/cloud/signals.ts","../src/cloud/documents.ts","../src/cloud/ledger.ts"],"sourcesContent":["type CacheEntry<T> = {\n fetchedAt: number;\n data: T;\n};\n\nexport class SessionCache {\n private readonly cache = new Map<string, CacheEntry<unknown>>();\n\n async get<T>(key: string, ttlMs: number, fetcher: () => Promise<T>): Promise<T> {\n const hit = this.cache.get(key) as CacheEntry<T> | undefined;\n if (hit && Date.now() - hit.fetchedAt < ttlMs) {\n return hit.data;\n }\n const data = await fetcher();\n this.cache.set(key, { fetchedAt: Date.now(), data });\n return data;\n }\n\n invalidate(key: string): void {\n this.cache.delete(key);\n }\n\n invalidateAll(): void {\n this.cache.clear();\n }\n\n stats(): { size: number; keys: string[] } {\n return { size: this.cache.size, keys: [...this.cache.keys()] };\n }\n}\n\nexport const sessionCache = new SessionCache();\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport interface LocalConfig {\n apiBaseUrl: string;\n activeTeamId?: string;\n activeTeamName?: string;\n userEmail?: string;\n}\n\nconst DEFAULT_CONFIG: LocalConfig = {\n apiBaseUrl: process.env.TRIE_API_BASE_URL || \"https://trie-api.vercel.app\",\n};\n\nexport function getConfigDir(): string {\n return join(homedir(), \".trie\");\n}\n\nexport function getConfigPath(): string {\n return join(getConfigDir(), \"config.json\");\n}\n\nexport async function ensureConfigDir(): Promise<void> {\n await mkdir(getConfigDir(), { recursive: true });\n}\n\nexport async function loadLocalConfig(): Promise<LocalConfig> {\n const path = getConfigPath();\n if (!existsSync(path)) {\n return { ...DEFAULT_CONFIG };\n }\n try {\n const raw = await readFile(path, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<LocalConfig>;\n return { ...DEFAULT_CONFIG, ...parsed };\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport async function saveLocalConfig(next: LocalConfig): Promise<void> {\n await ensureConfigDir();\n const path = getConfigPath();\n await writeFile(path, `${JSON.stringify(next, null, 2)}\\n`, \"utf-8\");\n}\n","import { createHash } from \"node:crypto\";\nimport { hostname, platform, userInfo } from \"node:os\";\nimport { clearCredentials, loadCredentials, saveCredentials } from \"./keychain.js\";\nimport type { CliAuthTokens } from \"../types/index.js\";\nimport { loadLocalConfig, saveLocalConfig } from \"../config/store.js\";\nimport { normalizeAndValidateApiBaseUrl } from \"../config/api-base-url.js\";\n\nlet accessTokenCache: { token: string; expiresAt: number } | null = null;\nlet refreshAttempts: number[] = [];\n\nexport function getMachineFingerprint(): string {\n return createHash(\"sha256\")\n .update(`${hostname()}:${userInfo().username}:${platform()}:${process.arch}`)\n .digest(\"hex\");\n}\n\nfunction allowRefreshAttempt(): boolean {\n const now = Date.now();\n refreshAttempts = refreshAttempts.filter((t) => now - t < 60_000);\n if (refreshAttempts.length >= 5) return false;\n refreshAttempts.push(now);\n return true;\n}\n\nexport function setAccessToken(token: string, expiresIn: number): void {\n accessTokenCache = {\n token,\n expiresAt: Date.now() + Math.max(10, expiresIn - 300) * 1000,\n };\n}\n\nexport async function persistAuthTokens(tokens: CliAuthTokens): Promise<void> {\n if (tokens.refresh_token) {\n const credentialsPayload: {\n refreshToken: string;\n teamId?: string;\n teamName?: string;\n userEmail?: string;\n } = {\n refreshToken: tokens.refresh_token,\n };\n if (tokens.team?.id) credentialsPayload.teamId = tokens.team.id;\n if (tokens.team?.name) credentialsPayload.teamName = tokens.team.name;\n if (tokens.user?.email) credentialsPayload.userEmail = tokens.user.email;\n\n await saveCredentials({\n ...credentialsPayload,\n });\n }\n setAccessToken(tokens.access_token, tokens.expires_in);\n const cfg = await loadLocalConfig();\n const nextConfig = {\n ...cfg,\n };\n if (tokens.team?.id) nextConfig.activeTeamId = tokens.team.id;\n if (tokens.team?.name) nextConfig.activeTeamName = tokens.team.name;\n if (tokens.user?.email) nextConfig.userEmail = tokens.user.email;\n await saveLocalConfig({\n ...nextConfig,\n });\n}\n\nexport async function getAccessToken(apiBaseUrl: string): Promise<string> {\n if (accessTokenCache && Date.now() < accessTokenCache.expiresAt) {\n return accessTokenCache.token;\n }\n const creds = await loadCredentials();\n if (!creds) throw new Error(\"Not authenticated. Run `trie login`.\");\n const refreshed = await refreshAccessToken(apiBaseUrl, creds.refreshToken);\n return refreshed.access_token;\n}\n\nexport async function refreshAccessToken(\n apiBaseUrl: string,\n refreshToken: string,\n): Promise<CliAuthTokens> {\n const safeApiBaseUrl = normalizeAndValidateApiBaseUrl(apiBaseUrl);\n if (!allowRefreshAttempt()) {\n throw new Error(\"Refresh rate limited. Try again in a minute.\");\n }\n const res = await fetch(`${safeApiBaseUrl}/api/auth/cli/refresh`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n refresh_token: refreshToken,\n machine_fingerprint: getMachineFingerprint(),\n }),\n });\n if (!res.ok) {\n if (res.status === 401 || res.status === 403) {\n await clearCredentials();\n }\n throw new Error(\"Session expired. Run `trie login`.\");\n }\n const data = (await res.json()) as CliAuthTokens;\n setAccessToken(data.access_token, data.expires_in);\n return data;\n}\n\nexport async function revokeSession(apiBaseUrl: string): Promise<void> {\n const safeApiBaseUrl = normalizeAndValidateApiBaseUrl(apiBaseUrl);\n const creds = await loadCredentials();\n if (creds) {\n await fetch(`${safeApiBaseUrl}/api/auth/cli/revoke`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: creds.refreshToken }),\n }).catch(() => undefined);\n }\n accessTokenCache = null;\n await clearCredentials();\n}\n","import { chmod, lstat, mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getConfigDir } from \"../config/store.js\";\n\nexport interface StoredCredentials {\n refreshToken: string;\n teamId?: string;\n teamName?: string;\n userEmail?: string;\n}\n\nconst SERVICE = \"dev.trie.cli\";\nconst ACCOUNT = \"default\";\nconst FALLBACK_FILE = \"credentials.json\";\nconst PERMS_PRIVATE = 0o600;\n\nfunction serialize(value: StoredCredentials): string {\n return JSON.stringify(value);\n}\n\nfunction parse(value: string): StoredCredentials | null {\n try {\n return JSON.parse(value) as StoredCredentials;\n } catch {\n return null;\n }\n}\n\nfunction getFallbackPath(): string {\n return join(getConfigDir(), FALLBACK_FILE);\n}\n\nasync function ensureSafeCredentialFile(path: string): Promise<void> {\n if (!existsSync(path)) return;\n const stats = await lstat(path);\n if (!stats.isFile() || stats.isSymbolicLink()) {\n throw new Error(\"Unsafe credentials file path detected.\");\n }\n}\n\nasync function loadKeytar() {\n try {\n const mod = await import(\"keytar\");\n return mod.default;\n } catch {\n return null;\n }\n}\n\nasync function saveFallback(value: StoredCredentials): Promise<void> {\n const configDir = getConfigDir();\n await mkdir(configDir, { recursive: true });\n const path = getFallbackPath();\n await ensureSafeCredentialFile(path);\n const tempPath = `${path}.tmp-${process.pid}-${Date.now()}`;\n await writeFile(tempPath, serialize(value), { encoding: \"utf-8\", mode: PERMS_PRIVATE, flag: \"w\" });\n await rename(tempPath, path);\n await chmod(path, PERMS_PRIVATE);\n}\n\nasync function loadFallback(): Promise<StoredCredentials | null> {\n const path = getFallbackPath();\n if (!existsSync(path)) return null;\n await ensureSafeCredentialFile(path);\n const stats = await lstat(path);\n if ((stats.mode & 0o077) !== 0) {\n await chmod(path, PERMS_PRIVATE);\n }\n const raw = await readFile(path, \"utf-8\");\n return parse(raw);\n}\n\nasync function clearFallback(): Promise<void> {\n const path = getFallbackPath();\n if (!existsSync(path)) return;\n await unlink(path).catch(() => undefined);\n}\n\nexport async function saveCredentials(value: StoredCredentials): Promise<void> {\n const keytar = await loadKeytar();\n if (keytar) {\n await keytar.setPassword(SERVICE, ACCOUNT, serialize(value));\n return;\n }\n await saveFallback(value);\n}\n\nexport async function loadCredentials(): Promise<StoredCredentials | null> {\n const keytar = await loadKeytar();\n if (keytar) {\n const raw = await keytar.getPassword(SERVICE, ACCOUNT);\n if (!raw) return null;\n return parse(raw);\n }\n return loadFallback();\n}\n\nexport async function clearCredentials(): Promise<void> {\n const keytar = await loadKeytar();\n if (keytar) {\n await keytar.deletePassword(SERVICE, ACCOUNT);\n return;\n }\n await clearFallback();\n}\n","const DEFAULT_ALLOWED_HOSTS = new Set([\n \"trie-api.vercel.app\",\n]);\n\nfunction readAllowedHosts(): Set<string> {\n const raw = process.env.TRIE_API_BASE_ALLOWLIST;\n if (!raw) return DEFAULT_ALLOWED_HOSTS;\n const hosts = raw\n .split(\",\")\n .map((part) => part.trim().toLowerCase())\n .filter(Boolean);\n return hosts.length > 0 ? new Set(hosts) : DEFAULT_ALLOWED_HOSTS;\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n return hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"::1\";\n}\n\nfunction allowInsecureLoopback(): boolean {\n return process.env.TRIE_ALLOW_INSECURE_LOCALHOST === \"1\";\n}\n\nexport function normalizeAndValidateApiBaseUrl(rawUrl: string): string {\n let parsed: URL;\n try {\n parsed = new URL(rawUrl);\n } catch {\n throw new Error(\"Invalid API base URL.\");\n }\n\n const protocol = parsed.protocol.toLowerCase();\n const hostname = parsed.hostname.toLowerCase();\n const hasPath = parsed.pathname !== \"/\" || parsed.search || parsed.hash;\n if (hasPath) {\n throw new Error(\"API base URL must not include path, query, or hash.\");\n }\n if (parsed.username || parsed.password) {\n throw new Error(\"API base URL must not include credentials.\");\n }\n\n if (protocol === \"https:\") {\n const allowedHosts = readAllowedHosts();\n if (!allowedHosts.has(hostname) && !isLoopbackHost(hostname)) {\n throw new Error(\"API base URL host is not in allowlist.\");\n }\n return parsed.origin;\n }\n\n if (protocol === \"http:\" && isLoopbackHost(hostname) && allowInsecureLoopback()) {\n return parsed.origin;\n }\n\n throw new Error(\"Refusing insecure API base URL.\");\n}\n","import { getAccessToken } from \"../auth/session.js\";\nimport { loadLocalConfig } from \"../config/store.js\";\nimport { normalizeAndValidateApiBaseUrl } from \"../config/api-base-url.js\";\n\nexport class CloudClient {\n private async base(): Promise<{ apiBaseUrl: string; teamId?: string }> {\n const cfg = await loadLocalConfig();\n const apiBaseUrl = normalizeAndValidateApiBaseUrl(cfg.apiBaseUrl);\n return cfg.activeTeamId ? { apiBaseUrl, teamId: cfg.activeTeamId } : { apiBaseUrl };\n }\n\n async request<T>(path: string, init?: RequestInit): Promise<T> {\n const { apiBaseUrl, teamId } = await this.base();\n const token = await getAccessToken(apiBaseUrl);\n const headers = new Headers(init?.headers || {});\n headers.set(\"Authorization\", `Bearer ${token}`);\n headers.set(\"Content-Type\", \"application/json\");\n if (teamId) headers.set(\"X-Trie-Team-Id\", teamId);\n\n let res = await fetch(`${apiBaseUrl}${path}`, { ...init, headers });\n if (res.status === 401) {\n const retryToken = await getAccessToken(apiBaseUrl);\n headers.set(\"Authorization\", `Bearer ${retryToken}`);\n res = await fetch(`${apiBaseUrl}${path}`, { ...init, headers });\n }\n if (!res.ok) {\n throw new Error(`Cloud API error ${res.status}: ${path}`);\n }\n return (await res.json()) as T;\n }\n}\n\nexport const cloudClient = new CloudClient();\n","import { cloudClient } from \"./client.js\";\nimport type { CloudGraphResponse } from \"./types.js\";\n\nexport interface GraphQuery {\n view?: string;\n types?: string[];\n since?: string;\n until?: string;\n}\n\nexport async function fetchGraph(query: GraphQuery = {}): Promise<CloudGraphResponse> {\n const params = new URLSearchParams();\n if (query.view) params.set(\"view\", query.view);\n if (query.types?.length) params.set(\"types\", query.types.join(\",\"));\n if (query.since) params.set(\"since\", query.since);\n if (query.until) params.set(\"until\", query.until);\n const qs = params.toString();\n return cloudClient.request<CloudGraphResponse>(`/api/cloud/ledger/graph${qs ? `?${qs}` : \"\"}`);\n}\n","import { cloudClient } from \"./client.js\";\nimport type { SignalItem } from \"./types.js\";\n\nexport async function fetchSignals(limit = 20): Promise<SignalItem[]> {\n const data = await cloudClient.request<{ items?: SignalItem[]; signals?: SignalItem[] }>(\n `/api/cloud/signals?limit=${limit}`,\n );\n return data.items || data.signals || [];\n}\n","import { cloudClient } from \"./client.js\";\nimport type { CloudDocument } from \"./types.js\";\n\nexport async function fetchDocuments(): Promise<CloudDocument[]> {\n const data = await cloudClient.request<{ items?: CloudDocument[]; documents?: CloudDocument[] }>(\n \"/api/cloud/documents\",\n );\n return data.items || data.documents || [];\n}\n","import type { CloudLedgerResponse } from \"./types.js\";\nimport { cloudClient } from \"./client.js\";\n\nexport async function fetchLedger(project?: string): Promise<CloudLedgerResponse> {\n const qs = project ? `?project=${encodeURIComponent(project)}` : \"\";\n return cloudClient.request<CloudLedgerResponse>(`/api/cloud/ledger${qs}`);\n}\n"],"mappings":"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","names":["mkdir","readFile","writeFile","existsSync","join","join","existsSync","mkdir","writeFile","readFile","hostname"]}