[FSSDK-12444] getQualifiedSegments helper addition#326
[FSSDK-12444] getQualifiedSegments helper addition#326junaed-optimizely merged 5 commits intomasterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new public helper to fetch a user’s qualified ODP segments by extracting segment names from datafile audience conditions and querying the ODP GraphQL API.
Changes:
- Added
getQualifiedSegmentsutility to parse ODP config + audience conditions and fetch segment qualification via GraphQL. - Added Vitest coverage for the new helper.
- Re-exported the helper from the package entrypoint.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
src/utils/helpers.ts |
Implements getQualifiedSegments plus internal helpers for condition parsing and GraphQL payload construction. |
src/utils/helpers.spec.ts |
Adds unit tests covering ODP config validation, empty segments, success path, and error paths. |
src/index.ts |
Exposes getQualifiedSegments as a public export. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const segmentsList = segmentsToCheck.map((s) => `"${s}"`).join(','); | ||
| const query = `query {customer(fs_user_id : "${userId}") {audiences(subset: [${segmentsList}]) {edges {node {name state}}}}}`; | ||
| return JSON.stringify({ query }); |
There was a problem hiding this comment.
buildGraphQLQuery interpolates userId and segment names directly into the GraphQL source. If either contains quotes/backslashes/newlines, the query becomes invalid, and this also opens the door to GraphQL injection (the query text is constructed from untrusted input). Prefer sending a static query with GraphQL variables (e.g., variables: { userId, subset: segmentsToCheck }) so values are encoded safely, rather than embedding them into the query string.
| const segmentsList = segmentsToCheck.map((s) => `"${s}"`).join(','); | |
| const query = `query {customer(fs_user_id : "${userId}") {audiences(subset: [${segmentsList}]) {edges {node {name state}}}}}`; | |
| return JSON.stringify({ query }); | |
| const query = | |
| 'query GetQualifiedSegments($userId: String!, $subset: [String!]!) {' + | |
| ' customer(fs_user_id: $userId) {' + | |
| ' audiences(subset: $subset) {' + | |
| ' edges {' + | |
| ' node {' + | |
| ' name state' + | |
| ' }' + | |
| ' }' + | |
| ' }' + | |
| ' }' + | |
| '}'; | |
| return JSON.stringify({ | |
| query, | |
| variables: { | |
| userId, | |
| subset: segmentsToCheck, | |
| }, | |
| }); |
| export async function getQualifiedSegments( | ||
| userId: string, | ||
| datafile: string | Record<string, any> | ||
| ): Promise<string[] | null> { | ||
| let datafileObj: any; | ||
|
|
||
| if (typeof datafile === 'string') { | ||
| try { | ||
| datafileObj = JSON.parse(datafile); | ||
| } catch { | ||
| return null; | ||
| } | ||
| } else if (typeof datafile === 'object' && datafile !== null) { | ||
| datafileObj = datafile; | ||
| } else { | ||
| return null; | ||
| } | ||
|
|
||
| // Extract ODP integration config from datafile | ||
| const odpIntegration = Array.isArray(datafileObj.integrations) | ||
| ? datafileObj.integrations.find((i: Record<string, unknown>) => i.key === 'odp') | ||
| : undefined; | ||
|
|
||
| const apiKey = odpIntegration?.publicKey; | ||
| const apiHost = odpIntegration?.host; | ||
|
|
||
| if (!apiKey || !apiHost) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
getQualifiedSegments returns null on non-integrated/failed fetch, but the Provider’s qualifiedSegments?: string[] contract treats undefined as “normal flow” and assumes any provided value is an array (see src/utils/UserContextManager.ts:107-123, which spreads qualifiedSegments). If callers pass this helper’s null directly into qualifiedSegments, it can cause a runtime TypeError. Consider changing the return type to string[] | undefined (return undefined instead of null), or otherwise ensure consumers can’t pass null through to the Provider APIs.
Summary
Add a standalone
getQualifiedSegmentshelper that fetches a user's qualified ODP segments by parsing the datafile for ODP config and segment conditions, then querying the ODP GraphQL API.Test plan
Tests have been added
Issues