UNPKG

everything-dev

Version:

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

708 lines (706 loc) • 28.7 kB
const require_runtime = require('./_virtual/_rolldown/runtime.cjs'); const require_http_client = require('./http-client.cjs'); const require_merge = require('./merge.cjs'); const require_fastkv = require('./fastkv.cjs'); const require_network = require('./network.cjs'); const require_version_manifest_resolve = require('./version-manifest-resolve.cjs'); const require_config = require('./config.cjs'); const require_theme = require('./utils/theme.cjs'); const require_resolution_session = require('./resolution/session.cjs'); const require_fingerprint = require('./fingerprint.cjs'); const require_integrity = require('./integrity.cjs'); const require_timing = require('./cli/timing.cjs'); const require_string = require('./utils/string.cjs'); const require_build = require('./build.cjs'); const require_code_artifacts = require('./code-artifacts.cjs'); const require_auth_session = require('./auth-session.cjs'); const require_cdn_deploy = require('./cdn-deploy.cjs'); const require_delegate_signer = require('./delegate-signer.cjs'); const require_rollback = require('./rollback.cjs'); const require_deploy_diff = require('./deploy-diff.cjs'); const require_near_signer = require('./near-signer.cjs'); const require_platform_deploy = require('./platform-deploy.cjs'); const require_storage_upload = require('./storage-upload.cjs'); const require_version_manifest_deploy = require('./version-manifest-deploy.cjs'); let node_fs = require("node:fs"); let node_path = require("node:path"); let node_process = require("node:process"); node_process = require_runtime.__toESM(node_process, 1); let every_plugin_build_ui = require("every-plugin/build/ui"); //#region src/publish.ts function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } async function pinWorkspaceVersionManifest(input) { if (!input.report) return void 0; const versionManifest = require_version_manifest_deploy.composeWorkspaceVersionManifest({ report: input.report, ssrReport: input.ssrReport, integrityMap: input.integrityMap, ...input.files ? { files: input.files } : {} }); if (!versionManifest) return void 0; const manifestFile = `versions/${versionManifest.version}.json`; const manifestUpload = await require_storage_upload.uploadBundle({ origin: input.origin, apiKey: input.apiKey, account: input.account, gateway: input.gateway, workspace: input.workspace, files: [{ path: manifestFile, bytes: new TextEncoder().encode(`${JSON.stringify(versionManifest, null, 2)}\n`) }] }); const manifestIntegrity = manifestUpload.integrity[manifestFile]; if (!manifestIntegrity) return void 0; console.log(` ${require_theme.colors.dim(`${require_string.padRight("", 28)} version manifest ${manifestFile} (SRI pinned)`)}`); return { file: manifestFile, integrity: manifestIntegrity, storage: manifestUpload.storage }; } /** * One workspace's upload leg with skip-unchanged diffing: resolve the previous * manifest's `files` map, hash the local dist, upload only new/changed files, * and return the merged per-file SRI map for the version manifest. Any failure * to resolve the previous map degrades to a full upload. */ async function diffUploadWorkspace(input) { const localSri = require_deploy_diff.localSriMap(input.files); let uploadFiles = input.files; let prevFiles; if (input.previousPin) try { const resolved = await require_version_manifest_resolve.resolveSlotVersion({ base: input.base, pin: input.previousPin }); if (resolved.files) { const diff = require_deploy_diff.diffWorkspaceFiles(input.files, localSri, resolved.files); prevFiles = resolved.files; uploadFiles = diff.upload; if (diff.skipped > 0) console.log(` ${require_theme.colors.dim(`${require_string.padRight(input.workspace, 28)} ${diff.skipped} unchanged file(s) — skipping (manifest diff)`)}`); } } catch { console.log(` ${require_theme.colors.dim(`${require_string.padRight(input.workspace, 28)} previous manifest unusable — uploading everything`)}`); } console.log(` ${require_string.padRight(input.workspace, 28)} uploading ${uploadFiles.length} of ${input.files.length} files (${formatBundleMb(uploadFiles)}) → ${input.base}`); const result = uploadFiles.length > 0 ? await require_storage_upload.uploadWorkspaceDist({ origin: input.origin, apiKey: input.apiKey, account: input.account, gateway: input.gateway, workspace: input.workspace, files: uploadFiles }) : { stored: 0, totalBytes: 0, integrity: {}, storage: void 0 }; return { result, fileIntegrity: require_deploy_diff.mergedFileIntegrity(input.files, result.integrity, prevFiles), uploaded: result.stored, skipped: input.files.length - uploadFiles.length, total: input.files.length }; } function formatBundleMb(files) { return `${(files.reduce((sum, file) => sum + file.bytes.byteLength, 0) / 1024 / 1024).toFixed(1)} MB`; } async function waitForPublishedConfig(opts) { const envTimeoutMs = Number(node_process.default.env.BOS_PUBLISH_CONFIRMATION_TIMEOUT_MS); const envIntervalMs = Number(node_process.default.env.BOS_PUBLISH_CONFIRMATION_INTERVAL_MS); const timeoutMs = opts.timeoutMs ?? (Number.isFinite(envTimeoutMs) ? envTimeoutMs : void 0) ?? 12e4; const intervalMs = opts.intervalMs ?? (Number.isFinite(envIntervalMs) ? envIntervalMs : void 0) ?? 3e3; const startedAt = Date.now(); let lastError; while (Date.now() - startedAt < timeoutMs) { try { const verifiedConfig = await require_fastkv.fetchBosConfigFromFastKv(`bos://${opts.account}/${opts.gateway}`, opts.registry); if (JSON.stringify(verifiedConfig) === JSON.stringify(opts.publishConfig)) return; } catch (error) { lastError = error; } await sleep(intervalMs); } const reason = lastError instanceof Error ? ` Last error: ${lastError.message}` : ""; throw new Error(`Timed out waiting for publish confirmation at bos://${opts.account}/${opts.gateway}.${reason}`); } async function isConfigAlreadyPublished(opts) { try { const current = await require_fastkv.fetchBosConfigFromFastKv(`bos://${opts.account}/${opts.gateway}`, opts.registry); return JSON.stringify(current) === JSON.stringify(opts.publishConfig); } catch { return false; } } const FRAMEWORK_PACKAGE_NAMES = [ "better-near-auth", "every-plugin", "everything-dev" ]; /** * Whether npm serves `name@version` (true), definitively does not (404 — * false), or whether publishability could not be determined (network error, * unexpected status — null; callers must not block on that). */ async function npmVersionPublished(name, version) { try { const res = await require_http_client.fetchResponse(`https://registry.npmjs.org/${name}/${version}`, { headers: { Accept: "application/json" } }); if (res.status === 200) return true; if (res.status === 404) return false; return null; } catch { return null; } } /** * The npm-publish gate: a workspace that vendors the framework packages' * sources must not ship bundles ahead of npm — the update check, child * scaffolds (`bos init`), and template syncs all read those versions from * the registry. Reads only apply when the sources are workspace-local (the * parent repo); child projects install the framework from npm and are * inherently in sync. */ async function findUnpublishedFrameworkPackages(configDir) { const unpublished = []; for (const name of FRAMEWORK_PACKAGE_NAMES) { const manifestPath = (0, node_path.join)(configDir, "packages", name, "package.json"); if (!(0, node_fs.existsSync)(manifestPath)) continue; const version = JSON.parse((0, node_fs.readFileSync)(manifestPath, "utf-8")).version; if (!version) continue; const published = await npmVersionPublished(name, version); if (published === false) unpublished.push({ name, version }); else if (published === null) console.log(require_theme.colors.yellow(` ! Could not verify ${name}@${version} on npm (registry unreachable) — continuing`)); } return unpublished; } async function preflightPublish(input) { const { configDir } = input; const bosConfig = input.bosConfig; const isStaging = input.env === "staging"; const account = isStaging ? bosConfig.staging?.account ?? bosConfig.account : bosConfig.account; const gateway = isStaging ? bosConfig.staging?.domain ?? bosConfig.domain : bosConfig.domain; if (!gateway) return { kind: "error", registryUrl: "", error: "authored config must define domain to publish" }; const network = input.network ?? require_network.getNetworkIdForAccount(account); const registryUrl = require_fastkv.buildRegistryConfigUrlForNetwork(network, account, gateway, input.registry); const fail = (error) => ({ kind: "error", registryUrl, error }); const publishAuth = bosConfig.publish?.auth; if ((publishAuth === "session" || input.wallet) && !input.privateKey) { const session = require_auth_session.readSessionHandle(configDir); if (!session?.credential) return fail((input.wallet ? "--wallet requires" : "the authored config sets publish.auth = \"session\", but") + " no CLI session is stored in .bos/ for this project. Run bos login to create one."); if (session.credential.accountId && session.credential.accountId !== account) return fail(`The CLI session was created for ${session.credential.accountId}, but the configured account is ${account}. Gasless wallet publish relays the FastKV write under the session's NEAR account. Run bos login again under the matching account.`); } if (publishAuth && !input.privateKey) { if (publishAuth === "custody") return fail("the authored config sets publish.auth = \"custody\", but custody publish is not implemented yet (see NEARBuilders/everything-dev#291)."); } if (input.dryRun) return { kind: "dry-run", registryUrl }; const useWallet = input.wallet === true; let strategy; if (useWallet) console.log(` Signing via ${require_theme.colors.cyan("gasless NEP-366 delegate action (relayed by the platform relayer)")}`); else try { strategy = await require_near_signer.resolveSigningStrategy({ privateKey: input.privateKey, account, network }); console.log(` Signing via ${require_theme.colors.cyan(require_near_signer.describeSigningStrategy(strategy))}`); } catch (error) { return fail(error instanceof Error ? error.message : "Unknown error"); } const session = require_auth_session.readSessionHandle(configDir); let cdnDeploy = { cdnOrigin: void 0, storageOrigin: "", apiKey: void 0 }; if (input.build) { const unpublished = await findUnpublishedFrameworkPackages(configDir); if (unpublished.length > 0) return fail(`Framework package(s) ${unpublished.map((pkg) => `${pkg.name}@${pkg.version}`).join(", ")} are not published to npm yet — deploys must not ship bundles ahead of the registry (child scaffolds and update checks read these versions). Re-run the Release workflow (or \`pnpm run release\`) first.`); cdnDeploy = require_cdn_deploy.resolveCdnDeployInputs({ env: node_process.default.env, bosConfig, session: session?.credential ?? null, account, gateway, uploadsPlanned: input.build }); if (cdnDeploy.error) return fail(cdnDeploy.error); if (cdnDeploy.warning) console.log(require_theme.colors.yellow(` ! ${cdnDeploy.warning}`)); if (!cdnDeploy.cdnOrigin) return fail("CDN deploy resolved no bundle origin"); const probeError = await require_cdn_deploy.probeStorageOrigin(cdnDeploy.storageOrigin); if (probeError) return fail(`The bundle upload origin ${cdnDeploy.storageOrigin} is not running the platform API — ${probeError}. Check BOS_STORAGE_ORIGIN / the bos login session, then re-run.`); } let publishedConfig = null; let publishedConfigState = "missing"; try { publishedConfig = await require_fastkv.fetchBosConfigFromFastKv(registryUrl, input.registry); publishedConfigState = "fetched"; } catch (error) { if ((error instanceof Error ? error.message : String(error)).startsWith("No config found")) console.log(require_theme.colors.dim(" Note: no published config found yet (first publish) — continuing")); else { publishedConfigState = "unreachable"; console.log(require_theme.colors.dim(" Note: registry read failed — continuing")); } } return { kind: "ready", plan: { isStaging, account, gateway, network, registryUrl, registryNamespace: require_fastkv.getRegistryNamespaceForNetwork(network, input.registry), targets: require_build.selectWorkspaceTargets(input.packages, bosConfig), useWallet, strategy, cdnOrigin: cdnDeploy.cdnOrigin, storageOrigin: cdnDeploy.storageOrigin, storageApiKey: cdnDeploy.apiKey, publishedConfig, publishedConfigState } }; } /** * The deploy-train publish core (ADR 0020, as amended): preflight * (storage/CDN creds + signing) fails fast before the build, then build → * upload → version-manifest pin → config write-back → FastKV publish + * read-back. Scoped to one plugin via `packages`, a single-plugin redeploy * ships real bytes to the storage origin — same as the full train, nothing * image-native left. */ async function publishToFastKv(input) { const preflight = await preflightPublish(input); if (preflight.kind === "error") return { status: "error", registryUrl: preflight.registryUrl, error: preflight.error }; if (preflight.kind === "dry-run") return { status: "dry-run", registryUrl: preflight.registryUrl }; const plan = preflight.plan; const { isStaging, account, gateway, network, registryUrl, registryNamespace, targets, useWallet, strategy } = plan; const storageOrigin = plan.storageOrigin; const storageApiKey = plan.storageApiKey; const { configDir } = input; let bosConfig = input.bosConfig; const runtimeConfig = input.runtimeConfig; let built; let skipped; let deployResults; let refreshedRawConfig = null; if (input.build) { await require_code_artifacts.generateCodeArtifacts(configDir, bosConfig, { env: "production", runtimeConfig: runtimeConfig ?? void 0 }); const result = await require_build.buildWorkspaceTargets({ configDir, bosConfig, runtimeConfig, targets, deploy: true, verbose: input.verbose }); built = result.built; skipped = result.skipped; deployResults = result.deployResults; if (deployResults) { const failures = deployResults.filter((r) => !r.success); if (failures.length > 0) { const total = deployResults.length; console.log(); console.log(require_theme.colors.error(` ${require_theme.icons.err} Deploy failed — ${failures.length} of ${total} workspace${total > 1 ? "s" : ""} failed`)); console.log(); for (const f of failures) { const errorLine = (f.error ?? "Failed").split("\n")[0]; console.log(` ${require_theme.colors.error(require_theme.icons.err)} ${require_string.padRight(f.key, 28)} ${errorLine}`); } console.log(); if (!input.verbose) { console.log(require_theme.colors.dim(" Run with --verbose for full build output.")); console.log(); } return { status: "error", registryUrl, built, skipped, deployResults, error: `${failures.length} of ${total} workspaces failed to deploy` }; } } const refreshed = await require_resolution_session.openResolution({ cwd: configDir }); if (!refreshed?.config) return { status: "error", registryUrl, built, skipped, deployResults, error: "Failed to reload the config after build" }; bosConfig = refreshed.config; refreshedRawConfig = refreshed.rawConfig; } const authoredPath = require_config.findConfigPath(configDir); const tsForm = authoredPath !== null && require_config.isAppDescriptorPath(authoredPath); let rawConfig; if (refreshedRawConfig) rawConfig = refreshedRawConfig; else { const opened = await require_resolution_session.openResolution({ cwd: configDir }); if (!opened?.rawConfig) return { status: "error", registryUrl, built, skipped, deployResults, error: "Failed to load the authored config for publish" }; rawConfig = opened.rawConfig; } if (tsForm && !input.build && plan.publishedConfigState === "unreachable") return { status: "error", registryUrl, built, skipped, deployResults, error: "Cannot read the currently published config from the registry — a config-only publish would overwrite live bundle URLs. Retry when the registry is reachable, or run a full deploy." }; let publishPayload = tsForm && !input.build ? require_merge.mergeAuthoredOverPublished(plan.publishedConfig ?? {}, rawConfig) : rawConfig; const urlOrigin = plan.cdnOrigin ?? `https://${gateway}`; const deployTargets = (built ?? []).filter((key) => targets.includes(key)); const platformEntries = []; const prevPins = input.fullUpload === true || node_process.default.env.BOS_FULL_UPLOAD === "1" ? {} : { ...require_deploy_diff.pinsFromPublishedConfig(plan.publishedConfig ?? {}, account, gateway), ...require_deploy_diff.pinsFromDeployState(configDir, account, gateway) }; console.log(); console.log(` CDN deploy — uploading workspace dists to ${storageOrigin}...`); for (const key of deployTargets) { const ws = require_build.resolveWorkspaceTarget(key, bosConfig, runtimeConfig, configDir); if (!ws) continue; const distFiles = await require_storage_upload.collectDistFiles((0, node_path.join)(ws.path, "dist")); const workspaceBase = `${urlOrigin}/bundles/${account}/${gateway}/${key}/`; const startedAt = Date.now(); let outcome; try { outcome = await diffUploadWorkspace({ origin: storageOrigin, apiKey: storageApiKey, account, gateway, workspace: key, files: distFiles, base: workspaceBase, previousPin: prevPins[key] }); } catch (error) { return { status: "error", registryUrl, built, skipped, deployResults, error: error instanceof Error ? error.message : `[publish] bundle upload for ${key} failed` }; } const report = require_version_manifest_deploy.readBuildReport((0, node_path.join)(ws.path, "dist")); const ssrReport = require_version_manifest_deploy.readBuildReport((0, node_path.join)(ws.path, "dist", "ssr")); const integrity = report ? outcome.fileIntegrity[report.entry] : void 0; const ssrIntegrity = ssrReport?.entry ? outcome.fileIntegrity[`ssr/${ssrReport.entry}`] : void 0; const manifestPointer = await pinWorkspaceVersionManifest({ origin: storageOrigin, apiKey: storageApiKey, account, gateway, workspace: key, report, ssrReport, integrityMap: outcome.fileIntegrity, files: outcome.fileIntegrity }); if (!manifestPointer) return { status: "error", registryUrl, built, skipped, deployResults, error: `bundle upload for ${key}: version manifest missing — the dist predates hashed entry names (rebuild required; atomic-deploys hard break)` }; if (outcome.result.storage === "memory" || manifestPointer.storage === "memory") return { status: "error", registryUrl, built, skipped, deployResults, error: "The receiving instance is serving bundle storage from memory (BOS_STORAGE_* R2 credentials are not configured there) — uploaded bytes would be lost on restart. Aborting before publish." }; console.log(` ${require_theme.colors.green(require_theme.icons.ok)} ${require_string.padRight(key, 28)} → ${urlOrigin}/bundles/${account}/${gateway}/${key}/ (${outcome.uploaded} uploaded, ${outcome.skipped} skipped, ${require_timing.formatDuration(Date.now() - startedAt)})`); platformEntries.push(...require_platform_deploy.platformUrlDeployEntries({ origin: urlOrigin, account, gateway, key, kind: ws.kind, integrity, ssrIntegrity, pin: manifestPointer })); if ((0, every_plugin_build_ui.hasFolderFormUi)(ws.path)) { const uiDistDir = (0, node_path.join)(ws.path, "ui", "dist"); const rawUi = ((ws.kind === "app" ? "app" : "plugins") === "app" ? rawConfig.app : rawConfig.plugins)?.[key]?.ui; const uiName = require_config.resolveUiRuntimeName(rawUi, (0, node_path.join)(ws.path, "ui"), key); let uiIntegrity; let uiSsrIntegrity; let uiManifestPointer; if ((0, node_fs.existsSync)(uiDistDir)) { const uiDistFiles = await require_storage_upload.collectDistFiles(uiDistDir); const uiStartedAt = Date.now(); const uiOutcome = await diffUploadWorkspace({ origin: storageOrigin, apiKey: storageApiKey, account, gateway, workspace: `${key}-ui`, files: uiDistFiles, base: `${urlOrigin}/bundles/${account}/${gateway}/${key}-ui/`, previousPin: prevPins[`${key}-ui`] }); const uiReport = require_version_manifest_deploy.readBuildReport(uiDistDir); const uiSsrReport = require_version_manifest_deploy.readBuildReport((0, node_path.join)(uiDistDir, "ssr")); uiIntegrity = uiReport ? uiOutcome.fileIntegrity[uiReport.entry] : void 0; uiSsrIntegrity = uiSsrReport?.entry ? uiOutcome.fileIntegrity[`ssr/${uiSsrReport.entry}`] : void 0; uiManifestPointer = await pinWorkspaceVersionManifest({ origin: storageOrigin, apiKey: storageApiKey, account, gateway, workspace: `${key}-ui`, report: uiReport, ssrReport: uiSsrReport, integrityMap: uiOutcome.fileIntegrity, files: uiOutcome.fileIntegrity }); if (!uiManifestPointer) return { status: "error", registryUrl, built, skipped, deployResults, error: `bundle upload for ${key}-ui: version manifest missing — the dist predates hashed entry names (rebuild required; atomic-deploys hard break)` }; if (uiOutcome.result.storage === "memory" || uiManifestPointer.storage === "memory") return { status: "error", registryUrl, built, skipped, deployResults, error: "The receiving instance is serving bundle storage from memory (BOS_STORAGE_* R2 credentials are not configured there) — uploaded bytes would be lost on restart. Aborting before publish." }; console.log(` ${require_theme.colors.green(require_theme.icons.ok)} ${require_string.padRight(`${key}-ui`, 28)} → ${urlOrigin}/bundles/${account}/${gateway}/${key}-ui/ (${uiOutcome.uploaded} uploaded, ${uiOutcome.skipped} skipped, ${require_timing.formatDuration(Date.now() - uiStartedAt)})`); } else console.log(` ${require_theme.colors.green(require_theme.icons.ok)} ${require_string.padRight(`${key}-ui`, 28)} → ${urlOrigin}/bundles/${account}/${gateway}/${key}-ui/`); platformEntries.push(...require_platform_deploy.pluginUiUrlDeployEntries({ origin: urlOrigin, account, gateway, key, kind: ws.kind, integrity: uiIntegrity, ssrIntegrity: uiSsrIntegrity, name: uiName, pin: uiManifestPointer })); } } if (platformEntries.length > 0) { const merged = require_integrity.applyDeployResults(rawConfig, platformEntries); if (!tsForm) try { (0, node_fs.writeFileSync)((0, node_path.join)(configDir, "bos.config.json"), `${JSON.stringify(merged, null, 2)}\n`); } catch (error) { return { status: "error", registryUrl, built, skipped, deployResults, error: `Failed to write bundle URLs to bos.config.json: ${error instanceof Error ? error.message : String(error)}` }; } publishPayload = merged; } if (isStaging) publishPayload = { ...publishPayload, domain: gateway }; const pinVerification = await require_rollback.verifyRollbackSnapshot(publishPayload); if (pinVerification.verifiable && !pinVerification.ok) { const failures = pinVerification.slots.filter((check) => !check.ok).map((check) => ` ${check.slot}: ${check.reason}`).join("\n"); console.error(` ${require_theme.colors.error(require_theme.icons.err)} Publish blocked — a pinned slot's bytes do not serve at its production URL:\n${failures}`); return { status: "error", registryUrl, built, skipped, deployResults, error: `Publish blocked — pinned slot bytes missing or SRI mismatched:\n${failures}` }; } const registryKey = `apps/${account}/${gateway}/bos.config.json`; const publishedAt = (/* @__PURE__ */ new Date()).toISOString(); const fingerprint = require_fingerprint.pointerFingerprint(publishPayload); const publishSlotPins = require_fingerprint.slotPins(publishPayload); const registryEntries = { [registryKey]: JSON.stringify(publishPayload) }; const manifestKey = `apps/${account}/${gateway}/manifests/${publishedAt.replace(/[:.]/g, "-")}.json`; registryEntries[manifestKey] = JSON.stringify({ account, gateway, network, publishedAt, registryUrl }); console.log(); console.log(" Publishing to:"); console.log(` ${require_theme.colors.cyan(registryUrl)}`); console.log(` ${require_theme.colors.dim("Fingerprint:")} ${fingerprint}`); for (const [slot, pin] of Object.entries(publishSlotPins)) { console.log(` ${require_theme.colors.dim(`${slot}:`)}`); console.log(` ${pin}`); } console.log(` ${require_theme.colors.dim(`+ per-deploy manifest ${manifestKey.split("/").pop()} (audit trail)`)}`); const persistDeployState = () => { try { const pins = require_deploy_diff.pinsFromPublishedConfig(publishPayload, account, gateway); if (Object.keys(pins).length > 0) require_deploy_diff.upsertDeployStatePins(configDir, account, gateway, pins); } catch (error) { console.log(require_theme.colors.dim(` Note: could not update .bos/deploy-state.json — ${error instanceof Error ? error.message : String(error)}`)); } }; try { if (await isConfigAlreadyPublished({ account, gateway, publishConfig: publishPayload, registry: input.registry })) { console.log(" Already up to date — skipping transaction"); persistDeployState(); return { status: "published", registryUrl, built, skipped, deployResults, publishConfig: publishPayload }; } console.log(` Submitting transaction on ${network}...`); let result; if (useWallet) { const credential = require_auth_session.readSessionHandle(configDir)?.credential; if (!credential || credential.accountId !== account) return { status: "error", registryUrl, error: `--wallet requires a CLI session under ${account}. Run bos login first.` }; const record = await require_delegate_signer.ensureDelegateKey({ configDir, account, contract: registryNamespace, network, siteUrl: credential.siteUrl }); result = await require_delegate_signer.submitRegistryWriteDelegated({ account, contract: registryNamespace, network, args: registryEntries, delegatePrivateKey: record.privateKey, relayEndpoint: `${credential.siteUrl}/api/auth/near/relay`, apiKey: credential.apiKey }); } else { if (!strategy) return { status: "error", registryUrl, error: "non-wallet publish requires a resolved signing strategy" }; result = await require_near_signer.submitRegistryWrite({ account, contract: registryNamespace, method: "__fastdata_kv", args: registryEntries, network, privateKey: input.privateKey }, strategy); } if (result.txHash) console.log(` Transaction submitted: ${require_theme.colors.dim(result.txHash)}`); console.log(" Waiting for publish confirmation..."); await waitForPublishedConfig({ account, gateway, publishConfig: publishPayload, registry: input.registry }); persistDeployState(); return { status: "published", registryUrl, txHash: result.txHash, fingerprint, slotPins: publishSlotPins, built, skipped, deployResults, publishConfig: publishPayload }; } catch (error) { return { status: "error", registryUrl, error: formatNearError(error), built, skipped, deployResults }; } } function formatNearError(error) { const message = error instanceof Error ? error.message : String(error); if (message.includes("does not have enough allowance")) return `The publish access key has insufficient allowance to cover this transaction. Regenerate your key with a higher allowance: bos key generate Original: ${message}`; if (message.includes("exceeded gas") || message.includes("GasLimitExceeded")) return `Transaction exceeded gas limit.\n Original: ${message}`; if (message.includes("timeout") || message.includes("Timeout")) return `Transaction timed out. Check NEAR network status.\n Original: ${message}`; return message; } //#endregion exports.findUnpublishedFrameworkPackages = findUnpublishedFrameworkPackages; exports.isConfigAlreadyPublished = isConfigAlreadyPublished; exports.npmVersionPublished = npmVersionPublished; exports.preflightPublish = preflightPublish; exports.publishToFastKv = publishToFastKv; exports.waitForPublishedConfig = waitForPublishedConfig; //# sourceMappingURL=publish.cjs.map