Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,13 @@ export async function apiGet(
params?: Record<string, unknown>,
) {
const client = createClient();
// tRPC v11 servers require the GET `input` query param to be wrapped in a
// { json: ... } envelope (see https://trpc.io/docs/client/http-link). A
// bare object is deserialized as `undefined` and every GET call fails with
// HTTP 400. The envelope is also accepted by older tRPC v10 servers, so it
// works against all Dokploy server versions.
const query = params
? `?input=${encodeURIComponent(JSON.stringify(params))}`
? `?input=${encodeURIComponent(JSON.stringify({ json: params }))}`
: "";
const response = await client.get(`/trpc/${endpoint}${query}`);
return response.data?.result?.data?.json ?? response.data;
Expand Down
57 changes: 57 additions & 0 deletions tests/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

vi.mock("axios", () => {
return {
default: {
create: () => ({
get: () => Promise.resolve({ data: {} }),
post: () => Promise.resolve({ data: {} }),
}),
},
};
});

describe("readAuthConfig", () => {
const originalEnv = { ...process.env };

Expand Down Expand Up @@ -48,6 +59,52 @@ describe("readAuthConfig", () => {
});
});

describe("apiGet", () => {
it("should pass GET params in the tRPC { json: ... } input envelope", async () => {
process.env.DOKPLOY_URL = "https://test.dokploy.com";
process.env.DOKPLOY_API_KEY = "test-key-123";

const urls: string[] = [];
const axiosMock = await import("axios");
axiosMock.default.create = () =>
({
get: async (url: string) => {
urls.push(url);
return { data: {} };
},
}) as never;

const { apiGet } = await import("../src/client.js");
await apiGet("compose.one", { composeId: "abc123", limit: 1 });

expect(urls[0]).toBe(
`/trpc/compose.one?input=${encodeURIComponent(
JSON.stringify({ json: { composeId: "abc123", limit: 1 } }),
)}`,
);
});

it("should omit the input query string when no params are passed", async () => {
process.env.DOKPLOY_URL = "https://test.dokploy.com";
process.env.DOKPLOY_API_KEY = "test-key-123";

const urls: string[] = [];
const axiosMock = await import("axios");
axiosMock.default.create = () =>
({
get: async (url: string) => {
urls.push(url);
return { data: {} };
},
}) as never;

const { apiGet } = await import("../src/client.js");
await apiGet("project.all");

expect(urls[0]).toBe("/trpc/project.all");
});
});

describe("saveAuthConfig", () => {
it("should write config with correct structure", async () => {
const { saveAuthConfig } = await import("../src/client.js");
Expand Down