{"version":3,"file":"publish.mjs","names":[],"sources":["../src/publish.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport process from \"node:process\";\nimport { Effect } from \"effect\";\nimport { buildWorkspaceTargets, selectWorkspaceTargets } from \"./build\";\nimport { generateCodeArtifacts } from \"./code-artifacts\";\nimport { loadResolvedConfig } from \"./config\";\nimport type { WorkspaceDeployResult } from \"./contract\";\nimport {\n  buildRegistryConfigUrlForNetwork,\n  fetchBosConfigFromFastKv,\n  getRegistryNamespaceForNetwork,\n} from \"./fastkv\";\nimport { ensureNearCli, executeTransaction, resolveNearSigningMode } from \"./near-cli\";\nimport { getNetworkIdForAccount } from \"./network\";\nimport type { BosConfig, BosConfigInput, RuntimeConfig } from \"./types\";\nimport { padRight } from \"./utils/string\";\nimport { colors, icons } from \"./utils/theme\";\n\nfunction sleep(ms: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function extractPublishedUrl(output: string): string | null {\n  const deployMatch = output.match(/🚀.*Deployed:\\s*(https?:\\S+)/);\n  if (deployMatch) return deployMatch[1];\n  const match = output.match(/https?:\\/\\/[^\\s\"'<>]+/g);\n  if (!match || match.length === 0) return null;\n  return match[match.length - 1] ?? null;\n}\n\nexport async function waitForPublishedConfig(opts: {\n  account: string;\n  gateway: string;\n  publishConfig: BosConfigInput;\n  timeoutMs?: number;\n  intervalMs?: number;\n}): Promise<void> {\n  const envTimeoutMs = Number(process.env.BOS_PUBLISH_CONFIRMATION_TIMEOUT_MS);\n  const envIntervalMs = Number(process.env.BOS_PUBLISH_CONFIRMATION_INTERVAL_MS);\n  const timeoutMs =\n    opts.timeoutMs ?? (Number.isFinite(envTimeoutMs) ? envTimeoutMs : undefined) ?? 120_000;\n  const intervalMs =\n    opts.intervalMs ?? (Number.isFinite(envIntervalMs) ? envIntervalMs : undefined) ?? 3_000;\n  const startedAt = Date.now();\n  let lastError: unknown;\n\n  while (Date.now() - startedAt < timeoutMs) {\n    try {\n      const verifiedConfig = await fetchBosConfigFromFastKv<BosConfigInput>(\n        `bos://${opts.account}/${opts.gateway}`,\n      );\n\n      if (JSON.stringify(verifiedConfig) === JSON.stringify(opts.publishConfig)) {\n        return;\n      }\n    } catch (error) {\n      lastError = error;\n    }\n\n    await sleep(intervalMs);\n  }\n\n  const reason = lastError instanceof Error ? ` Last error: ${lastError.message}` : \"\";\n  throw new Error(\n    `Timed out waiting for publish confirmation at bos://${opts.account}/${opts.gateway}.${reason}`,\n  );\n}\n\ninterface PublishToFastKvInput {\n  bosConfig: BosConfig;\n  runtimeConfig: RuntimeConfig | null;\n  configDir: string;\n  env: \"production\" | \"staging\";\n  build: boolean;\n  dryRun: boolean;\n  verbose: boolean;\n  packages: string;\n  network?: \"mainnet\" | \"testnet\";\n  privateKey?: string;\n}\n\ninterface PublishToFastKvResult {\n  status: \"published\" | \"error\" | \"dry-run\";\n  registryUrl: string;\n  txHash?: string;\n  built?: string[];\n  skipped?: string[];\n  error?: string;\n  publishConfig?: BosConfigInput;\n  deployResults?: WorkspaceDeployResult[];\n}\n\nexport async function publishToFastKv(input: PublishToFastKvInput): Promise<PublishToFastKvResult> {\n  const { env, dryRun, configDir } = input;\n  let bosConfig = input.bosConfig;\n  const runtimeConfig = input.runtimeConfig;\n\n  const isStaging = env === \"staging\";\n  const account = bosConfig.account;\n  const gateway = isStaging ? (bosConfig.staging?.domain ?? bosConfig.domain) : bosConfig.domain;\n  if (!gateway) {\n    return {\n      status: \"error\",\n      registryUrl: \"\",\n      error: \"bos.config.json must define domain to publish\",\n    };\n  }\n\n  const network = input.network ?? getNetworkIdForAccount(account);\n  const registryUrl = buildRegistryConfigUrlForNetwork(network, account, gateway);\n  const targets = selectWorkspaceTargets(input.packages, bosConfig);\n\n  let built: string[] | undefined;\n  let skipped: string[] | undefined;\n  let deployResults: WorkspaceDeployResult[] | undefined;\n\n  if (dryRun) {\n    return { status: \"dry-run\", registryUrl, built, skipped };\n  }\n\n  const privateKey =\n    input.privateKey || process.env.NEAR_PRIVATE_KEY || process.env.BOS_NEAR_PRIVATE_KEY;\n  let signingMode: ReturnType<typeof resolveNearSigningMode>;\n  try {\n    signingMode = resolveNearSigningMode(privateKey);\n  } catch (error) {\n    return {\n      status: \"error\" as const,\n      registryUrl,\n      error: error instanceof Error ? error.message : \"Unknown error\",\n    };\n  }\n\n  if (input.build) {\n    console.log(\"  Ensuring NEAR CLI...\");\n    await Effect.runPromise(ensureNearCli);\n    console.log(\"  NEAR CLI ready\");\n\n    await generateCodeArtifacts(configDir, bosConfig, {\n      env: \"production\",\n      runtimeConfig: runtimeConfig ?? undefined,\n    });\n\n    const result = await buildWorkspaceTargets({\n      configDir,\n      bosConfig,\n      runtimeConfig,\n      targets,\n      deploy: true,\n      verbose: input.verbose,\n    });\n    built = result.built;\n    skipped = result.skipped;\n    deployResults = result.deployResults;\n\n    if (deployResults) {\n      const failures = deployResults.filter((r) => !r.success);\n      if (failures.length > 0) {\n        const total = deployResults.length;\n        console.log();\n        console.log(\n          colors.error(\n            `  ${icons.err} Deploy failed — ${failures.length} of ${total} workspace${total > 1 ? \"s\" : \"\"} failed`,\n          ),\n        );\n        console.log();\n        for (const f of failures) {\n          const errorLine = (f.error ?? \"Failed\").split(\"\\n\")[0];\n          console.log(`    ${colors.error(icons.err)} ${padRight(f.key, 28)} ${errorLine}`);\n        }\n        console.log();\n        if (!input.verbose) {\n          console.log(colors.dim(\"  Run with --verbose for full build output.\"));\n          console.log();\n        }\n        return {\n          status: \"error\" as const,\n          registryUrl,\n          built,\n          skipped,\n          deployResults,\n          error: `${failures.length} of ${total} workspaces failed to deploy`,\n        };\n      }\n    }\n\n    const refreshed = await loadResolvedConfig({ cwd: configDir });\n    if (!refreshed?.config) {\n      return {\n        status: \"error\",\n        registryUrl,\n        built,\n        skipped,\n        deployResults,\n        error: \"Failed to reload bos.config.json after build\",\n      };\n    }\n\n    bosConfig = refreshed.config;\n  }\n\n  const rawConfigPath = join(configDir, \"bos.config.json\");\n  const rawConfig = JSON.parse(readFileSync(rawConfigPath, \"utf-8\")) as BosConfigInput;\n  const publishPayload: BosConfigInput = isStaging ? { ...rawConfig, domain: gateway } : rawConfig;\n\n  const registryEntries: Record<string, string> = {\n    [`apps/${account}/${gateway}/bos.config.json`]: JSON.stringify(publishPayload),\n  };\n\n  const payload = JSON.stringify(registryEntries);\n  const argsBase64 = Buffer.from(payload).toString(\"base64\");\n\n  console.log();\n  console.log(\"  Publishing to:\");\n  console.log(`    ${colors.cyan(registryUrl)}`);\n\n  try {\n    let txHash: string | undefined;\n\n    console.log(`  Submitting transaction on ${network}...`);\n\n    try {\n      const tx = await Effect.runPromise(\n        executeTransaction(\n          {\n            account,\n            contract: getRegistryNamespaceForNetwork(network),\n            method: \"__fastdata_kv\",\n            argsBase64,\n            network,\n            privateKey: signingMode._tag === \"privateKey\" ? signingMode.privateKey : undefined,\n            gas: \"300Tgas\",\n            deposit: \"0NEAR\",\n            verbose: input.verbose,\n          },\n          signingMode,\n        ),\n      );\n      txHash = tx.txHash;\n      if (txHash && !tx.output?.includes(\"CodeDoesNotExist\")) {\n        console.log(`  Transaction submitted: ${colors.dim(txHash)}`);\n      }\n    } catch (error) {\n      console.log(colors.dim(\"  Transaction reported an error — verifying publish...\"));\n      try {\n        await waitForPublishedConfig({\n          account,\n          gateway,\n          publishConfig: publishPayload,\n          timeoutMs: 30_000,\n          intervalMs: 2_000,\n        });\n        txHash = extractTransactionHash(error);\n      } catch {\n        throw error;\n      }\n    }\n\n    console.log(\"  Waiting for publish confirmation...\");\n    await waitForPublishedConfig({\n      account,\n      gateway,\n      publishConfig: publishPayload,\n    });\n\n    return {\n      status: \"published\",\n      registryUrl,\n      txHash,\n      built,\n      skipped,\n      deployResults,\n      publishConfig: publishPayload,\n    };\n  } catch (error) {\n    return {\n      status: \"error\",\n      registryUrl,\n      error: formatNearError(error),\n      built,\n      skipped,\n      deployResults,\n    };\n  }\n}\n\nfunction formatNearError(error: unknown): string {\n  const message = error instanceof Error ? error.message : String(error);\n\n  if (message.includes(\"exceeded gas\") || message.includes(\"GasLimitExceeded\")) {\n    return `Transaction exceeded gas limit.\\n  Original: ${message}`;\n  }\n\n  if (message.includes(\"timeout\") || message.includes(\"Timeout\")) {\n    return `Transaction timed out. Check NEAR network status.\\n  Original: ${message}`;\n  }\n\n  return message;\n}\n\nfunction extractTransactionHash(error: unknown) {\n  const message = error instanceof Error ? error.message : String(error);\n  const match = message.match(/Transaction ID:\\s*([A-Za-z0-9]+)/i);\n  return match?.[1];\n}\n"],"mappings":"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"}