diff --git a/actions/clients/fileRouteBuilder.js b/actions/clients/fileRouteBuilder.js index 944c366f..0d366469 100644 --- a/actions/clients/fileRouteBuilder.js +++ b/actions/clients/fileRouteBuilder.js @@ -31,3 +31,7 @@ export const withBaseUrl = (baseUrl, route) => { export const appendQuerySuffix = (route, suffix = "") => { return `${route}${suffix}`; }; + +export const appendHashSuffix = (route, hashBuilder) => { + return appendQuerySuffix(route, hashBuilder(route)); +}; diff --git a/actions/services/documentDirectService.js b/actions/services/documentDirectService.js index b3d0d3c6..8075e3bf 100644 --- a/actions/services/documentDirectService.js +++ b/actions/services/documentDirectService.js @@ -4,7 +4,8 @@ import { hashAPIPath } from "../core/hash"; import { buildFileQuery, withBaseUrl, - appendQuerySuffix + appendQuerySuffix, + appendHashSuffix } from "../clients/fileRouteBuilder"; import { getFileJson, @@ -19,7 +20,7 @@ export const getAwaitingSubmissionFromBlob = (containerName) => { }); return getFileJson( - withBaseUrl(BASE_URL, appendQuerySuffix(route, hashAPIPath(route))) + withBaseUrl(BASE_URL, appendHashSuffix(route, hashAPIPath)) ).catch((error) => { consoleLogger(error); }); @@ -31,7 +32,7 @@ export const getRepsFromBlob = (containerName) => { }); return getFileJson( - withBaseUrl(BASE_URL, appendQuerySuffix(route, hashAPIPath(route))) + withBaseUrl(BASE_URL, appendHashSuffix(route, hashAPIPath)) ).catch((error) => { consoleLogger(error); }); @@ -227,7 +228,7 @@ export const getFilesFromBlob = (containerName, casefolderID) => { }); return getFileJson( - withBaseUrl(BASE_URL, appendQuerySuffix(route, hashAPIPath(route))) + withBaseUrl(BASE_URL, appendHashSuffix(route, hashAPIPath)) ).catch((error) => { consoleLogger(error); }); @@ -328,7 +329,7 @@ export const getProgressFromBlob = async (containerName, casereference) => { ); return getFileJson( - withBaseUrl(BASE_URL, appendQuerySuffix(route, hashAPIPath(route))) + withBaseUrl(BASE_URL, appendHashSuffix(route, hashAPIPath)) ).catch((error) => { consoleLogger(error); }); @@ -338,7 +339,7 @@ export const createContainerProxy = (containerName) => { var route = buildFileQuery("/api/file/setupcontainer", { ident: containerName }); - var queryUrl = appendQuerySuffix(route, hashAPIPath(route)); + var queryUrl = appendHashSuffix(route, hashAPIPath); return getFileJson(withBaseUrl(BASE_URL, queryUrl)).catch((error) => { consoleLogger(error); diff --git a/memory-bank/change-log.md b/memory-bank/change-log.md index 18114986..a8714674 100644 --- a/memory-bank/change-log.md +++ b/memory-bank/change-log.md @@ -2871,3 +2871,37 @@ Validation: Follow-ups: - Remaining special-case signed pattern is now primarily the signed-suffix append composition in `sendCaseCompleteMessage` (already using shared `buildSignedUrl`), with broader module migrations to be planned in future bounded slices. + +--- + +### CL-080: TASK22269 Slice B1.5 — document hash-suffix route normalization helper + +date: 2026-03-25 +author: Cline +scope: `actions/clients/fileRouteBuilder.js`, `actions/services/documentDirectService.js`, `tests/{serviceHarness,phase22/client-utils-behaviour}.cjs` +type: change +rationale: Continue grouped follow-on candidates by normalizing repeated deterministic hash-suffix route assembly in document service behind one shared route-builder helper. +impact: Reduces repeated `appendQuerySuffix(route, hashAPIPath(route))` composition drift risk while preserving route/query/hash behavior. +status: completed + +Summary: + +- Added `appendHashSuffix(route, hashBuilder)` to `fileRouteBuilder`. +- Migrated document service deterministic hash-suffix paths to new helper: + - `getAwaitingSubmissionFromBlob` + - `getRepsFromBlob` + - `getFilesFromBlob` + - `getProgressFromBlob` + - `createContainerProxy` +- Updated shared VM harness defaults (`tests/serviceHarness.cjs`) to inject `appendHashSuffix`. +- Expanded phase22 utility test to cover new helper behavior (`tests/phase22/client-utils-behaviour.test.cjs`). + +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: + +- Remaining non-service candidate for this stream is `actions/azurestorage.js` direct `hashAPIPath` metadata assembly (separate bounded slice if desired). diff --git a/tests/phase22/client-utils-behaviour.test.cjs b/tests/phase22/client-utils-behaviour.test.cjs index 76bad6fe..310c58fc 100644 --- a/tests/phase22/client-utils-behaviour.test.cjs +++ b/tests/phase22/client-utils-behaviour.test.cjs @@ -70,7 +70,7 @@ const loadFileRouteBuilderModule = (injected = {}) => { source = source.replace(/import[\s\S]*?from\s+"[^"]+";\n?/g, ""); source = source.replace(/export const\s+/g, "const "); source += - "\nmodule.exports = { buildFileQuery, withBaseUrl, appendQuerySuffix };\n"; + "\nmodule.exports = { buildFileQuery, withBaseUrl, appendQuerySuffix, appendHashSuffix };\n"; const context = { module: { exports: {} }, @@ -211,6 +211,12 @@ test("clients/fileRouteBuilder builds query with optional encoding and suffix he mod.appendQuerySuffix(unencoded, "&hash=123"), "/api/file/getbloblist?container=abc&casefolderID=x/y&hash=123" ); + assert.strictEqual( + mod.appendHashSuffix(unencoded, (route) => + route.includes("getbloblist") ? "&hash=abc" : "" + ), + "/api/file/getbloblist?container=abc&casefolderID=x/y&hash=abc" + ); }); const run = async () => { diff --git a/tests/serviceHarness.cjs b/tests/serviceHarness.cjs index 9ab82344..aea3882b 100644 --- a/tests/serviceHarness.cjs +++ b/tests/serviceHarness.cjs @@ -200,6 +200,8 @@ const loadServiceModule = (fileName, injected = {}) => { const defaultWithBaseUrl = (baseUrl, route) => `${baseUrl}${route}`; const defaultAppendQuerySuffix = (route, suffix = "") => `${route}${suffix}`; + const defaultAppendHashSuffix = (route, hashBuilder) => + defaultAppendQuerySuffix(route, hashBuilder(route)); const context = { module: { exports: {} }, @@ -230,6 +232,7 @@ const loadServiceModule = (fileName, injected = {}) => { withBaseUrl: injected.withBaseUrl || defaultWithBaseUrl, appendQuerySuffix: injected.appendQuerySuffix || defaultAppendQuerySuffix, + appendHashSuffix: injected.appendHashSuffix || defaultAppendHashSuffix, ...injected };