everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 17 kB
Source Map (JSON)
{"version":3,"file":"keys.cjs","names":["Context","BosDepsTag","MISSING_CONFIG_MESSAGE","getNetworkIdForAccount","getRegistryNamespaceForAccount","Effect","ensureNearCli","listPublishKeys","addFunctionCallAccessKey","colors","deleteAccessKeys","startDeviceLogin","openInBrowser","process","readSessionHandle","generateNearKeyPair","join","nearCredentialsPath","parseKey"],"sources":["../../src/commands/keys.ts"],"sourcesContent":["import { join } from \"node:path\";\nimport process from \"node:process\";\nimport { Context, Effect } from \"effect\";\nimport { type KeyPair, parseKey } from \"near-kit\";\nimport { openInBrowser, startDeviceLogin } from \"../auth-login\";\nimport {\n deleteSessionHandle,\n nearCredentialsPath,\n readSessionHandle,\n removePublishedKeyFile,\n type SessionCredential,\n writeSessionHandle,\n} from \"../auth-session\";\nimport { MISSING_CONFIG_MESSAGE } from \"../config\";\nimport type { LoginResult } from \"../contract\";\nimport { getRegistryNamespaceForAccount } from \"../fastkv\";\nimport {\n addFunctionCallAccessKey,\n deleteAccessKeys,\n ensureNearCli,\n generateNearKeyPair,\n listPublishKeys,\n} from \"../near-cli\";\nimport { getNetworkIdForAccount } from \"../network\";\nimport type { ResolutionSession } from \"../resolution/session\";\nimport { colors } from \"../utils/theme\";\nimport { type BosBuilder, BosDepsTag } from \"./shared\";\n\nconst PUBLISH_FUNCTION_NAMES = [\"__fastdata_kv\"];\n\nexport function registerKeys(builder: BosBuilder) {\n return {\n keyPublish: builder.keyPublish.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const session = deps.session;\n if (!session?.config) {\n return {\n status: \"error\" as const,\n account: \"\",\n network: \"mainnet\" as const,\n env: input.env,\n contract: \"\",\n allowance: input.allowance,\n functionNames: PUBLISH_FUNCTION_NAMES,\n error: MISSING_CONFIG_MESSAGE,\n };\n }\n\n const account =\n input.env === \"staging\"\n ? (session.config.staging?.account ?? session.config.account)\n : session.config.account;\n const network = getNetworkIdForAccount(account);\n const contract = getRegistryNamespaceForAccount(account, input.registry);\n try {\n await Effect.runPromise(ensureNearCli);\n\n const oldKeys = await listPublishKeys({ account, contract, network });\n\n const keyPair = await addFunctionCallAccessKey({\n account,\n contract,\n allowance: input.allowance,\n functionNames: PUBLISH_FUNCTION_NAMES,\n network,\n });\n\n if (oldKeys.length > 0) {\n console.log();\n console.log(\n ` Found ${oldKeys.length} existing publish key${oldKeys.length > 1 ? \"s\" : \"\"}:`,\n );\n for (const k of oldKeys) {\n console.log(` ${colors.dim(k)}`);\n }\n\n if (input.removeOldKeys !== false) {\n try {\n await deleteAccessKeys(account, oldKeys, network);\n console.log(\n ` ${colors.green(\"✓\")} Removed ${oldKeys.length} old key${\n oldKeys.length > 1 ? \"s\" : \"\"\n }`,\n );\n } catch {\n console.log(\n ` ${colors.yellow(\"⚠\")} Failed to remove old key${\n oldKeys.length > 1 ? \"s\" : \"\"\n } (new key still active)`,\n );\n }\n } else {\n console.log(` ${colors.dim(\"Old key(s) retained.\")}`);\n }\n }\n\n return {\n status: \"published\" as const,\n account,\n network,\n env: input.env,\n contract,\n allowance: input.allowance,\n functionNames: PUBLISH_FUNCTION_NAMES,\n publicKey: keyPair.publicKey,\n privateKey: keyPair.privateKey,\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n account,\n network,\n env: input.env,\n contract,\n allowance: input.allowance,\n functionNames: PUBLISH_FUNCTION_NAMES,\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }),\n\n login: builder.login.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const staging = input.env === \"staging\";\n const account = staging\n ? (deps.session?.config?.staging?.account ?? deps.session?.config?.account ?? \"\")\n : (deps.session?.config?.account ?? \"\");\n\n try {\n const siteUrl = resolveLoginSiteUrl(input.site, deps.session, staging);\n const login = await startDeviceLogin({\n siteUrl,\n device: input.device,\n account: account || undefined,\n expiresIn: input.expiresIn,\n });\n\n console.log();\n console.log(` One-time code: ${colors.cyan(login.userCode)}`);\n await openInBrowser(login.verificationUrl).catch((error: unknown) => {\n console.log(colors.yellow(` ⚠ ${(error as Error).message}`));\n });\n console.log();\n console.log(` Waiting for approval at ${colors.dim(login.verificationUrl)}…`);\n\n const approval = await login.waitForApproval();\n\n if (!approval.apiKey) {\n return {\n status: \"error\" as const,\n siteUrl,\n loginUrl: login.verificationUrl,\n error: \"Login approved but no CLI credential was created\",\n };\n }\n\n const expiresAt = new Date(Date.now() + input.expiresIn * 1000).toISOString();\n writeSessionHandle(deps.session?.root ?? process.cwd(), {\n version: 1,\n credential: {\n kind: \"session\",\n apiKey: approval.apiKey.key,\n apiKeyId: approval.apiKey.id,\n accountId: approval.accountId,\n label: input.device ?? siteUrl,\n siteUrl,\n createdAt: new Date().toISOString(),\n expiresAt,\n },\n publishKey: null,\n delegateKey: null,\n });\n\n let warning: string | null = null;\n if (account && approval.accountId && approval.accountId !== account) {\n warning = `Logged in as ${approval.accountId}, but the authored config account is ${account}. Publishes will use the configured account.`;\n }\n\n let publishKey: LoginResult[\"publishKey\"] = null;\n if (input.key) {\n try {\n publishKey = await exportPublishKey(account, input.registry);\n } catch (error) {\n warning = `Session stored, but publish-key export failed: ${\n error instanceof Error ? error.message : \"unknown error\"\n }`;\n }\n }\n\n return {\n status: \"logged-in\" as const,\n siteUrl,\n accountId: approval.accountId,\n expiresAt,\n loginUrl: login.verificationUrl,\n publishKey,\n warning,\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n siteUrl: input.site ?? \"\",\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }),\n\n logout: builder.logout.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const configDir = input.configDir ?? deps.session?.root ?? process.cwd();\n\n try {\n const session = readSessionHandle(configDir);\n let revokedApiKey = false;\n let removedPublishKey = false;\n let warning: string | null = null;\n\n if (session?.credential) {\n revokedApiKey = await revokeApiKey(session.credential).catch(() => false);\n if (!revokedApiKey) {\n warning =\n \"Could not revoke the API key remotely — revoke it manually under Settings → API keys.\";\n }\n }\n\n if (session?.publishKey) {\n const account = session.credential?.accountId ?? deps.session?.config?.account ?? \"\";\n removePublishedKeyFile(session.publishKey.network, account, session.publishKey.publicKey);\n removedPublishKey = true;\n warning = warning\n ? `${warning} Re-run ${colors.cyan(\"bos login --key\")} to re-export a publish key.`\n : \"Removed the exported publish key. Re-run bos login --key to re-export one.\";\n }\n\n deleteSessionHandle(configDir);\n return {\n status: \"logged-out\" as const,\n revokedApiKey,\n removedPublishKey,\n warning,\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n revokedApiKey: false,\n removedPublishKey: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }),\n };\n}\n\nfunction resolveLoginSiteUrl(\n siteInput: string | undefined,\n session: ResolutionSession | null,\n staging: boolean,\n): string {\n if (siteInput) {\n return siteInput.replace(/\\/+$/, \"\");\n }\n if (staging) {\n const stagingDomain = session?.config?.staging?.domain ?? session?.config?.domain;\n return stagingDomain ? `https://${stagingDomain}` : (session?.runtime?.ui?.url ?? \"\");\n }\n const devUiUrl = session?.runtime?.ui?.url;\n if (devUiUrl && /^https?:\\/\\/(localhost|127\\.0\\.0\\.1)/.test(devUiUrl)) {\n return devUiUrl.replace(/\\/+$/, \"\");\n }\n const domain = session?.config?.domain;\n return domain ? `https://${domain}` : \"\";\n}\n\nasync function exportPublishKey(\n account: string,\n registry: string | undefined,\n): Promise<NonNullable<LoginResult[\"publishKey\"]>> {\n if (!account) {\n throw new Error(\"the authored config has no account to export a publish key for\");\n }\n\n await Effect.runPromise(ensureNearCli);\n\n const network = getNetworkIdForAccount(account);\n const contract = getRegistryNamespaceForAccount(account, registry);\n await listPublishKeys({ account, contract, network });\n\n const keyPair = generateNearKeyPair();\n await addFunctionCallAccessKey({\n account,\n contract,\n allowance: \"1NEAR\",\n functionNames: PUBLISH_FUNCTION_NAMES,\n network,\n keyPair,\n });\n\n const { FileKeyStore } = await import(\"near-kit/keys/file\");\n const keyStore = new FileKeyStore(\"~/.near-credentials\", network);\n await keyStore.add(account, parseNearPrivateKey(keyPair.privateKey));\n try {\n const { statSync, chmodSync } = await import(\"node:fs\");\n const { homedir } = await import(\"node:os\");\n const credentialPath = join(\n homedir(),\n \".near-credentials\",\n network === \"mainnet\" ? \"mainnet\" : network,\n `${account}.json`,\n );\n if (statSync(credentialPath).mode & 0o077) {\n chmodSync(credentialPath, 0o600);\n }\n } catch {}\n\n return {\n publicKey: keyPair.publicKey,\n network,\n contract,\n exportedTo: nearCredentialsPath(network, account),\n };\n}\nfunction parseNearPrivateKey(privateKey: string): KeyPair {\n return parseKey(privateKey) as KeyPair;\n}\n\nasync function revokeApiKey(credential: SessionCredential): Promise<boolean> {\n if (!credential.apiKey || !credential.siteUrl) return false;\n try {\n const response = await fetch(`${credential.siteUrl}/api/auth/api-key/delete`, {\n method: \"POST\",\n headers: {\n \"x-api-key\": credential.apiKey,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({ keyId: credential.apiKeyId }),\n signal: AbortSignal.timeout(10_000),\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n"],"mappings":"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"}