EPILIBS-210: Add taskAdapter.query wrapping GET /task/search#166
EPILIBS-210: Add taskAdapter.query wrapping GET /task/search#166mpqmpqm wants to merge 1 commit into
Conversation
The /task/search endpoint runs at facilitator clearance and supports filter/sort/pagination over the permitted task fields; the adapter had no wrapper for it, forcing clients down to raw Router calls. Follows the shape of groupAdapter.query. Verified against epicenter-sandbox-1 with a facilitator session. EPILIBS-210 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces a new query method to the task adapter for searching tasks, along with corresponding unit tests. The review feedback highlights a potential runtime TypeError if searchOptions is omitted, which can be resolved by providing a default empty object. Additionally, it suggests ensuring that the paginated: true option cannot be overridden by optionals to maintain type safety, and recommends adding a unit test to verify behavior when empty options are provided.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| searchOptions: GenericSearchOptions, | ||
| optionals: RoutingOptions = {}, |
There was a problem hiding this comment.
Since all properties of GenericSearchOptions are optional, callers should be able to invoke query() without passing any arguments (e.g., to fetch the first page of tasks with default settings). Currently, omitting searchOptions will cause a runtime TypeError when destructuring properties like filter and sort from undefined.
Providing a default empty object {} for searchOptions resolves this issue and makes the method safer and more convenient to use, especially in JavaScript environments.
| searchOptions: GenericSearchOptions, | |
| optionals: RoutingOptions = {}, | |
| searchOptions: GenericSearchOptions = {}, | |
| optionals: RoutingOptions = {}, |
| .get('/task/search', { | ||
| paginated: true, | ||
| ...optionals, | ||
| }) |
There was a problem hiding this comment.
The query function is typed to return a Promise<Page<TaskReadOutView<B, H>>>. However, because ...optionals is spread after paginated: true, a caller could pass { paginated: false } in optionals, which would override the pagination setting and return a non-paginated response at runtime, violating the TypeScript return type contract.
Placing paginated: true after ...optionals ensures that pagination is always enforced for this endpoint.
| .get('/task/search', { | |
| paginated: true, | |
| ...optionals, | |
| }) | |
| .get('/task/search', { | |
| ...optionals, | |
| paginated: true, | |
| }) |
| expect(searchParams.get('sort')).toBe(OPTIONS.sort.join(';')); | ||
| expect(searchParams.get('first')).toBe(OPTIONS.first.toString()); | ||
| expect(searchParams.get('max')).toBe(OPTIONS.max.toString()); | ||
| }); |
There was a problem hiding this comment.
To ensure that calling query() with no arguments or empty options works correctly and does not regress in the future, we should add a unit test verifying this behavior.
});
it('Should support empty search options', async () => {
await taskAdapter.query();
const req = capturedRequests[capturedRequests.length - 1];
const search = req.url.split('?')[1];
const searchParams = new URLSearchParams(search);
expect(searchParams.get('filter')).toBeNull();
expect(searchParams.get('sort')).toBeNull();
expect(searchParams.get('first')).toBeNull();
expect(searchParams.get('max')).toBeNull();
});
What
Adds
taskAdapter.query(searchOptions, optionals)wrappingGET /task/search, following the shape ofgroupAdapter.query(parseFilterInput,sort.join(';'),paginated: true,Page<TaskReadOutView>).Why
EPILIBS-210 —
/task/searchis the listing surface that works for facilitator sessions (getTaskIn's endpoint queries at AUTHOR row-visibility, EPICENTER-6763), and it exposes filter/sort/pagination thatgetTaskInnever had. Clients currently drop to rawRoutercalls for this.Verification
npm run test:run: 1004 passed, including 5 newtaskAdapter.queryspecs (GET, auth, URL, generic options, query-string params) and the suite's untested-methods completeness check.npm run type-checkclean.dist/cjsand rantaskAdapter.query({ filter: ['task.scopeKey=…'], sort: ['-task.created'] })against epicenter-sandbox-1 (forio-dev/proxy-docs) with a FACILITATOR user session — returned the scope's tasks (totalResults 2) wheregetTaskInreturns zero rows.🤖 Generated with Claude Code