everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
130 lines (128 loc) • 6.85 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_http_client = require('./http-client.cjs');
//#region src/fastkv.ts
function getNetworkIdForAccount(accountId) {
return accountId.endsWith(".testnet") ? "testnet" : "mainnet";
}
const FASTKV_TESTNET_URL = "https://kv.test.fastnear.com";
const FASTKV_MAINNET_URL = "https://kv.main.fastnear.com";
const REGISTRY_NAMESPACE_TESTNET = "dev.allthethings.testnet";
const REGISTRY_NAMESPACE_MAINNET = "dev.everything.near";
function getFastKvBaseUrlForNetwork(network) {
return network === "testnet" ? FASTKV_TESTNET_URL : FASTKV_MAINNET_URL;
}
function getFastKvBaseUrlForAccount(accountId) {
return getNetworkIdForAccount(accountId) === "testnet" ? getFastKvBaseUrlForNetwork("testnet") : getFastKvBaseUrlForNetwork("mainnet");
}
function buildRegistryConfigUrl(accountId, gatewayId, registry) {
const baseUrl = getFastKvBaseUrlForAccount(accountId);
const namespace = getRegistryNamespaceForAccount(accountId, registry);
const key = encodeURIComponent(getRegistryConfigKey(accountId, gatewayId));
return `${baseUrl}/v0/latest/${encodeURIComponent(namespace)}/${encodeURIComponent(accountId)}/${key}`;
}
function buildRegistryConfigUrlForNetwork(network, accountId, gatewayId, registry) {
const baseUrl = getFastKvBaseUrlForNetwork(network);
const namespace = getRegistryNamespaceForNetwork(network, registry);
const key = encodeURIComponent(getRegistryConfigKey(accountId, gatewayId));
return `${baseUrl}/v0/latest/${encodeURIComponent(namespace)}/${encodeURIComponent(accountId)}/${key}`;
}
function getRegistryNamespaceForAccount(accountId, registry) {
return registry ?? getRegistryNamespaceForNetwork(getNetworkIdForAccount(accountId));
}
function getRegistryNamespaceForNetwork(network, registry) {
if (registry) return registry;
return network === "testnet" ? REGISTRY_NAMESPACE_TESTNET : REGISTRY_NAMESPACE_MAINNET;
}
function getRegistryConfigKey(accountId, gatewayId, pathSegments = []) {
return `apps/${accountId}/${gatewayId}${pathSegments.length > 0 ? `/${pathSegments.map((segment) => encodeURIComponent(segment)).join("/")}` : ""}/bos.config.json`;
}
function parseBosUrl(bosUrl) {
const match = bosUrl.split("#")[0].match(/^bos:\/\/([^/]+)\/(.+)$/);
if (!match?.[1] || !match[2]) throw new Error(`Invalid BOS URL: ${bosUrl}`);
const pathSegments = match[2].split("/").filter(Boolean).map((segment) => decodeURIComponent(segment));
if (pathSegments.length === 0) throw new Error(`Invalid BOS URL: ${bosUrl}`);
const [gatewayId, ...pathSegmentsTail] = pathSegments;
if (!gatewayId) throw new Error(`Invalid BOS URL: ${bosUrl}`);
return {
accountId: match[1],
gatewayId,
pathSegments: pathSegmentsTail
};
}
async function fetchBosConfigFromFastKv(bosUrl, registry) {
const { accountId, gatewayId, pathSegments } = parseBosUrl(bosUrl);
const key = encodeURIComponent(getRegistryConfigKey(accountId, gatewayId, pathSegments));
const value = (await fetchJson(`${getFastKvBaseUrlForAccount(accountId)}/v0/latest/${encodeURIComponent(getRegistryNamespaceForAccount(accountId, registry))}/${encodeURIComponent(accountId)}/${key}`))?.entries?.find(Boolean)?.value;
if (!value) throw new Error(`No config found for ${bosUrl}`);
if (typeof value === "string") return JSON.parse(value);
if (typeof value !== "object") throw new Error(`Invalid config value for ${bosUrl}`);
return value;
}
const FASTKV_HISTORY_MAX_LIMIT = 200;
/**
* Publish history for the registry config key (atomic-deploys 11): the
* exact-key variant of FastData's history endpoint, newest-first. The API
* caps a page at 200 rows; a config key's write history fits well inside
* that, so a single request is the whole story (the limit param is clamped).
*/
async function fetchConfigHistory(opts) {
const key = encodeURIComponent(getRegistryConfigKey(opts.accountId, opts.gatewayId));
const limit = Math.max(1, Math.min(opts.limit ?? 20, FASTKV_HISTORY_MAX_LIMIT));
return ((await fetchJson(`${getFastKvBaseUrlForAccount(opts.accountId)}/v0/history/${encodeURIComponent(getRegistryNamespaceForAccount(opts.accountId, opts.registry))}/${encodeURIComponent(opts.accountId)}/${key}?limit=${limit}`))?.entries ?? []).filter(Boolean).map((entry) => ({
blockHeight: entry.block_height ?? 0,
blockTimestampNs: String(entry.block_timestamp ?? ""),
...entry.tx_hash ? { txHash: entry.tx_hash } : {},
value: typeof entry.value === "string" && entry.value.length > 0 ? JSON.parse(entry.value) : entry.value
})).sort((a, b) => b.blockHeight - a.blockHeight);
}
/**
* The per-deploy audit trail (atomic-deploys 03/12): every publish writes
* `apps/<account>/<gateway>/manifests/<ts>.json` atomically with the pointer
* swap — this lists that key family newest-first via the history-by-prefix
* endpoint.
*/
async function fetchDeployManifests(opts) {
const keyPrefix = encodeURIComponent(`${getRegistryConfigKey(opts.accountId, opts.gatewayId).replace(/bos\.config\.json$/, "")}manifests/`);
return ((await fetchJson(`${getFastKvBaseUrlForAccount(opts.accountId)}/v0/history/${encodeURIComponent(getRegistryNamespaceForAccount(opts.accountId, opts.registry))}/${encodeURIComponent(opts.accountId)}`, {
method: "POST",
body: JSON.stringify({
key_prefix: decodeURIComponent(keyPrefix),
asc: false,
limit: Math.max(1, Math.min(opts.limit ?? 20, FASTKV_HISTORY_MAX_LIMIT))
})
}))?.entries ?? []).filter(Boolean).map((entry) => ({
key: entry.key ?? "",
blockHeight: entry.block_height ?? 0,
blockTimestampNs: String(entry.block_timestamp ?? ""),
value: typeof entry.value === "string" && entry.value.length > 0 ? JSON.parse(entry.value) : entry.value
})).sort((a, b) => b.blockHeight - a.blockHeight);
}
async function fetchRemotePluginManifest(cdnUrl) {
const baseUrl = cdnUrl.replace(/\/$/, "");
return require_http_client.fetchJsonOrNull(`${baseUrl}/plugin.manifest.json`, { retries: 2 });
}
async function fetchJson(url, init) {
const headers = {
accept: "application/json",
"content-type": "application/json",
...init?.headers
};
return require_http_client.fetchJsonOrNull(url, {
method: init?.method,
headers,
body: init?.body ?? void 0,
retries: 3
});
}
//#endregion
exports.buildRegistryConfigUrl = buildRegistryConfigUrl;
exports.buildRegistryConfigUrlForNetwork = buildRegistryConfigUrlForNetwork;
exports.fetchBosConfigFromFastKv = fetchBosConfigFromFastKv;
exports.fetchConfigHistory = fetchConfigHistory;
exports.fetchDeployManifests = fetchDeployManifests;
exports.fetchRemotePluginManifest = fetchRemotePluginManifest;
exports.getFastKvBaseUrlForNetwork = getFastKvBaseUrlForNetwork;
exports.getRegistryNamespaceForAccount = getRegistryNamespaceForAccount;
exports.getRegistryNamespaceForNetwork = getRegistryNamespaceForNetwork;
exports.parseBosUrl = parseBosUrl;
//# sourceMappingURL=fastkv.cjs.map