chore: refactored hub initialization

This commit is contained in:
Tiago Farto
2026-02-25 13:38:19 +00:00
parent 77cd1e9bd1
commit 1e7830d850
4 changed files with 47 additions and 29 deletions
+26
View File
@@ -0,0 +1,26 @@
import "server-only";
import FormbricksHub from "@formbricks/hub";
import { env } from "@/lib/env";
const globalForHub = globalThis as unknown as {
formbricksHubClient: FormbricksHub | undefined;
};
/**
* Returns a shared Formbricks Hub API client when HUB_API_KEY is set.
* Uses a global singleton so the same instance is reused across the process
* (and across Next.js HMR in development). When the key is not set, returns
* null and does not cache that result so a later call with the key set
* can create the client.
*/
export function getHubClient(): FormbricksHub | null {
if (globalForHub.formbricksHubClient) {
return globalForHub.formbricksHubClient;
}
const apiKey = env.HUB_API_KEY;
if (!apiKey) return null;
const client = new FormbricksHub({ apiKey, baseURL: env.HUB_API_URL });
globalForHub.formbricksHubClient = client;
return client;
}
+17 -16
View File
@@ -125,7 +125,8 @@ describe("handleConnectorPipeline", () => {
});
test("continues when transform returns no feedback records", async () => {
vi.mocked(getConnectorsBySurveyId).mockResolvedValue([createConnector()]);
const connector = createConnector();
vi.mocked(getConnectorsBySurveyId).mockResolvedValue([connector]);
vi.mocked(transformResponseToFeedbackRecords).mockReturnValue([]);
await handleConnectorPipeline(mockResponse, mockSurvey, "env-1");
@@ -133,13 +134,27 @@ describe("handleConnectorPipeline", () => {
expect(transformResponseToFeedbackRecords).toHaveBeenCalledWith(
mockResponse,
mockSurvey,
createConnector().formbricksMappings,
connector.formbricksMappings,
"env-1"
);
expect(mockFeedbackRecordsCreate).not.toHaveBeenCalled();
expect(updateConnector).not.toHaveBeenCalled();
});
test("updates connector to error when HUB_API_KEY is not set", async () => {
vi.mocked(env).HUB_API_KEY = undefined as any;
vi.mocked(getConnectorsBySurveyId).mockResolvedValue([createConnector()]);
vi.mocked(transformResponseToFeedbackRecords).mockReturnValue(oneFeedbackRecord as any);
await handleConnectorPipeline(mockResponse, mockSurvey, "env-1");
expect(mockFeedbackRecordsCreate).not.toHaveBeenCalled();
expect(updateConnector).toHaveBeenCalledWith("conn-1", "env-1", {
status: "error",
errorMessage: expect.stringContaining("HUB_API_KEY"),
});
});
test("sends records to Hub and updates connector to active on full success", async () => {
vi.mocked(getConnectorsBySurveyId).mockResolvedValue([createConnector()]);
vi.mocked(transformResponseToFeedbackRecords).mockReturnValue(oneFeedbackRecord as any);
@@ -156,20 +171,6 @@ describe("handleConnectorPipeline", () => {
});
});
test("updates connector to error when HUB_API_KEY is not set", async () => {
vi.mocked(env).HUB_API_KEY = undefined as any;
vi.mocked(getConnectorsBySurveyId).mockResolvedValue([createConnector()]);
vi.mocked(transformResponseToFeedbackRecords).mockReturnValue(oneFeedbackRecord as any);
await handleConnectorPipeline(mockResponse, mockSurvey, "env-1");
expect(mockFeedbackRecordsCreate).not.toHaveBeenCalled();
expect(updateConnector).toHaveBeenCalledWith("conn-1", "env-1", {
status: "error",
errorMessage: expect.stringContaining("HUB_API_KEY"),
});
});
test("updates connector to error when all Hub creates fail", async () => {
vi.mocked(getConnectorsBySurveyId).mockResolvedValue([createConnector()]);
vi.mocked(transformResponseToFeedbackRecords).mockReturnValue(oneFeedbackRecord as any);
+3 -12
View File
@@ -1,27 +1,18 @@
import "server-only";
import FormbricksHub from "@formbricks/hub";
import { logger } from "@formbricks/logger";
import { TResponse } from "@formbricks/types/responses";
import { TSurvey } from "@formbricks/types/surveys/types";
import { env } from "@/lib/env";
import { getConnectorsBySurveyId, updateConnector } from "./service";
import { getHubClient } from "./hub-client";
import { transformResponseToFeedbackRecords } from "./transform";
type FeedbackRecordCreateParams = FormbricksHub.FeedbackRecordCreateParams;
type FeedbackRecordData = FormbricksHub.FeedbackRecordData;
function getHubClient(): FormbricksHub | null {
const apiKey = env.HUB_API_KEY;
if (!apiKey) return null;
return new FormbricksHub({
apiKey,
baseURL: env.HUB_API_URL ?? undefined,
});
}
async function createFeedbackRecordsBatch(inputs: FeedbackRecordCreateParams[]): Promise<{
results: Array<{
data: FeedbackRecordData | null;
data: FormbricksHub.FeedbackRecordData | null;
error: { status: number; message: string; detail: string } | null;
}>;
}> {
+1 -1
View File
@@ -30,7 +30,7 @@
"@formbricks/cache": "workspace:*",
"@formbricks/database": "workspace:*",
"@formbricks/email": "workspace:*",
"@formbricks/hub": "^0.3.0",
"@formbricks/hub": "0.3.0",
"@formbricks/i18n-utils": "workspace:*",
"@formbricks/js-core": "workspace:*",
"@formbricks/logger": "workspace:*",