diff --git a/packages/widget/src/providers/api/api-client-provider.tsx b/packages/widget/src/providers/api/api-client-provider.tsx
index 078cffa2..95bd583a 100644
--- a/packages/widget/src/providers/api/api-client-provider.tsx
+++ b/packages/widget/src/providers/api/api-client-provider.tsx
@@ -1,5 +1,5 @@
import type { PropsWithChildren } from "react";
-import { createContext, useContext, useEffect, useMemo } from "react";
+import { createContext, useContext, useMemo } from "react";
import { config } from "../../config";
import { useSettings } from "../settings";
import { type ApiClient, createApiClient } from "./api-client";
@@ -19,8 +19,6 @@ export const SKApiClientProvider = ({ children }: PropsWithChildren) => {
[apiKey, baseUrl, yieldsApiUrl]
);
- useEffect(() => () => void apiClient.dispose(), [apiClient]);
-
return {children};
};
diff --git a/packages/widget/src/providers/api/api-client.ts b/packages/widget/src/providers/api/api-client.ts
index f441f2eb..21342630 100644
--- a/packages/widget/src/providers/api/api-client.ts
+++ b/packages/widget/src/providers/api/api-client.ts
@@ -21,6 +21,8 @@ type RunOptions = {
readonly signal?: AbortSignal;
};
+const runtime = ManagedRuntime.make(FetchHttpClient.layer);
+
const inspectResponse = ({
response,
}: {
@@ -66,8 +68,6 @@ const configureClient = ({
HttpClient.tap((response) => inspectResponse({ response }))
);
-type ApiRuntime = ManagedRuntime.ManagedRuntime;
-
type BoundOperation = Operation extends (
...args: infer Args
) => Effect.Effect
@@ -77,7 +77,6 @@ type BoundOperation = Operation extends (
const bindOperation = <
Operation extends (...args: never[]) => Effect.Effect,
>(
- runtime: ApiRuntime,
operation: Operation,
runOptions?: RunOptions
): BoundOperation =>
@@ -90,45 +89,36 @@ const bindOperation = <
const bindLegacyApi = ({
api,
runOptions,
- runtime,
}: {
readonly api: LegacyApi.LegacyApi;
readonly runOptions?: RunOptions;
- readonly runtime: ApiRuntime;
}) => ({
TokenControllerGetTokenBalances: bindOperation(
- runtime,
api.TokenControllerGetTokenBalances,
runOptions
),
TokenControllerGetTokenPrices: bindOperation(
- runtime,
api.TokenControllerGetTokenPrices,
runOptions
),
TokenControllerGetTokens: bindOperation(
- runtime,
api.TokenControllerGetTokens,
runOptions
),
TokenControllerTokenBalancesScan: bindOperation(
- runtime,
api.TokenControllerTokenBalancesScan,
runOptions
),
TransactionControllerGetTransactionVerificationMessageForNetwork:
bindOperation(
- runtime,
api.TransactionControllerGetTransactionVerificationMessageForNetwork,
runOptions
),
YieldControllerGetSingleYieldRewardsSummary: bindOperation(
- runtime,
api.YieldControllerGetSingleYieldRewardsSummary,
runOptions
),
YieldControllerYieldOpportunity: bindOperation(
- runtime,
api.YieldControllerYieldOpportunity,
runOptions
),
@@ -137,74 +127,56 @@ const bindLegacyApi = ({
const bindYieldApi = ({
api,
runOptions,
- runtime,
}: {
readonly api: YieldApi.YieldApi;
readonly runOptions?: RunOptions;
- readonly runtime: ApiRuntime;
}) => ({
ActionsControllerEnterYield: bindOperation(
- runtime,
api.ActionsControllerEnterYield,
runOptions
),
ActionsControllerExitYield: bindOperation(
- runtime,
api.ActionsControllerExitYield,
runOptions
),
ActionsControllerGetActions: bindOperation(
- runtime,
api.ActionsControllerGetActions,
runOptions
),
ActionsControllerManageYield: bindOperation(
- runtime,
api.ActionsControllerManageYield,
runOptions
),
- HealthControllerHealth: bindOperation(
- runtime,
- api.HealthControllerHealth,
- runOptions
- ),
+ HealthControllerHealth: bindOperation(api.HealthControllerHealth, runOptions),
NetworksControllerGetNetworks: bindOperation(
- runtime,
api.NetworksControllerGetNetworks,
runOptions
),
TransactionsControllerGetTransaction: bindOperation(
- runtime,
api.TransactionsControllerGetTransaction,
runOptions
),
TransactionsControllerSubmitTransaction: bindOperation(
- runtime,
api.TransactionsControllerSubmitTransaction,
runOptions
),
TransactionsControllerSubmitTransactionHash: bindOperation(
- runtime,
api.TransactionsControllerSubmitTransactionHash,
runOptions
),
YieldsControllerGetAggregateBalances: bindOperation(
- runtime,
api.YieldsControllerGetAggregateBalances,
runOptions
),
YieldsControllerGetYield: bindOperation(
- runtime,
api.YieldsControllerGetYield,
runOptions
),
YieldsControllerGetYieldBalances: bindOperation(
- runtime,
api.YieldsControllerGetYieldBalances,
runOptions
),
YieldsControllerGetYieldValidators: bindOperation(
- runtime,
api.YieldsControllerGetYieldValidators,
runOptions
),
@@ -213,16 +185,14 @@ const bindYieldApi = ({
const bindApiClients = ({
legacyApi,
runOptions,
- runtime,
yieldApi,
}: {
readonly legacyApi: LegacyApi.LegacyApi;
readonly runOptions?: RunOptions;
- readonly runtime: ApiRuntime;
readonly yieldApi: YieldApi.YieldApi;
}) => ({
- legacy: bindLegacyApi({ api: legacyApi, runOptions, runtime }),
- yield: bindYieldApi({ api: yieldApi, runOptions, runtime }),
+ legacy: bindLegacyApi({ api: legacyApi, runOptions }),
+ yield: bindYieldApi({ api: yieldApi, runOptions }),
});
export const createApiClient = ({
@@ -230,7 +200,6 @@ export const createApiClient = ({
baseUrl,
yieldsApiUrl,
}: WidgetApiClientOptions) => {
- const runtime = ManagedRuntime.make(FetchHttpClient.layer);
const baseClient = runtime.runSync(HttpClient.HttpClient);
const legacyHttpClient = configureClient({
@@ -245,13 +214,12 @@ export const createApiClient = ({
});
const legacyApi = LegacyApi.make(legacyHttpClient);
const yieldApi = YieldApi.make(yieldHttpClient);
- const boundClients = bindApiClients({ legacyApi, runtime, yieldApi });
+ const boundClients = bindApiClients({ legacyApi, yieldApi });
return {
...boundClients,
withRunOptions: (runOptions: RunOptions) =>
- bindApiClients({ legacyApi, runOptions, runtime, yieldApi }),
- dispose: () => runtime.dispose(),
+ bindApiClients({ legacyApi, runOptions, yieldApi }),
};
};
diff --git a/packages/widget/tests/providers/api-client.test.tsx b/packages/widget/tests/providers/api-client.test.tsx
index 325cda71..f22172d9 100644
--- a/packages/widget/tests/providers/api-client.test.tsx
+++ b/packages/widget/tests/providers/api-client.test.tsx
@@ -41,39 +41,31 @@ describe("API client", () => {
);
const client = createTestClient();
- try {
- await expect(
- client.legacy.TokenControllerGetTokens(undefined)
- ).resolves.toEqual([]);
- await expect(
- client.yield.HealthControllerHealth(undefined)
- ).resolves.toMatchObject({
- status: "OK",
- });
-
- expect(calls.map((call) => call.url)).toEqual([
- "https://api.example.com/v1/tokens",
- "https://yield.example.com/health",
- ]);
- expect(
- calls.every((call) => call.headers.get("X-API-KEY") === "test-key")
- ).toBe(true);
- } finally {
- client.dispose();
- }
+ await expect(
+ client.legacy.TokenControllerGetTokens(undefined)
+ ).resolves.toEqual([]);
+ await expect(
+ client.yield.HealthControllerHealth(undefined)
+ ).resolves.toMatchObject({
+ status: "OK",
+ });
+
+ expect(calls.map((call) => call.url)).toEqual([
+ "https://api.example.com/v1/tokens",
+ "https://yield.example.com/health",
+ ]);
+ expect(
+ calls.every((call) => call.headers.get("X-API-KEY") === "test-key")
+ ).toBe(true);
});
it("exposes only the generated operations currently used by the app", () => {
const client = createTestClient();
- try {
- expect("TokenControllerGetTokens" in client.legacy).toBe(true);
- expect("AuthControllerMe" in client.legacy).toBe(false);
- expect("YieldsControllerGetAggregateBalances" in client.yield).toBe(true);
- expect("ProvidersControllerGetProviders" in client.yield).toBe(false);
- } finally {
- client.dispose();
- }
+ expect("TokenControllerGetTokens" in client.legacy).toBe(true);
+ expect("AuthControllerMe" in client.legacy).toBe(false);
+ expect("YieldsControllerGetAggregateBalances" in client.yield).toBe(true);
+ expect("ProvidersControllerGetProviders" in client.yield).toBe(false);
});
it("records rich errors for failed StakeKit API responses", async ({
@@ -103,7 +95,6 @@ describe("API client", () => {
.poll(() => richError.result.current.error?.message)
.toBe("Rich failure");
} finally {
- client.dispose();
richError.unmount();
}
});
@@ -142,7 +133,6 @@ describe("API client", () => {
const value = geoBlock.result.current;
expect(value === false ? [] : [...value.tags]).toEqual(["staking"]);
} finally {
- client.dispose();
geoBlock.unmount();
}
});
@@ -163,14 +153,10 @@ describe("API client", () => {
);
const client = createTestClient();
- try {
- await expect(
- client.legacy.TokenControllerGetTokens(undefined)
- ).resolves.toEqual([]);
- expect(attempts).toBe(3);
- } finally {
- client.dispose();
- }
+ await expect(
+ client.legacy.TokenControllerGetTokens(undefined)
+ ).resolves.toEqual([]);
+ expect(attempts).toBe(3);
});
it("does not retry non-transient response statuses", async ({ worker }) => {
@@ -187,18 +173,14 @@ describe("API client", () => {
);
const client = createTestClient();
- try {
- await expect(
- client.legacy.TokenControllerGetTokens(undefined)
- ).rejects.toMatchObject({
- _tag: "TokenControllerGetTokens400",
- cause: { code: 400, message: "bad request" },
- response: { status: 400 },
- });
- expect(attempts).toBe(1);
- } finally {
- client.dispose();
- }
+ await expect(
+ client.legacy.TokenControllerGetTokens(undefined)
+ ).rejects.toMatchObject({
+ _tag: "TokenControllerGetTokens400",
+ cause: { code: 400, message: "bad request" },
+ response: { status: 400 },
+ });
+ expect(attempts).toBe(1);
});
it("does not retry aborted requests", async ({ worker }) => {
@@ -218,16 +200,12 @@ describe("API client", () => {
);
const client = createTestClient();
- try {
- await expect(
- client
- .withRunOptions({ signal: controller.signal })
- .legacy.TokenControllerGetTokens(undefined)
- ).rejects.toBeTruthy();
- expect(attempts).toBeLessThanOrEqual(1);
- } finally {
- client.dispose();
- }
+ await expect(
+ client
+ .withRunOptions({ signal: controller.signal })
+ .legacy.TokenControllerGetTokens(undefined)
+ ).rejects.toBeTruthy();
+ expect(attempts).toBeLessThanOrEqual(1);
});
it("waits for delayed API requests before resolving successful responses", async ({
@@ -261,7 +239,6 @@ describe("API client", () => {
expect(resolved).toBe(true);
} finally {
- client.dispose();
releaseDelay();
env.isTestMode = originalIsTestMode;
}
diff --git a/packages/widget/vite/vite.config.package.ts b/packages/widget/vite/vite.config.package.ts
index aef44450..ee3d4c58 100644
--- a/packages/widget/vite/vite.config.package.ts
+++ b/packages/widget/vite/vite.config.package.ts
@@ -2,40 +2,32 @@ import path from "node:path";
import { defineConfig, esmExternalRequirePlugin } from "vite";
import { getConfig } from "./vite.config.base";
-const reactExternals = [/^react(?:\/.*)?$/, /^react-dom(?:\/.*)?$/];
-
-const config = getConfig(
- {
- define: {
- // Drop dead AMD branches from bundled UMD dependencies so Next Turbopack
- // does not resolve their dependency arrays as real relative imports.
- define: "undefined",
+const config = getConfig({
+ define: {
+ // Drop dead AMD branches from bundled UMD dependencies so Next Turbopack
+ // does not resolve their dependency arrays as real relative imports.
+ define: "undefined",
+ },
+ build: {
+ lib: {
+ entry: path.resolve(__dirname, "..", "src/index.package.ts"),
+ name: "StakeKit",
+ fileName: "index.package",
+ formats: ["es"],
},
- build: {
- lib: {
- entry: path.resolve(__dirname, "..", "src/index.package.ts"),
- name: "StakeKit",
- fileName: "index.package",
- formats: ["es"],
- },
- rolldownOptions: {
- external: reactExternals,
- output: { banner: '"use client";\n' },
- },
- copyPublicDir: false,
- minify: false,
- outDir: "dist/package",
- sourcemap: false,
+ rolldownOptions: {
+ output: { banner: '"use client";\n' },
+ plugins: [
+ esmExternalRequirePlugin({
+ external: [/^react(-dom)?(\/.+)?$/],
+ }),
+ ],
},
+ copyPublicDir: false,
+ minify: false,
+ outDir: "dist/package",
+ sourcemap: false,
},
- {
- plugins: [
- esmExternalRequirePlugin({
- external: reactExternals,
- skipDuplicateCheck: true,
- }),
- ],
- }
-);
+});
export default defineConfig(config);