UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

1,203 lines (1,201 loc) 42.1 kB
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } }); const require_runtime = require('./_virtual/_rolldown/runtime.cjs'); const require_fastkv = require('./fastkv.cjs'); const require_network = require('./network.cjs'); const require_config = require('./config.cjs'); const require_contract = require('./contract.cjs'); const require_sidebar = require('./sidebar.cjs'); const require_integrity = require('./integrity.cjs'); const require_api_contract = require('./api-contract.cjs'); const require_app = require('./app.cjs'); const require_infra = require('./cli/infra.cjs'); const require_save_config = require('./utils/save-config.cjs'); const require_cli_init = require('./cli/init.cjs'); const require_status = require('./cli/status.cjs'); const require_sync = require('./cli/sync.cjs'); const require_upgrade = require('./cli/upgrade.cjs'); const require_near_cli = require('./near-cli.cjs'); const require_service_descriptor = require('./service-descriptor.cjs'); const require_shared = require('./shared.cjs'); const require_run = require('./utils/run.cjs'); let node_fs = require("node:fs"); let node_path = require("node:path"); let node_events = require("node:events"); let node_fs_promises = require("node:fs/promises"); let node_process = require("node:process"); node_process = require_runtime.__toESM(node_process, 1); let effect = require("effect"); let every_plugin = require("every-plugin"); let zod = require("zod"); //#region src/plugin.ts const pluginEvents = new node_events.EventEmitter(); let pendingSession = null; let pendingStartSummary = null; function consumeDevSession() { const data = pendingSession; const summary = pendingStartSummary; pendingSession = null; pendingStartSummary = null; if (!data) return null; return summary ? { ...data, summary } : data; } async function timePhase(timings, name, fn) { pluginEvents.emit("progress", { phase: name, status: "running" }); const startedAt = Date.now(); try { const result = await fn(); timings.push({ name, durationMs: Date.now() - startedAt }); pluginEvents.emit("progress", { phase: name, status: "done", durationMs: Date.now() - startedAt }); return result; } catch (error) { pluginEvents.emit("progress", { phase: name, status: "error", durationMs: Date.now() - startedAt }); throw error; } } const buildCommands = { host: { cmd: "bun", args: ["run", "build"] }, ui: { cmd: "bun", args: ["run", "build"] }, api: { cmd: "bun", args: ["run", "build"] } }; const PUBLISH_FUNCTION_NAMES = ["__fastdata_kv"]; function getPluginRef(entry) { if (!entry || typeof entry === "string") return null; return entry; } function parseSourceMode(value, defaultValue) { if (value === "local" || value === "remote") return value; return defaultValue; } function buildConfigResult(bosConfig) { const packages = bosConfig ? Object.keys(bosConfig.app) : []; return { config: bosConfig, packages, remotes: packages.filter((name) => name !== "host") }; } async function fileExists(path) { try { await (0, node_fs_promises.access)(path); return true; } catch { return false; } } async function readJsonFile(path) { return JSON.parse(await (0, node_fs_promises.readFile)(path, "utf8")); } function resolveWorkspaceTarget(key, bosConfig, runtimeConfig, configDir) { if (bosConfig?.app && key in bosConfig.app) { const appEntry = bosConfig.app[key]; const devPath = require_config.resolveLocalDevelopmentPath(appEntry?.development, configDir); if (devPath) return { key, kind: "app", path: devPath }; return { key, kind: "app", path: `${configDir}/${key}` }; } const pluginPath = (runtimeConfig?.plugins?.[key])?.localPath ?? require_config.resolveLocalDevelopmentPath(getPluginRef(bosConfig?.plugins?.[key])?.development, configDir); if (pluginPath) return { key, kind: "plugin", path: pluginPath }; return null; } function isValidProxyUrl(url) { try { const parsed = new URL(url); return parsed.protocol === "http:" || parsed.protocol === "https:"; } catch { return false; } } function resolveProxyUrl(bosConfig) { if (!bosConfig) return null; const apiConfig = bosConfig.app.api; if (!apiConfig) return null; if (apiConfig.proxy && isValidProxyUrl(apiConfig.proxy)) return apiConfig.proxy; if (apiConfig.production && isValidProxyUrl(apiConfig.production)) return apiConfig.production; return null; } function sanitizePluginKey(value) { return value.replace(/[^A-Za-z0-9/_-]/g, "-").replace(/\/+/g, "/").split("/").filter(Boolean).map((segment) => segment.replace(/[^A-Za-z0-9_-]/g, "-")).join("/").replace(/^\/+|\/+$/g, ""); } function defaultPluginKey(source) { const normalized = source.replace(/^local:/, "").replace(/\/$/, ""); if (source.startsWith("local:")) return sanitizePluginKey((0, node_path.basename)(normalized)) || "plugin"; try { const url = new URL(source); return sanitizePluginKey((0, node_path.basename)(url.pathname) || url.hostname) || "plugin"; } catch { return sanitizePluginKey(source) || "plugin"; } } function pluginLocalPath(configDir, attachment) { const ref = getPluginRef(attachment); const source = ref?.development ?? ref?.production; if (!source?.startsWith("local:")) return null; return (0, node_path.join)(configDir, source.slice(6)); } function listPluginAttachments(config) { return Object.entries(config?.plugins ?? {}).map(([key, attachment]) => { const ref = getPluginRef(attachment); return { key, development: ref?.development, production: ref?.production, localPath: ref?.development?.startsWith("local:") ? ref.development.slice(6) : void 0, source: ref?.development?.startsWith("local:") ? "local" : "remote", integrity: ref?.integrity, version: ref?.version, name: ref?.name }; }).sort((a, b) => a.key.localeCompare(b.key)); } async function generateCodeArtifacts(configDir, config, opts) { if (opts?.env) require_config.writeResolvedConfig(configDir, config, opts.env, opts.extendsChain); const runtimeConfig = opts?.runtimeConfig ?? (await require_config.loadConfig({ cwd: configDir }))?.runtime; if (!runtimeConfig) return null; require_sidebar.writePluginSidebarGen(configDir, runtimeConfig); const bridge = await require_api_contract.syncApiContractBridge({ configDir, runtimeConfig, apiBaseUrl: runtimeConfig.api.url }); return { sidebarPath: (0, node_path.join)(configDir, "ui/src/lib/plugin-sidebar.gen.ts"), resolvedConfigPath: opts?.env ? (0, node_path.join)(configDir, ".bos/bos.resolved-config.json") : void 0, contractBridgePath: bridge.bridgePath }; } function extractPublishedUrl(output) { const match = output.match(/https?:\/\/[^\s"'<>]+/g); if (!match || match.length === 0) return null; return match[match.length - 1] ?? null; } async function buildEveryPluginQuietly(cwd) { if (!await fileExists(`${`${cwd}/packages/every-plugin`}/package.json`)) return; if (await fileExists(`${cwd}/packages/every-plugin/dist/build/rspack/plugin.mjs`)) return; const result = await require_run.run("bun", [ "run", "--cwd", "packages/every-plugin", "build" ], { cwd, capture: true }); if (result.exitCode === 0) { console.log("[build:ssr] build succeeded"); return; } if (result.stdout.trim()) node_process.default.stdout.write(result.stdout); if (result.stderr.trim()) node_process.default.stderr.write(result.stderr); throw new Error(`bun run --cwd packages/every-plugin build failed with exit code ${result.exitCode}`); } async function buildEverythingDevQuietly(cwd) { if (!await fileExists(`${`${cwd}/packages/everything-dev`}/package.json`)) return; if (await fileExists(`${cwd}/packages/everything-dev/dist/index.mjs`)) return; const result = await require_run.run("bun", [ "run", "--cwd", "packages/everything-dev", "build" ], { cwd, capture: true }); if (result.exitCode === 0) { console.log("[everything-dev] build succeeded"); return; } if (result.stdout.trim()) node_process.default.stdout.write(result.stdout); if (result.stderr.trim()) node_process.default.stderr.write(result.stderr); throw new Error(`bun run --cwd packages/everything-dev build failed with exit code ${result.exitCode}`); } async function fetchPublishedConfig(accountId, gatewayId) { try { return await require_fastkv.fetchBosConfigFromFastKv(`bos://${accountId}/${gatewayId}`); } catch { return null; } } function selectWorkspaceTargets(packages, bosConfig) { const allPackages = [...Object.keys(bosConfig?.app ?? {}), ...Object.keys(bosConfig?.plugins ?? {})]; if (packages === "all") return allPackages; return packages.split(",").map((pkg) => pkg.trim()).filter((pkg) => allPackages.includes(pkg)); } async function buildWorkspaceTargets(opts) { const existing = []; const skipped = []; for (const target of opts.targets) { const resolved = resolveWorkspaceTarget(target, opts.bosConfig, opts.runtimeConfig, opts.configDir); if (!resolved) { skipped.push(target); continue; } if (await fileExists(`${resolved.path}/package.json`)) existing.push(resolved); else skipped.push(target); } if (existing.length === 0) return { built: [], skipped }; if ((await require_shared.syncAndGenerateSharedUi({ configDir: opts.configDir, hostMode: "local", bosConfig: opts.bosConfig ?? void 0, extendsChain: [] })).catalogChanged) await require_run.run("bun", ["install"], { cwd: opts.configDir }); if (existing.some((entry) => entry.key === "api")) await buildEveryPluginQuietly(opts.configDir); await buildEverythingDevQuietly(opts.configDir); const env = { ...node_process.default.env, NODE_ENV: opts.deploy ? "production" : "development" }; if (opts.deploy) env.DEPLOY = "true"; else delete env.DEPLOY; const orderedExisting = opts.deploy ? [ ...existing.filter((entry) => entry.kind === "app" && entry.key !== "host"), ...existing.filter((entry) => entry.kind === "plugin"), ...existing.filter((entry) => entry.kind === "app" && entry.key === "host") ] : existing; const built = []; for (const resolved of orderedExisting) { const pkgJson = await readJsonFile(`${resolved.path}/package.json`); const buildConfig = opts.deploy && pkgJson.scripts?.deploy ? { cmd: "bun", args: ["run", "deploy"] } : buildCommands[resolved.key] ?? { cmd: "bun", args: ["run", "build"] }; await require_run.run(buildConfig.cmd, buildConfig.args, { cwd: resolved.path, env }); built.push(resolved.key); } return { built, skipped }; } var plugin_default = (0, every_plugin.createPlugin)({ variables: zod.z.object({ configPath: zod.z.string().optional() }), secrets: zod.z.object({}), contract: require_contract.bosContract, initialize: (config) => effect.Effect.promise(async () => { const configResult = await require_config.loadConfig({ path: config.variables.configPath }); return { bosConfig: configResult?.config ?? null, runtimeConfig: configResult?.runtime ?? null, configDir: require_config.getProjectRoot() }; }), shutdown: () => effect.Effect.void, createRouter: (deps, builder) => ({ config: builder.config.handler(async () => buildConfigResult(deps.bosConfig)), pluginAdd: builder.pluginAdd.handler(async ({ input }) => { if (!deps.bosConfig) return { status: "error", key: "", error: "No bos.config.json found" }; const isBosRef = input.source.startsWith("bos://"); const isLocal = input.source.startsWith("local:"); const key = sanitizePluginKey(input.as ?? (isBosRef ? input.source.split("/").pop() ?? "plugin" : defaultPluginKey(input.source))); const existing = deps.bosConfig.plugins?.[key]; const existingEntry = existing && typeof existing === "object" ? existing : {}; const nextPlugins = { ...deps.bosConfig.plugins ?? {} }; if (isBosRef) nextPlugins[key] = { ...existingEntry, extends: input.source }; else if (isLocal) nextPlugins[key] = { ...existingEntry, development: input.source, ...existingEntry.extends ? {} : {} }; else nextPlugins[key] = { ...existingEntry, production: input.production ?? input.source }; deps.bosConfig = { ...deps.bosConfig, plugins: nextPlugins }; await require_save_config.saveBosConfig(deps.configDir, deps.bosConfig); await generateCodeArtifacts(deps.configDir, deps.bosConfig); const stored = deps.bosConfig.plugins?.[key]; const storedObj = stored && typeof stored === "object" ? stored : {}; return { status: "added", key, development: storedObj.development, production: storedObj.production, integrity: storedObj.integrity, version: storedObj.version }; }), pluginRemove: builder.pluginRemove.handler(async ({ input }) => { if (!deps.bosConfig) return { status: "error", key: input.key, error: "No bos.config.json found" }; if (!deps.bosConfig.plugins?.[input.key]) return { status: "error", key: input.key, error: `Plugin '${input.key}' is not configured` }; const nextPlugins = { ...deps.bosConfig.plugins ?? {} }; delete nextPlugins[input.key]; deps.bosConfig = { ...deps.bosConfig, plugins: Object.keys(nextPlugins).length > 0 ? nextPlugins : void 0 }; await require_save_config.saveBosConfig(deps.configDir, deps.bosConfig); await generateCodeArtifacts(deps.configDir, deps.bosConfig); return { status: "removed", key: input.key }; }), pluginList: builder.pluginList.handler(async () => { return { status: "listed", plugins: listPluginAttachments(deps.bosConfig) }; }), pluginPublish: builder.pluginPublish.handler(async ({ input }) => { if (!deps.bosConfig) return { status: "error", key: input.key, error: "No bos.config.json found" }; const attachment = deps.bosConfig.plugins?.[input.key]; if (!attachment) return { status: "error", key: input.key, error: `Plugin '${input.key}' is not configured` }; const attachmentRef = getPluginRef(attachment); const localPath = pluginLocalPath(deps.configDir, attachment); if (!localPath) return { status: "error", key: input.key, error: `Plugin '${input.key}' does not have a local development path` }; const pkgPath = (0, node_path.join)(localPath, "package.json"); if (!await fileExists(pkgPath)) return { status: "error", key: input.key, error: `Missing package.json at ${localPath}` }; const pkgJson = await readJsonFile(pkgPath); const script = pkgJson.scripts?.deploy ? "deploy" : "build"; const { stdout, stderr, exitCode } = await require_run.run("bun", ["run", script], { cwd: localPath, capture: true }); if (exitCode !== 0) { if (stdout.trim()) node_process.default.stdout.write(stdout); if (stderr.trim()) node_process.default.stderr.write(stderr); return { status: "error", key: input.key, error: `Publish failed with exit code ${exitCode}` }; } if (stdout.trim()) node_process.default.stdout.write(stdout); if (stderr.trim()) node_process.default.stderr.write(stderr); let publishedUrl = extractPublishedUrl(`${stdout}\n${stderr}`); let manifest = null; if (publishedUrl) manifest = await require_fastkv.fetchRemotePluginManifest(publishedUrl); else if (attachmentRef?.production) { manifest = await require_fastkv.fetchRemotePluginManifest(attachmentRef.production); if (manifest) publishedUrl = attachmentRef.production; } const integrity = publishedUrl ? await require_integrity.computeSriHashForUrl(publishedUrl) : null; const version = manifest?.plugin.version ?? pkgJson.version; if (publishedUrl) { const rootConfigPath = (0, node_path.join)(deps.configDir, "bos.config.json"); try { const rootConfig = JSON.parse((0, node_fs.readFileSync)(rootConfigPath, "utf-8")); if (!rootConfig.plugins || typeof rootConfig.plugins !== "object") rootConfig.plugins = {}; const plugins = rootConfig.plugins; if (!plugins[input.key] || typeof plugins[input.key] !== "object") plugins[input.key] = {}; const entry = plugins[input.key]; entry.production = publishedUrl; if (integrity) entry.integrity = integrity; else delete entry.integrity; (0, node_fs.writeFileSync)(rootConfigPath, `${JSON.stringify(rootConfig, null, 2)}\n`); console.log(` ✅ Updated bos.config.json: plugins.${input.key}.production`); } catch (err) { console.error(` ❌ Failed to update bos.config.json:`, err instanceof Error ? err.message : err); } await generateCodeArtifacts(deps.configDir, deps.bosConfig); } return { status: "published", key: input.key, path: localPath, script, production: publishedUrl ?? attachmentRef?.production, integrity: integrity ?? void 0, version: version ?? void 0 }; }), dev: builder.dev.handler(async ({ input }) => { require_infra.ensureEnvFile(deps.configDir); require_infra.loadProjectEnv(deps.configDir); pluginEvents.emit("progress", { phase: "config", status: "running" }); const localPackages = require_app.detectLocalPackages(deps.bosConfig ?? void 0, deps.runtimeConfig ?? void 0); const hostSource = localPackages.includes("host") ? parseSourceMode(input.host, "local") : "remote"; const uiSource = localPackages.includes("ui") ? parseSourceMode(input.ui, "local") : "remote"; const apiSource = localPackages.includes("api") ? parseSourceMode(input.api, "local") : "remote"; const authSource = localPackages.includes("auth") ? parseSourceMode(input.auth, "local") : "remote"; const ssr = input.ssr ?? false; const proxy = input.proxy ?? false; if ((await require_shared.syncAndGenerateSharedUi({ configDir: deps.configDir, hostMode: hostSource, bosConfig: deps.bosConfig ?? void 0, extendsChain: [] })).catalogChanged) { pluginEvents.emit("progress", { phase: "install", status: "running" }); await require_run.run("bun", ["install"], { cwd: deps.configDir }); pluginEvents.emit("progress", { phase: "install", status: "done" }); } if (apiSource === "local" && !proxy || localPackages.some((pkg) => pkg.startsWith("plugin:"))) { pluginEvents.emit("progress", { phase: "build plugin", status: "running" }); await buildEveryPluginQuietly(deps.configDir); pluginEvents.emit("progress", { phase: "build plugin", status: "done" }); } pluginEvents.emit("progress", { phase: "build", status: "running" }); await buildEverythingDevQuietly(deps.configDir); pluginEvents.emit("progress", { phase: "build", status: "done" }); pluginEvents.emit("progress", { phase: "config", status: "done" }); const refreshed = await require_config.loadConfig({ cwd: deps.configDir }); deps.bosConfig = refreshed?.config ?? deps.bosConfig; deps.runtimeConfig = refreshed?.runtime ?? deps.runtimeConfig; if (!deps.bosConfig) return { status: "error", description: "No bos.config.json found", processes: [] }; if (proxy && !resolveProxyUrl(deps.bosConfig)) return { status: "error", description: "No valid proxy URL configured in bos.config.json", processes: [] }; const hostPort = input.port ?? require_config.getHostDevelopmentPort(deps.bosConfig.app.host.development); const runtimeConfig = await require_app.prepareDevelopmentRuntimeConfig(require_app.buildRuntimeConfig(deps.bosConfig, { uiSource, apiSource, authSource, hostSource, env: "development", plugins: deps.runtimeConfig?.plugins }), { hostPort, ssr }); await generateCodeArtifacts(deps.configDir, deps.bosConfig, { env: "development", extendsChain: refreshed?.source.extended, runtimeConfig }); const services = require_service_descriptor.buildServiceDescriptorMap(runtimeConfig, { ssr, proxy }); const packages = [...services.keys()]; const displayEnv = {}; if (services.get("api")?.proxy) { const proxyUrl = resolveProxyUrl(deps.bosConfig); if (proxyUrl) displayEnv.API_PROXY = proxyUrl; } const orchestrator = { packages, env: displayEnv, description: require_service_descriptor.buildDescription(services), port: runtimeConfig.host.port, interactive: input.interactive }; pendingSession = { orchestrator, services, runtimeConfig }; return { status: "started", description: orchestrator.description, processes: packages }; }), start: builder.start.handler(async ({ input }) => { require_infra.ensureEnvFile(deps.configDir); require_infra.loadProjectEnv(deps.configDir); pluginEvents.emit("progress", { phase: "config", status: "running" }); const account = input.account ?? node_process.default.env.BOS_ACCOUNT; const domain = input.domain ?? node_process.default.env.BOS_GATEWAY; let config = null; let remoteConfig = null; if (account && domain) { remoteConfig = await fetchPublishedConfig(account, domain); if (remoteConfig) config = remoteConfig; else console.warn(`[Start] Failed to fetch remote config for ${account}/${domain}, falling back to local bos.config.json`); } if (!config) config = deps.bosConfig; if (!config) return { status: "error", url: "", error: "No configuration found. Set BOS_ACCOUNT and BOS_GATEWAY environment variables, or provide a local bos.config.json." }; if (account) config = { ...config, account }; if (domain) config = { ...config, domain }; const port = input.port ?? require_config.getHostDevelopmentPort(config.app.host.development); const isStaging = input.env === "staging"; const runtimePlugins = await require_config.buildRuntimePluginsForConfig(config, deps.configDir, "production"); const runtimeConfig = require_app.buildRuntimeConfig(config, { uiSource: "remote", apiSource: "remote", authSource: "remote", hostSource: "remote", env: "production", plugins: runtimePlugins }); pluginEvents.emit("progress", { phase: "generate artifacts", status: "running" }); await generateCodeArtifacts(deps.configDir, config, { env: "production", runtimeConfig }); pluginEvents.emit("progress", { phase: "generate artifacts", status: "done" }); const productionEnv = {}; const warnings = []; if (!node_process.default.env.CORS_ORIGIN && config.domain) { const defaultOrigin = `https://${config.domain}`; productionEnv.CORS_ORIGIN = defaultOrigin; warnings.push(`CORS_ORIGIN defaulting to ${defaultOrigin}`); } const requiredSecrets = /* @__PURE__ */ new Set(); const missingSecrets = []; if (runtimeConfig.auth?.secrets) for (const s of runtimeConfig.auth.secrets) requiredSecrets.add(s); if (runtimeConfig.api?.secrets) for (const s of runtimeConfig.api.secrets) requiredSecrets.add(s); for (const plugin of Object.values(runtimeConfig.plugins ?? {})) if (plugin.secrets) for (const s of plugin.secrets) requiredSecrets.add(s); for (const secret of requiredSecrets) { const value = node_process.default.env[secret]; if (!value || value.length === 0) missingSecrets.push(secret); } if (missingSecrets.length > 0) warnings.push(`Missing ${missingSecrets.length} secret(s): ${missingSecrets.join(", ")}`); const services = require_service_descriptor.buildServiceDescriptorMap(runtimeConfig); const stagingEnvVars = isStaging ? { BOS_GATEWAY: config.staging?.domain ?? config.domain ?? "" } : {}; const summary = { configSource: remoteConfig ? `bos://${account}/${domain}` : require_config.findConfigPath() ?? "bos.config.json", configSourceHttp: remoteConfig && account && domain ? require_fastkv.buildRegistryConfigUrl(account, domain) : void 0, account: config.account, domain: config.domain ?? void 0, modules: { host: runtimeConfig.host.remoteUrl ?? runtimeConfig.host.url ?? "local", ui: runtimeConfig.ui.url ?? "local", api: runtimeConfig.api.url ?? "local", auth: runtimeConfig.auth?.url ?? void 0 }, warnings }; pendingSession = { orchestrator: { packages: ["host"], env: { NODE_ENV: "production", ...productionEnv, ...stagingEnvVars }, description: `${isStaging ? "Staging" : "Production"} Mode (${config.account})`, port, interactive: input.interactive, noLogs: true }, services, runtimeConfig }; pendingStartSummary = summary; pluginEvents.emit("progress", { phase: "config", status: "done" }); return { status: "running", url: `http://localhost:${port}` }; }), build: builder.build.handler(async ({ input }) => { if (!deps.bosConfig) return { status: "error", built: [], skipped: [] }; const buildEnv = input.deploy ? "production" : "development"; const targets = selectWorkspaceTargets(input.packages, deps.bosConfig); if (targets.length === 0) return { status: "error", built: [], skipped: [] }; const runtimeConfig = require_app.buildRuntimeConfig(deps.bosConfig, { uiSource: deps.bosConfig.app.ui?.development ? "local" : "remote", apiSource: deps.bosConfig.app.api?.development ? "local" : "remote", authSource: deps.bosConfig.app.auth?.development ? "local" : "remote", hostSource: deps.bosConfig.app.host?.development ? "local" : "remote", env: buildEnv, plugins: deps.runtimeConfig?.plugins }); await generateCodeArtifacts(deps.configDir, deps.bosConfig, { env: buildEnv, runtimeConfig }); const { built, skipped } = await buildWorkspaceTargets({ configDir: deps.configDir, bosConfig: deps.bosConfig, runtimeConfig, targets, deploy: input.deploy }); if (built.length === 0) return { status: "error", built: [], skipped }; return { status: "success", built, skipped, deployed: input.deploy }; }), publish: builder.publish.handler(async ({ input }) => { if (!deps.bosConfig) return { status: "error", registryUrl: "", error: "No bos.config.json found" }; const account = deps.bosConfig.account; const gateway = deps.bosConfig.domain; if (!gateway) return { status: "error", registryUrl: "", error: "bos.config.json must define domain to publish" }; const network = input.network ?? require_network.getNetworkIdForAccount(account); const bosUrl = `bos://${account}/${gateway}`; const registryUrl = require_fastkv.buildRegistryConfigUrlForNetwork(network, account, gateway); const targets = selectWorkspaceTargets(input.packages, deps.bosConfig); let publishConfig = deps.bosConfig; let built; let skipped; if (input.dryRun) return { status: "dry-run", registryUrl, built, skipped }; if (input.deploy) { await generateCodeArtifacts(deps.configDir, deps.bosConfig, { env: "production", runtimeConfig: deps.runtimeConfig ?? void 0 }); const result = await buildWorkspaceTargets({ configDir: deps.configDir, bosConfig: deps.bosConfig, runtimeConfig: deps.runtimeConfig, targets, deploy: true }); built = result.built; skipped = result.skipped; const refreshed = await require_config.loadConfig({ cwd: deps.configDir }); if (refreshed?.config) { deps.bosConfig = refreshed.config; deps.runtimeConfig = refreshed.runtime; publishConfig = refreshed.config; } } const registryEntries = { [`apps/${account}/${gateway}/bos.config.json`]: JSON.stringify(publishConfig) }; const payload = JSON.stringify(registryEntries); const argsBase64 = Buffer.from(payload).toString("base64"); const privateKey = input.privateKey || node_process.default.env.NEAR_PRIVATE_KEY || node_process.default.env.BOS_NEAR_PRIVATE_KEY; try { await effect.Effect.runPromise(require_near_cli.ensureNearCli); let txHash; try { txHash = (await effect.Effect.runPromise(require_near_cli.executeTransaction({ account, contract: require_fastkv.getRegistryNamespaceForNetwork(network), method: "__fastdata_kv", argsBase64, network, privateKey, gas: "300Tgas", deposit: "0NEAR" }))).txHash; } catch (error) { txHash = extractTransactionHash(error); if (!txHash) throw error; try { const verifiedConfig = await require_fastkv.fetchBosConfigFromFastKv(bosUrl); if (JSON.stringify(verifiedConfig) !== JSON.stringify(publishConfig)) throw error; } catch {} } return { status: "published", registryUrl, txHash, built, skipped }; } catch (error) { return { status: "error", registryUrl, error: error instanceof Error ? error.message : "Unknown error", built, skipped }; } }), keyPublish: builder.keyPublish.handler(async ({ input }) => { if (!deps.bosConfig) return { status: "error", account: "", network: "mainnet", contract: "", allowance: input.allowance, functionNames: PUBLISH_FUNCTION_NAMES, error: "No bos.config.json found" }; const account = deps.bosConfig.account; const network = require_network.getNetworkIdForAccount(account); const contract = require_fastkv.getRegistryNamespaceForAccount(account); try { await effect.Effect.runPromise(require_near_cli.ensureNearCli); const keyPair = await require_near_cli.addFunctionCallAccessKey({ account, contract, allowance: input.allowance, functionNames: PUBLISH_FUNCTION_NAMES, network }); return { status: "published", account, network, contract, allowance: input.allowance, functionNames: PUBLISH_FUNCTION_NAMES, publicKey: keyPair.publicKey, privateKey: keyPair.privateKey }; } catch (error) { return { status: "error", account, network, contract, allowance: input.allowance, functionNames: PUBLISH_FUNCTION_NAMES, error: error instanceof Error ? error.message : "Unknown error" }; } }), init: builder.init.handler(async ({ input }) => { try { const timings = []; let extendsAccount = ""; let extendsGateway = ""; let directory = input.directory; const account = input.account; const domain = input.domain; let overrides = input.overrides; let plugins = input.plugins; if (input.extends) { const match = (input.extends.startsWith("bos://") ? input.extends : `bos://${input.extends}`).match(/^bos:\/\/([^/]+)\/(.+)$/); if (match) { extendsAccount = match[1]; extendsGateway = match[2]; } } extendsAccount = extendsAccount || "dev.everything.near"; extendsGateway = extendsGateway || "everything.dev"; let parentPluginKeys = []; let parentConfig = null; try { parentConfig = await timePhase(timings, "parent config", () => require_cli_init.fetchParentConfig(extendsAccount, extendsGateway)); if (parentConfig?.plugins && typeof parentConfig.plugins === "object") parentPluginKeys = Object.keys(parentConfig.plugins); } catch {} overrides = overrides?.length ? overrides : ["ui", "api"]; if (overrides.includes("plugins") && plugins === void 0) plugins = parentPluginKeys; plugins = plugins ?? []; directory = directory || domain || extendsGateway; const targetDir = (0, node_path.resolve)(directory); const extendsRef = `bos://${extendsAccount}/${extendsGateway}`; const repository = await require_cli_init.detectGitRemoteUrl(node_process.default.cwd()).catch(() => void 0) ?? parentConfig?.repository; if (!parentConfig) try { parentConfig = await timePhase(timings, "parent config", () => require_cli_init.fetchParentConfig(extendsAccount, extendsGateway)); } catch { return { status: "error", directory, extendsRef, account, domain, extends: extendsRef, plugins, overrides, filesCopied: 0, timings, error: `No config found at ${extendsRef} — are you sure this is the right parent?` }; } const { sourceDir, parentConfig: resolvedParentConfig, cleanup } = await timePhase(timings, "template source", () => require_cli_init.resolveSourceDir({ extendsAccount, extendsGateway, source: input.source })); parentConfig = resolvedParentConfig; const isMinimalScaffold = sourceDir === ""; try { let filesCopied; if (isMinimalScaffold) { filesCopied = await timePhase(timings, "scaffold project", () => require_cli_init.scaffoldMinimalProject(targetDir, parentConfig, { extendsAccount, extendsGateway, account: account || extendsAccount, domain, plugins, overrides, repository, title: parentConfig?.title, description: parentConfig?.description })); await timePhase(timings, "personalize config", () => require_cli_init.personalizeConfig(targetDir, { extendsAccount, extendsGateway, account: account || extendsAccount, domain: domain || extendsGateway, plugins, overrides, mode: "init", repository, title: parentConfig?.title, description: parentConfig?.description, testnet: parentConfig?.testnet, staging: parentConfig?.staging })); } else { const patterns = require_cli_init.buildInitPatterns(overrides, plugins); filesCopied = await timePhase(timings, "copy files", () => require_cli_init.copyFilteredFiles(sourceDir, targetDir, patterns, { overrides, plugins })); await timePhase(timings, "personalize config", () => require_cli_init.personalizeConfig(targetDir, { extendsAccount, extendsGateway, account: account || extendsAccount, domain: domain || extendsGateway, plugins, overrides, workspaceOpts: { sourceDir }, repository, title: parentConfig?.title, description: parentConfig?.description, testnet: parentConfig?.testnet, staging: parentConfig?.staging })); await timePhase(timings, "write snapshot", () => require_cli_init.writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, { overrides, plugins })); } const lockfilePath = (0, node_path.join)(targetDir, "bun.lock"); require_cli_init.stripOrphanedWorkspacesFromLockfile(lockfilePath, computeAllowedWorkspaces(overrides, plugins)); require_cli_init.removeInitLockfile(lockfilePath); const initConfig = await timePhase(timings, "resolve config", () => require_config.loadConfig({ cwd: targetDir })); if (initConfig?.runtime) await timePhase(timings, "generate env/docker", async () => { require_infra.writeGeneratedInfra(targetDir, initConfig.runtime); }); await timePhase(timings, "create env file", async () => { require_infra.ensureEnvFile(targetDir); }); if (!input.noInstall) { await timePhase(timings, "install dependencies", () => require_cli_init.runBunInstall(targetDir)); await timePhase(timings, "generate types", () => require_cli_init.runTypesGen(targetDir)); await timePhase(timings, "generate migrations", () => require_cli_init.generateDatabaseMigrations(targetDir)); } if (input.noInstall && initConfig?.config) await timePhase(timings, "generate code artifacts", () => generateCodeArtifacts(targetDir, initConfig.config)); return { status: "initialized", directory, extendsRef, account, domain, extends: extendsRef, plugins, overrides, filesCopied, timings, targetDir }; } finally { await cleanup(); } } catch (error) { const extendsRef = input.extends ? input.extends.startsWith("bos://") ? input.extends : `bos://${input.extends}` : "bos://dev.everything.near/everything.dev"; return { status: "error", directory: input.directory ?? "", extendsRef, account: input.account, domain: input.domain, extends: extendsRef, plugins: input.plugins ?? [], overrides: input.overrides, filesCopied: 0, timings: [], error: error instanceof Error ? error.message : "Unknown error" }; } }), sync: builder.sync.handler(async ({ input }) => { try { const configPath = require_config.findConfigPath(); if (!configPath) return { status: "error", updated: [], skipped: [], added: [], error: "No bos.config.json found in current directory" }; const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath)); const result = await require_sync.syncTemplate(projectDir, input); if (result.status === "synced" || result.status === "dry-run") { const syncedConfig = await require_config.loadConfig({ cwd: projectDir }); if (syncedConfig?.config) await generateCodeArtifacts(projectDir, syncedConfig.config); } return result; } catch (error) { return { status: "error", updated: [], skipped: [], added: [], error: error instanceof Error ? error.message : "Unknown error" }; } }), upgrade: builder.upgrade.handler(async ({ input }) => { try { const configPath = require_config.findConfigPath(); if (!configPath) return { status: "error", packages: [], error: "No bos.config.json found in current directory" }; return await require_upgrade.upgradeTemplate((0, node_path.resolve)((0, node_path.dirname)(configPath)), input); } catch (error) { return { status: "error", packages: [], error: error instanceof Error ? error.message : "Unknown error" }; } }), typesGen: builder.typesGen.handler(async ({ input }) => { try { const configPath = require_config.findConfigPath(); if (!configPath) return { status: "error", generated: [], fetched: [], skipped: [], failed: [], error: "No bos.config.json found in current directory" }; const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath)); const refreshed = await require_config.loadConfig({ cwd: projectDir, env: input.env ?? (node_process.default.env.NODE_ENV === "production" ? "production" : "development") }); if (!refreshed) return { status: "error", generated: [], fetched: [], skipped: [], failed: [], error: "Failed to load bos.config.json" }; if (input.dryRun) { const pluginEntries = Object.entries(refreshed.runtime.plugins ?? {}); const fetched = []; const skipped = []; if (refreshed.runtime.api.source !== "local") fetched.push(refreshed.runtime.api.url); else skipped.push("api (local)"); if (refreshed.runtime.auth) if (refreshed.runtime.auth.source !== "local") fetched.push(refreshed.runtime.auth.url); else skipped.push("auth (local)"); for (const [key, plugin] of pluginEntries) if (plugin.url && plugin.source !== "local") fetched.push(plugin.url); else if (plugin.localPath) skipped.push(`${key} (local)`); const generated = [ "ui/src/lib/api-types.gen.ts", "ui/src/lib/auth-types.gen.ts", "api/src/lib/plugins-types.gen.ts", "api/src/lib/auth-types.gen.ts" ]; if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, "host", "src"))) generated.push("host/src/lib/auth-types.gen.ts"); return { status: "success", generated, fetched, skipped, failed: [], source: refreshed.runtime.api.source }; } await generateCodeArtifacts(projectDir, refreshed.config, { runtimeConfig: refreshed.runtime }); const generated = [ "ui/src/lib/plugin-sidebar.gen.ts", "ui/src/lib/api-types.gen.ts", "api/src/lib/plugins-types.gen.ts", "api/src/lib/auth-types.gen.ts" ]; if (refreshed.runtime.auth && (refreshed.runtime.auth.source !== "local" || refreshed.runtime.auth.localPath)) generated.push("ui/src/lib/auth-types.gen.ts"); if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, "host", "src"))) generated.push("host/src/lib/auth-types.gen.ts"); return { status: "success", generated, fetched: refreshed.runtime.api.source === "remote" ? [refreshed.runtime.api.url] : [], skipped: refreshed.runtime.api.source === "local" ? ["api (local)"] : [], failed: [], source: refreshed.runtime.api.source }; } catch (error) { return { status: "error", generated: [], fetched: [], skipped: [], failed: [], error: error instanceof Error ? error.message : "Unknown error" }; } }), status: builder.status.handler(async () => { try { const configPath = require_config.findConfigPath(); if (!configPath) return { status: "error", packages: [], envFile: "missing", error: "No bos.config.json found in current directory" }; return await require_status.getStatus((0, node_path.resolve)((0, node_path.dirname)(configPath))); } catch (error) { return { status: "error", packages: [], envFile: "missing", error: error instanceof Error ? error.message : "Unknown error" }; } }) }) }); function extractTransactionHash(error) { return (error instanceof Error ? error.message : String(error)).match(/Transaction ID:\s*([A-Za-z0-9]+)/i)?.[1]; } function computeAllowedWorkspaces(overrides, plugins) { const workspaces = []; for (const section of overrides) { if (section === "host") workspaces.push("host"); if (section === "ui") workspaces.push("ui"); if (section === "api") workspaces.push("api"); } if (plugins && plugins.length > 0) workspaces.push("plugins/*"); return workspaces; } //#endregion exports.consumeDevSession = consumeDevSession; exports.default = plugin_default; exports.pluginEvents = pluginEvents; //# sourceMappingURL=plugin.cjs.map