everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
176 lines (174 loc) • 8.34 kB
JavaScript
const require_runtime = require('../../_virtual/_rolldown/runtime.cjs');
const require_http_client = require('../../utils/http-client.cjs');
const require_services_registry_fastkv = require('../registry/fastkv.cjs');
const require_network = require('../../utils/network.cjs');
const require_theme = require('../../utils/theme.cjs');
const require_build_train = require('../workspace/build-train.cjs');
const require_session = require('../auth/session.cjs');
const require_near_signer = require('../auth/near-signer.cjs');
const require_cdn = require('./cdn.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);
//#region src/services/deploy/preflight.ts
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_services_registry_fastkv.buildRegistryConfigUrlForNetwork(network, account, gateway, input.registry);
const fail = (error) => ({
kind: "error",
registryUrl,
error
});
const sessionFile = require_session.readSessionHandle(configDir);
const publishAuth = bosConfig.publish?.auth;
const governsWalletPublish = (publishAuth === "session" || input.wallet) && !input.privateKey;
let credential;
if (governsWalletPublish) {
if (!sessionFile?.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 (sessionFile.credential.accountId && sessionFile.credential.accountId !== account) return fail(`The CLI session was created for ${sessionFile.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.`);
credential = sessionFile.credential;
}
const useCustody = publishAuth === "custody" && !input.privateKey && !input.wallet;
let custodyWallet;
if (useCustody) {
const wallet = sessionFile?.custodyWallet;
if (!wallet) return fail("the authored config sets publish.auth = \"custody\", but no custody wallet is stored in .bos/. Run `bos login --custody` first.");
if (wallet.network !== network) return fail(`The custody wallet was registered on ${wallet.network}, but this project publishes on ${network}. Run \`bos login --custody\` from a ${network} account.`);
if (wallet.nearAccountId !== account) return fail(`publish.auth = "custody" publishes under the custody wallet's account, but the configured account is ${account} and the custody wallet account is ${wallet.nearAccountId}. Set the authored config's account to the custody wallet account.`);
custodyWallet = wallet;
}
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");
}
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.resolveCdnDeployInputs({
env: node_process.default.env,
bosConfig,
session: sessionFile?.credential ?? null,
custodyAccount: useCustody ? custodyWallet?.nearAccountId : void 0,
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.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_services_registry_fastkv.fetchPublishedConfigFromFastKv(registryUrl);
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_services_registry_fastkv.getRegistryNamespaceForNetwork(network, input.registry),
targets: require_build_train.selectWorkspaceTargets(input.packages, bosConfig),
useWallet,
useCustody,
strategy,
cdnOrigin: cdnDeploy.cdnOrigin,
storageOrigin: cdnDeploy.storageOrigin,
storageApiKey: cdnDeploy.apiKey,
publishedConfig,
publishedConfigState,
...custodyWallet ? { custodyWallet } : {},
...credential ? { credential } : {}
}
};
}
//#endregion
exports.findUnpublishedFrameworkPackages = findUnpublishedFrameworkPackages;
exports.npmVersionPublished = npmVersionPublished;
exports.preflightPublish = preflightPublish;
//# sourceMappingURL=preflight.cjs.map