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