From e1ae618cfaf7e81dfbab473a71e4e3eed51347c3 Mon Sep 17 00:00:00 2001 From: Oskar Wiedeweg <78727642+OskarWiedeweg@users.noreply.github.com> Date: Tue, 28 Apr 2026 00:03:30 +0200 Subject: [PATCH 1/3] fix: remove trcp path prefix The CLI calls /trpc/ endpoints but the server only responds on /api/ REST endpoints Fixes #39 --- src/client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client.ts b/src/client.ts index dc31d14..82369b0 100644 --- a/src/client.ts +++ b/src/client.ts @@ -87,7 +87,7 @@ export async function apiPost( ) { const client = createClient(); const response = await client.post( - `/trpc/${endpoint}`, + `/${endpoint}`, data ? { json: data } : undefined, ); return response.data?.result?.data?.json ?? response.data; @@ -101,6 +101,6 @@ export async function apiGet( const query = params ? `?input=${encodeURIComponent(JSON.stringify(params))}` : ""; - const response = await client.get(`/trpc/${endpoint}${query}`); + const response = await client.get(`/${endpoint}${query}`); return response.data?.result?.data?.json ?? response.data; } From 91687876557b5767fffd519378cb59a6f8ca75f4 Mon Sep 17 00:00:00 2001 From: Oskar Wiedeweg <78727642+OskarWiedeweg@users.noreply.github.com> Date: Tue, 28 Apr 2026 00:22:35 +0200 Subject: [PATCH 2/3] feat: migrate to rest endpoints from trcp api --- src/client.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/client.ts b/src/client.ts index 82369b0..826e053 100644 --- a/src/client.ts +++ b/src/client.ts @@ -88,9 +88,9 @@ export async function apiPost( const client = createClient(); const response = await client.post( `/${endpoint}`, - data ? { json: data } : undefined, + data, ); - return response.data?.result?.data?.json ?? response.data; + return response.data; } export async function apiGet( @@ -98,9 +98,10 @@ export async function apiGet( params?: Record, ) { const client = createClient(); - const query = params - ? `?input=${encodeURIComponent(JSON.stringify(params))}` - : ""; - const response = await client.get(`/${endpoint}${query}`); - return response.data?.result?.data?.json ?? response.data; + const query = Object + .entries(params ?? {}) + .map(([key, value]) => `${key}=${value}`) + .join('&') + const response = await client.get(`/${endpoint}?${query}`); + return response.data; } From ac0bf3442313993aec2e9390090fe438f3f25903 Mon Sep 17 00:00:00 2001 From: Jared McQueen Date: Sat, 18 Jul 2026 19:39:59 -0400 Subject: [PATCH 3/3] test: harden REST API request handling --- src/client.ts | 16 +++++------- tests/client.test.ts | 59 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/client.ts b/src/client.ts index 826e053..379325f 100644 --- a/src/client.ts +++ b/src/client.ts @@ -24,7 +24,10 @@ function loadEnvFile(): void { const eqIndex = trimmed.indexOf("="); if (eqIndex === -1) continue; const key = trimmed.slice(0, eqIndex).trim(); - const value = trimmed.slice(eqIndex + 1).trim().replace(/^["']|["']$/g, ""); + const value = trimmed + .slice(eqIndex + 1) + .trim() + .replace(/^["']|["']$/g, ""); if (!process.env[key]) { process.env[key] = value; } @@ -86,10 +89,7 @@ export async function apiPost( data?: Record, ) { const client = createClient(); - const response = await client.post( - `/${endpoint}`, - data, - ); + const response = await client.post(`/${endpoint}`, data); return response.data; } @@ -98,10 +98,6 @@ export async function apiGet( params?: Record, ) { const client = createClient(); - const query = Object - .entries(params ?? {}) - .map(([key, value]) => `${key}=${value}`) - .join('&') - const response = await client.get(`/${endpoint}?${query}`); + const response = await client.get(`/${endpoint}`, { params }); return response.data; } diff --git a/tests/client.test.ts b/tests/client.test.ts index 849213f..5f64004 100644 --- a/tests/client.test.ts +++ b/tests/client.test.ts @@ -1,5 +1,17 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +const axiosMocks = vi.hoisted(() => ({ + create: vi.fn(), + get: vi.fn(), + post: vi.fn(), +})); + +vi.mock("axios", () => ({ + default: { + create: axiosMocks.create, + }, +})); + describe("readAuthConfig", () => { const originalEnv = { ...process.env }; @@ -54,3 +66,50 @@ describe("saveAuthConfig", () => { expect(typeof saveAuthConfig).toBe("function"); }); }); + +describe("REST API client", () => { + beforeEach(() => { + process.env.DOKPLOY_URL = "https://test.dokploy.com"; + process.env.DOKPLOY_API_KEY = "test-key"; + axiosMocks.create.mockReturnValue({ + get: axiosMocks.get, + post: axiosMocks.post, + }); + }); + + afterEach(() => { + delete process.env.DOKPLOY_URL; + delete process.env.DOKPLOY_API_KEY; + vi.clearAllMocks(); + }); + + it("sends GET parameters to the REST endpoint", async () => { + const responseData = { projectId: "project-1" }; + axiosMocks.get.mockResolvedValue({ data: responseData }); + + const { apiGet } = await import("../src/client.js"); + const result = await apiGet("project.one", { + projectId: "project with spaces", + }); + + expect(axiosMocks.get).toHaveBeenCalledWith("/project.one", { + params: { projectId: "project with spaces" }, + }); + expect(result).toEqual(responseData); + }); + + it("sends POST data directly to the REST endpoint", async () => { + const requestData = { name: "My Project" }; + const responseData = { projectId: "project-1", ...requestData }; + axiosMocks.post.mockResolvedValue({ data: responseData }); + + const { apiPost } = await import("../src/client.js"); + const result = await apiPost("project.create", requestData); + + expect(axiosMocks.post).toHaveBeenCalledWith( + "/project.create", + requestData, + ); + expect(result).toEqual(responseData); + }); +});