everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
105 lines (103 loc) • 4.01 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
let _orpc_client = require("@orpc/client");
let _orpc_client_fetch = require("@orpc/client/fetch");
let _orpc_tanstack_query = require("@orpc/tanstack-query");
let _tanstack_react_router = require("@tanstack/react-router");
//#region src/ui/api.ts
function createRpcLink(config, url, headers) {
return new _orpc_client_fetch.RPCLink({
origin: config.hostUrl,
url,
interceptors: [(0, _orpc_client.onError)((error) => {
if (typeof window === "undefined") return;
if (error && typeof error === "object" && "message" in error) {
const message = String(error.message).toLowerCase();
if (message.includes("fetch") || message.includes("network") || message.includes("failed to fetch")) import("sonner").then(({ toast }) => {
const message = config.connectionError?.() ?? {
title: "Unable to connect to API",
description: "The API is currently unavailable. Please try again later."
};
toast.error(message.title, {
id: "api-connection-error",
description: message.description
});
}).catch(() => {});
}
})],
fetch(fetchUrl, options) {
return fetchWithRateLimitRetry(fetchUrl, {
...options,
credentials: "include",
headers: headers ? {
...Object.fromEntries(headers),
...options?.headers
} : options?.headers
});
}
});
}
const RATE_LIMIT_MAX_RETRIES = 3;
const RATE_LIMIT_RETRY_CAP_MS = 2e3;
/**
* A 429 from the host's edge limiter is transient saturation, not an
* application failure — retry within the server's `Retry-After` (capped) so
* queries and the session check self-heal instead of surfacing errors.
*/
async function fetchWithRateLimitRetry(fetchUrl, options) {
let response = await fetch(fetchUrl, options);
for (let attempt = 1; attempt <= RATE_LIMIT_MAX_RETRIES && response.status === 429; attempt++) {
const retryAfterSeconds = Number(response.headers.get("retry-after"));
const delay = Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0 ? Math.min(retryAfterSeconds * 1e3, RATE_LIMIT_RETRY_CAP_MS) : 100 * attempt;
await new Promise((resolve) => setTimeout(resolve, delay));
response = await fetch(fetchUrl, options);
}
return response;
}
function buildClient(config, url, headers) {
if (!config.hostUrl) throw new Error("Missing runtime host URL");
return (0, _orpc_client.createORPCClient)(createRpcLink(config, url, headers));
}
const browserClients = /* @__PURE__ */ new Map();
function memoizedClient(config, url, headers) {
if (typeof window !== "undefined" && !headers) {
const key = `${config.hostUrl}${url}`;
const memoized = browserClients.get(key);
if (memoized) return memoized;
const client = buildClient(config, url, headers);
browserClients.set(key, client);
return client;
}
return buildClient(config, url, headers);
}
function createApiClient(config, headers) {
return memoizedClient(config, config.rpcBase, headers);
}
function createPluginApiClient(pluginKey, config, headers) {
return memoizedClient(config, `${config.rpcBase}/${pluginKey}`, headers);
}
function createServiceClients(config, keys, headers) {
const clients = {};
for (const key of keys) if (key === "api") clients[key] = createApiClient(config, headers);
else clients[key] = createPluginApiClient(key, config, headers);
return clients;
}
function useClientContext() {
return (0, _tanstack_react_router.useRouter)().options.context;
}
function useApiClient() {
return useClientContext().apiClient;
}
function useOrpc() {
return (0, _orpc_tanstack_query.createTanstackQueryUtils)(useApiClient());
}
function usePluginClients() {
return useClientContext().pluginClients ?? {};
}
//#endregion
exports.createApiClient = createApiClient;
exports.createPluginApiClient = createPluginApiClient;
exports.createServiceClients = createServiceClients;
exports.useApiClient = useApiClient;
exports.useOrpc = useOrpc;
exports.usePluginClients = usePluginClients;
//# sourceMappingURL=api.cjs.map