@ripla/godd-mcp 1.0.2-canary.6 → 1.0.2-canary.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -98,6 +98,52 @@ describe("formatApiDetail (via loginApi error path)", () => {
|
|
|
98
98
|
});
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
+
describe("delete APIs", () => {
|
|
102
|
+
beforeEach(() => {
|
|
103
|
+
vi.restoreAllMocks();
|
|
104
|
+
localStorage.clear();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("deleteFileApi は HTML エラーを JSON としてパースしない", async () => {
|
|
108
|
+
const { deleteFileApi, setToken } = await import("./api");
|
|
109
|
+
setToken("test-token");
|
|
110
|
+
vi.spyOn(globalThis, "fetch").mockResolvedValue(
|
|
111
|
+
new Response("<!DOCTYPE html><html></html>", {
|
|
112
|
+
status: 500,
|
|
113
|
+
headers: { "Content-Type": "text/html" },
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
await expect(deleteFileApi("docs/a.md")).rejects.toThrow("Delete failed: 500");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("deleteFileApi は成功時の非 JSON レスポンスを分かるエラーにする", async () => {
|
|
121
|
+
const { deleteFileApi, setToken } = await import("./api");
|
|
122
|
+
setToken("test-token");
|
|
123
|
+
vi.spyOn(globalThis, "fetch").mockResolvedValue(
|
|
124
|
+
new Response("<!DOCTYPE html><html></html>", {
|
|
125
|
+
status: 200,
|
|
126
|
+
headers: { "Content-Type": "text/html" },
|
|
127
|
+
}),
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
await expect(deleteFileApi("docs/a.md")).rejects.toThrow("Delete response was not JSON");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("deleteFolderApi は JSON エラー detail を表示する", async () => {
|
|
134
|
+
const { deleteFolderApi, setToken } = await import("./api");
|
|
135
|
+
setToken("test-token");
|
|
136
|
+
vi.spyOn(globalThis, "fetch").mockResolvedValue(
|
|
137
|
+
new Response(JSON.stringify({ detail: "Directory is empty or not found" }), {
|
|
138
|
+
status: 404,
|
|
139
|
+
headers: { "Content-Type": "application/json" },
|
|
140
|
+
}),
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
await expect(deleteFolderApi("docs/empty")).rejects.toThrow("Directory is empty or not found");
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
101
147
|
describe("fetchBranchStatusApi", () => {
|
|
102
148
|
beforeEach(() => {
|
|
103
149
|
vi.restoreAllMocks();
|
package/notes-app/src/lib/api.ts
CHANGED
|
@@ -139,10 +139,10 @@ export async function deleteFileApi(
|
|
|
139
139
|
): Promise<{ success: boolean }> {
|
|
140
140
|
const res = await apiFetch(`/files/${encodePath(path)}`, { method: "DELETE" });
|
|
141
141
|
if (!res.ok) {
|
|
142
|
-
const body = await res
|
|
142
|
+
const body = await readJsonBody(res);
|
|
143
143
|
throw new Error(formatApiDetail(body, `Delete failed: ${res.status}`));
|
|
144
144
|
}
|
|
145
|
-
return res
|
|
145
|
+
return parseJsonBody(res, "Delete response was not JSON");
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
export async function deleteFolderApi(
|
|
@@ -150,10 +150,10 @@ export async function deleteFolderApi(
|
|
|
150
150
|
): Promise<{ success: boolean; deletedCount: number }> {
|
|
151
151
|
const res = await apiFetch(`/folder/${encodePath(path)}`, { method: "DELETE" });
|
|
152
152
|
if (!res.ok) {
|
|
153
|
-
const body = await res
|
|
153
|
+
const body = await readJsonBody(res);
|
|
154
154
|
throw new Error(formatApiDetail(body, `Folder delete failed: ${res.status}`));
|
|
155
155
|
}
|
|
156
|
-
return res
|
|
156
|
+
return parseJsonBody(res, "Folder delete response was not JSON");
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
export async function moveFolderApi(
|
|
@@ -567,3 +567,15 @@ export function formatApiDetail(body: unknown, fallback: string): string {
|
|
|
567
567
|
}
|
|
568
568
|
return fallback;
|
|
569
569
|
}
|
|
570
|
+
|
|
571
|
+
async function readJsonBody(res: Response): Promise<unknown | null> {
|
|
572
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
573
|
+
if (!contentType.toLowerCase().includes("application/json")) return null;
|
|
574
|
+
return res.json().catch(() => null);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
async function parseJsonBody<T>(res: Response, fallback: string): Promise<T> {
|
|
578
|
+
const body = await readJsonBody(res);
|
|
579
|
+
if (body === null) throw new Error(fallback);
|
|
580
|
+
return body as T;
|
|
581
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ripla/godd-mcp",
|
|
3
|
-
"version": "1.0.2-canary.
|
|
3
|
+
"version": "1.0.2-canary.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "GoDD (Governance-orchestrated Driven Development) MCP Server - Encrypted prompt distribution via Model Context Protocol",
|
|
6
6
|
"main": "dist/index.js",
|