TASK22269: delegate fileClient signed get/post to signedRequestClient

This commit is contained in:
2026-03-25 13:47:46 +00:00
parent 7470975d0e
commit 85cc7d165e
3 changed files with 49 additions and 41 deletions
+3 -15
View File
@@ -1,17 +1,12 @@
import { getJson, requestJson } from "./endpointClient"; import { getJson, requestJson } from "./endpointClient";
import { buildHashedQueryUrl } from "./relayClient"; import { getSignedJson, postSignedJson } from "./signedRequestClient";
export const getFileJson = (url) => { export const getFileJson = (url) => {
return getJson(url); return getJson(url);
}; };
export const getSignedFileJson = async (queryUrl) => { export const getSignedFileJson = async (queryUrl) => {
const signedUrl = await buildHashedQueryUrl(queryUrl); return getSignedJson(queryUrl);
return requestJson({
method: "get",
url: signedUrl
});
}; };
export const downloadFileBlob = (url) => { export const downloadFileBlob = (url) => {
@@ -23,12 +18,5 @@ export const downloadFileBlob = (url) => {
}; };
export const postSignedFileJson = async (queryUrl, data, config = {}) => { export const postSignedFileJson = async (queryUrl, data, config = {}) => {
const signedUrl = await buildHashedQueryUrl(queryUrl); return postSignedJson(queryUrl, data, config);
return requestJson({
method: "post",
url: signedUrl,
data,
...config
});
}; };
+31
View File
@@ -2801,3 +2801,34 @@ Validation:
Follow-ups: Follow-ups:
- Next bounded signed GET candidate in portal service is `sendRepCompleteMessage` (single signed URL + GET request path). - Next bounded signed GET candidate in portal service is `sendRepCompleteMessage` (single signed URL + GET request path).
---
### CL-078: TASK22269 Slice B1.3 — fileClient signed helper delegation bundle
date: 2026-03-25
author: Cline
scope: `actions/clients/fileClient.js`, `tests/phase22/file-client-behaviour.test.cjs`
type: change
rationale: Continue grouped signed-request consolidation by reducing duplicate signing logic in `fileClient` and delegating signed GET/POST operations to shared `signedRequestClient` helpers.
impact: Centralizes signed method execution behavior in one helper layer and lowers drift risk across file-service call paths.
status: completed
Summary:
- Updated `actions/clients/fileClient.js`:
- replaced direct `buildHashedQueryUrl + requestJson` logic in:
- `getSignedFileJson` -> now delegates to `getSignedJson`
- `postSignedFileJson` -> now delegates to `postSignedJson`
- retained `downloadFileBlob` and `getFileJson` behavior unchanged.
- Updated `tests/phase22/file-client-behaviour.test.cjs` to assert delegation contracts for `getSignedJson` and `postSignedJson` rather than direct signing internals.
Validation:
- `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors)
- `node tests/phase22/index.test.cjs` -> pass
- `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13)
Follow-ups:
- Candidate map now indicates remaining explicit signed request composition is primarily in account/portal signed GET edge paths (`getPortalLogin`, `sendRepCompleteMessage`, and signed suffix append flow in `sendCaseCompleteMessage`) for future bounded slices.
+15 -26
View File
@@ -24,8 +24,11 @@ const loadFileClientModule = (injected = {}) => {
requestJson: async () => { requestJson: async () => {
throw new Error("requestJson not injected"); throw new Error("requestJson not injected");
}, },
buildHashedQueryUrl: async () => { getSignedJson: async () => {
throw new Error("buildHashedQueryUrl not injected"); throw new Error("getSignedJson not injected");
},
postSignedJson: async () => {
throw new Error("postSignedJson not injected");
}, },
...injected ...injected
}; };
@@ -56,15 +59,10 @@ test("clients/fileClient getFileJson delegates to getJson", async () => {
test("clients/fileClient getSignedFileJson signs url and requests json", async () => { test("clients/fileClient getSignedFileJson signs url and requests json", async () => {
const signedCalls = []; const signedCalls = [];
const requestCalls = [];
const mod = loadFileClientModule({ const mod = loadFileClientModule({
buildHashedQueryUrl: async (queryUrl) => { getSignedJson: async (queryUrl) => {
signedCalls.push(queryUrl); signedCalls.push(queryUrl);
return queryUrl + "&hash=signed";
},
requestJson: async (config) => {
requestCalls.push(config);
return { deleted: true }; return { deleted: true };
} }
}); });
@@ -77,11 +75,9 @@ test("clients/fileClient getSignedFileJson signs url and requests json", async (
deleted: true deleted: true
}); });
assert.strictEqual(signedCalls.length, 1); assert.strictEqual(signedCalls.length, 1);
assert.strictEqual(requestCalls.length, 1);
assert.strictEqual(requestCalls[0].method, "get");
assert.strictEqual( assert.strictEqual(
requestCalls[0].url, signedCalls[0],
"/api/file/deleteblobcase?container=a&casefolderID=b&hash=signed" "/api/file/deleteblobcase?container=a&casefolderID=b"
); );
}); });
@@ -106,15 +102,12 @@ test("clients/fileClient downloadFileBlob requests blob response", async () => {
test("clients/fileClient postSignedFileJson signs url and posts payload", async () => { test("clients/fileClient postSignedFileJson signs url and posts payload", async () => {
const signedCalls = []; const signedCalls = [];
const requestCalls = []; const postedCalls = [];
const mod = loadFileClientModule({ const mod = loadFileClientModule({
buildHashedQueryUrl: async (queryUrl) => { postSignedJson: async (queryUrl, data, config) => {
signedCalls.push(queryUrl); signedCalls.push(queryUrl);
return queryUrl + "&hash=signed-post"; postedCalls.push({ data, config });
},
requestJson: async (config) => {
requestCalls.push(config);
return { uploaded: true }; return { uploaded: true };
} }
}); });
@@ -132,18 +125,14 @@ test("clients/fileClient postSignedFileJson signs url and posts payload", async
uploaded: true uploaded: true
}); });
assert.strictEqual(signedCalls.length, 1); assert.strictEqual(signedCalls.length, 1);
assert.strictEqual(requestCalls.length, 1); assert.strictEqual(postedCalls.length, 1);
assert.strictEqual(requestCalls[0].method, "post"); assert.strictEqual(signedCalls[0], "/api/file/uploadsinglefile");
assert.strictEqual(
requestCalls[0].url,
"/api/file/uploadsinglefile&hash=signed-post"
);
assert.deepStrictEqual( assert.deepStrictEqual(
JSON.parse(JSON.stringify(requestCalls[0].data)), JSON.parse(JSON.stringify(postedCalls[0].data)),
payload payload
); );
assert.strictEqual( assert.strictEqual(
requestCalls[0].headers["content-type"], postedCalls[0].config.headers["content-type"],
"multipart/form-data" "multipart/form-data"
); );
}); });