TASK22269: add signed request client and migrate portal deleteWatchedCases pilot
This commit is contained in:
@@ -2,3 +2,4 @@ export * from "./relayClient";
|
||||
export * from "./endpointClient";
|
||||
export * from "./fileClient";
|
||||
export * from "./fileRouteBuilder";
|
||||
export * from "./signedRequestClient";
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { requestJson } from "./endpointClient";
|
||||
import { buildHashedQueryUrl } from "./relayClient";
|
||||
|
||||
const signedRequestJson = async ({ method, queryUrl, data, config = {} }) => {
|
||||
const signedUrl = await buildHashedQueryUrl(queryUrl);
|
||||
|
||||
return requestJson({
|
||||
method,
|
||||
url: signedUrl,
|
||||
data,
|
||||
...config
|
||||
});
|
||||
};
|
||||
|
||||
export const getSignedJson = (queryUrl, config = {}) => {
|
||||
return signedRequestJson({
|
||||
method: "get",
|
||||
queryUrl,
|
||||
config
|
||||
});
|
||||
};
|
||||
|
||||
export const postSignedJson = (queryUrl, data, config = {}) => {
|
||||
return signedRequestJson({
|
||||
method: "post",
|
||||
queryUrl,
|
||||
data,
|
||||
config
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteSignedJson = (queryUrl, config = {}) => {
|
||||
return signedRequestJson({
|
||||
method: "delete",
|
||||
queryUrl,
|
||||
config
|
||||
});
|
||||
};
|
||||
@@ -2,6 +2,7 @@ import { BASE_URL } from "../core/env";
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { buildHashedQueryUrl } from "../clients/relayClient";
|
||||
import { getJson, requestJson } from "../clients/endpointClient";
|
||||
import { deleteSignedJson } from "../clients/signedRequestClient";
|
||||
import {
|
||||
buildFileQuery,
|
||||
withBaseUrl,
|
||||
@@ -189,16 +190,9 @@ export const deleteWatchedCases = async (watchedCaseID) => {
|
||||
watchedCaseID
|
||||
});
|
||||
|
||||
return buildHashedQueryUrl(queryUrl)
|
||||
.then((signedUrl) =>
|
||||
requestJson({
|
||||
method: "delete",
|
||||
url: signedUrl
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
return deleteSignedJson(queryUrl).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const sendCaseCompleteMessage = async (
|
||||
|
||||
@@ -2725,3 +2725,46 @@ Validation:
|
||||
Follow-ups:
|
||||
|
||||
- Sequence A step3 targeted gaps are now covered; further test expansion should be treated as new scope (e.g., deeper end-to-end journey assertions).
|
||||
|
||||
---
|
||||
|
||||
### CL-076: TASK22269 Slice B1.1 — signed-request helper set + portal pilot signed-flow migration
|
||||
|
||||
date: 2026-03-25
|
||||
author: Cline
|
||||
scope: `actions/clients/{signedRequestClient,index}.js`, `actions/services/portalDirectService.js`, `tests/{serviceHarness,phase22/portal-service-behaviour}.cjs`
|
||||
type: change
|
||||
rationale: Execute Sequence B Workstream B1 pilot by introducing shared signed request helpers (GET/POST/DELETE) and migrating one bounded portal signed flow without broader module rollout.
|
||||
impact: Reduces duplication and drift risk in hash-signing + method execution paths while preserving existing signed-flow behavior contracts.
|
||||
status: completed
|
||||
|
||||
Summary:
|
||||
|
||||
- Added new shared signed-request client helper module:
|
||||
- `actions/clients/signedRequestClient.js`
|
||||
- exports:
|
||||
- `getSignedJson(queryUrl, config?)`
|
||||
- `postSignedJson(queryUrl, data, config?)`
|
||||
- `deleteSignedJson(queryUrl, config?)`
|
||||
- all helpers use existing `buildHashedQueryUrl(...)` + `requestJson(...)` composition to preserve signing semantics
|
||||
- Exported new helper module via `actions/clients/index.js`.
|
||||
- Migrated exactly one pilot signed flow in portal service:
|
||||
- `deleteWatchedCases` in `actions/services/portalDirectService.js`
|
||||
- from inline `buildHashedQueryUrl(...).then(requestJson(...))` to `deleteSignedJson(queryUrl)`
|
||||
- preserved existing catch/log behavior (`consoleLogger` + `undefined` return on catch)
|
||||
- Added test harness compatibility for VM import-stripping suites:
|
||||
- `tests/serviceHarness.cjs` now injects default `deleteSignedJson` mock behavior.
|
||||
- Expanded portal behavioral tests with explicit negative-path assertion:
|
||||
- `tests/phase22/portal-service-behaviour.test.cjs`
|
||||
- verifies `deleteWatchedCases` logs and safely returns `undefined` when signed delete fails.
|
||||
|
||||
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
|
||||
- portal-service suite now 5/5 including signed-delete failure path
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13)
|
||||
|
||||
Follow-ups:
|
||||
|
||||
- Continue Sequence B B1 in future bounded slices by migrating additional signed flows one module/function cluster at a time (outside this slice).
|
||||
|
||||
@@ -134,6 +134,27 @@ test("portal/sendRepCompleteMessage rejects when hash signing fails before reque
|
||||
assert.strictEqual(logger.calls.length, 0);
|
||||
});
|
||||
|
||||
test("portal/deleteWatchedCases logs and returns undefined when signed delete fails", async () => {
|
||||
const axios = createAxiosMock();
|
||||
const logger = createLoggerMock();
|
||||
const error = createAxiosError(401, "Unauthorized");
|
||||
|
||||
const portal = loadServiceModule("portalDirectService.js", {
|
||||
axios,
|
||||
BASE_URL: "",
|
||||
consoleLogger: logger.consoleLogger,
|
||||
deleteSignedJson: async () => {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
const result = await portal.deleteWatchedCases("watch-2");
|
||||
|
||||
assert.strictEqual(result, undefined);
|
||||
assert.strictEqual(logger.calls.length, 1);
|
||||
assert.strictEqual(logger.calls[0], error);
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
let passed = 0;
|
||||
|
||||
|
||||
@@ -126,6 +126,18 @@ const loadServiceModule = (fileName, injected = {}) => {
|
||||
});
|
||||
};
|
||||
|
||||
const defaultDeleteSignedJson = async (queryUrl, config = {}) => {
|
||||
const hashedUrl = await (
|
||||
injected.buildHashedQueryUrl || defaultBuildHashedQueryUrl
|
||||
)(queryUrl);
|
||||
|
||||
return (injected.requestJson || defaultRequestJson)({
|
||||
method: "delete",
|
||||
url: hashedUrl,
|
||||
...config
|
||||
});
|
||||
};
|
||||
|
||||
const defaultBuildFileQuery = (pathValue, params = {}, options = {}) => {
|
||||
const { encode = false } = options;
|
||||
const entries = Object.entries(params).filter(([, value]) => {
|
||||
@@ -172,6 +184,7 @@ const loadServiceModule = (fileName, injected = {}) => {
|
||||
getSignedFileJson:
|
||||
injected.getSignedFileJson || defaultGetSignedFileJson,
|
||||
downloadFileBlob: injected.downloadFileBlob || defaultDownloadFileBlob,
|
||||
deleteSignedJson: injected.deleteSignedJson || defaultDeleteSignedJson,
|
||||
buildHashedQueryUrl:
|
||||
injected.buildHashedQueryUrl || defaultBuildHashedQueryUrl,
|
||||
buildFileQuery: injected.buildFileQuery || defaultBuildFileQuery,
|
||||
|
||||
Reference in New Issue
Block a user