// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 import { ConvexHttpClient } from "convex/browser" // Convex 1.45's CLI lists env through a WebSocket subscription. Linked-service relays are // deliberately HTTP-only. Query the same system function once over HTTP, then use the CLI's // update endpoint with its default (no --force) semantics: equal values stay, conflicts fail // the whole batch, missing values are created, and unlisted variables are untouched. export async function syncPlatformEnvironment({ url, adminKey, variables, timeoutMs = 30_000 }) { const controller = new AbortController() const timer = setTimeout(() => controller.abort(), timeoutMs) const boundedFetch = (input, options) => fetch(input, { ...options, signal: controller.signal, redirect: "error" }) try { const client = new ConvexHttpClient(url, { logger: false, fetch: boundedFetch }) client.setAdminAuth(adminKey) const existing = await client.query("_system/cli/queryEnvironmentVariables", {}) if ( !Array.isArray(existing) || existing.some((entry) => typeof entry?.name !== "string" || typeof entry?.value !== "string") ) { throw new Error("Invalid environment response") } const current = new Map(existing.map(({ name, value }) => [name, value])) const changes = [] for (const [name, value] of Object.entries(variables)) { if (current.has(name) && current.get(name) !== value) { throw new Error("Environment conflict") } if (!current.has(name)) changes.push({ name, value }) } if (changes.length > 0) { const response = await boundedFetch(new URL("/api/update_environment_variables", url), { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Convex ${adminKey}` }, body: JSON.stringify({ changes }), }) await response.body?.cancel() if (!response.ok) throw new Error("Environment update refused") } } catch { // Upstream failures can contain environment values or credentials. Never surface their // bodies, messages or causes in deployment logs, including a conflicting existing value. throw new Error("Convex platform service environment sync failed") } finally { clearTimeout(timer) } }