-
Notifications
You must be signed in to change notification settings - Fork 3
feat(journey-client): wellknown-endpoint-config-support #525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: e58f29a The changes in this PR will be included in the next version bump. This PR includes changesets to release 12 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📝 WalkthroughWalkthroughAdds shared OIDC well‑known discovery: new RTK Query wellknown API and error utilities, URL/realm validators, journey/davinci/oidc clients refactored to consume/re-export the shared modules, new config types and discovery flow, tests, and workspace/tsconfig/tooling updates. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Journey initializer
participant Utils as Wellknown utils
participant WKApi as wellknownApi (RTK Query)
participant Store as Redux Store
participant OIDC as OIDC Server
Client->>Utils: isValidWellknownUrl(wellknownUrl)
Utils-->>Client: boolean
alt valid well-known
Client->>WKApi: configuration.query(wellknownUrl)
WKApi->>OIDC: GET /.well-known/openid-configuration
OIDC-->>WKApi: WellknownResponse
WKApi-->>Store: cache response
Client->>Utils: inferRealmFromIssuer(response.issuer)
Utils-->>Client: inferred realm?
Client->>Store: dispatch setConfig(InternalJourneyClientConfig)
Store-->>Client: config persisted
else fetch/error
WKApi-->>Client: error
Client->>Utils: createWellknownError(error)
Utils-->>Client: GenericError
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
View your CI Pipeline Execution ↗ for commit 8b88793
☁️ Nx Cloud last updated this comment at |
@forgerock/davinci-client
@forgerock/device-client
@forgerock/journey-client
@forgerock/oidc-client
@forgerock/protect
@forgerock/sdk-types
@forgerock/sdk-utilities
@forgerock/iframe-manager
@forgerock/sdk-logger
@forgerock/sdk-oidc
@forgerock/sdk-request-middleware
@forgerock/storage
commit: |
Codecov Report❌ Patch coverage is ❌ Your project status has failed because the head coverage (19.36%) is below the target coverage (40.00%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #525 +/- ##
==========================================
+ Coverage 18.79% 19.36% +0.57%
==========================================
Files 140 148 +8
Lines 27640 28005 +365
Branches 980 1028 +48
==========================================
+ Hits 5195 5424 +229
- Misses 22445 22581 +136
🚀 New features to boost your workflow:
|
|
Deployed 6040463 to https://ForgeRock.github.io/ping-javascript-sdk/pr-525/60404630041fd0447a1f86618c6bcd942cea5b9b branch gh-pages in ForgeRock/ping-javascript-sdk |
📦 Bundle Size Analysis📦 Bundle Size Analysis🚨 Significant Changes🔺 @forgerock/sdk-utilities - 9.9 KB (+1.4 KB, +16.0%) 📊 Minor Changes📈 @forgerock/oidc-client - 23.8 KB (+0.3 KB) ➖ No Changes➖ @forgerock/device-client - 9.2 KB 13 packages analyzed • Baseline from latest Legend🆕 New package ℹ️ How bundle sizes are calculated
🔄 Updated automatically on each push to this PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/journey-client/src/lib/client.store.ts (1)
68-179: Apply request middleware to well-known discovery.
The discovery call is made via a temp store that doesn’t includerequestMiddleware, so any custom headers/auth/fetch logic won’t apply to the well-known request. That can break environments that rely on middleware.🔧 Proposed fix
async function resolveAsyncConfig( config: JourneyConfigInput & { serverConfig: { wellknown: string } }, log: ReturnType<typeof loggerFn>, + requestMiddleware?: RequestMiddleware[], ): Promise<InternalJourneyClientConfig> { @@ - const tempStore = createJourneyStore({ config: tempConfig, logger: log }); + const tempStore = createJourneyStore({ config: tempConfig, logger: log, requestMiddleware }); @@ - resolvedConfig = await resolveAsyncConfig(config, log); + resolvedConfig = await resolveAsyncConfig(config, log, requestMiddleware);
🤖 Fix all issues with AI agents
In `@packages/sdk-effects/oidc/package.json`:
- Line 31: Replace the explicit version for the dependency key
"@reduxjs/toolkit" in package.json (currently "^2.8.0") with the monorepo
catalog spec so it follows the workspace pattern — set the version to
"catalog:^2.8.2" (i.e., change the value for "@reduxjs/toolkit" to
"catalog:^2.8.2") so the package uses the single source of truth defined in
pnpm-workspace.yaml.
🧹 Nitpick comments (4)
packages/sdk-utilities/src/lib/wellknown/wellknown.utils.ts (1)
85-98: Consider adding IPv6 localhost support.The function allows HTTP for
localhostand127.0.0.1, but not for::1(IPv6 localhost) or[::1]. This is a minor edge case but could cause unexpected behavior in IPv6-only development environments.♻️ Optional: Add IPv6 localhost support
// Allow HTTP only for localhost (development) - const isLocalhost = url.hostname === 'localhost' || url.hostname === '127.0.0.1'; + const isLocalhost = + url.hostname === 'localhost' || + url.hostname === '127.0.0.1' || + url.hostname === '[::1]' || + url.hostname === '::1'; const isSecure = url.protocol === 'https:'; const isHttpLocalhost = url.protocol === 'http:' && isLocalhost;packages/oidc-client/src/lib/wellknown.api.ts (2)
33-38: Selector created on every call defeats memoization.
createSelectoris invoked inside the function body, creating a new memoized selector on each call towellknownSelector. This negates the memoization benefits since each call produces a fresh selector instance.Consider creating the selector once per
wellknownUrlor usingcreateWellknownSelectorfrom the re-exported utilities if it handles this pattern.♻️ Option: Cache selectors by URL
+const selectorCache = new Map<string, ReturnType<typeof createSelector>>(); + export function wellknownSelector(wellknownUrl: string, state: RootState) { - const selector = createSelector( - wellknownApi.endpoints.configuration.select(wellknownUrl), - (result) => result?.data, - ); + let selector = selectorCache.get(wellknownUrl); + if (!selector) { + selector = createSelector( + wellknownApi.endpoints.configuration.select(wellknownUrl), + (result) => result?.data, + ); + selectorCache.set(wellknownUrl, selector); + } return selector(state); }Alternatively, if
createWellknownSelector(already exported) provides this functionality, consider using it directly instead of this wrapper.
18-21: Consider combining export and import statements.The separate re-export (line 18) and import (line 21) from the same package can be consolidated.
♻️ Suggested consolidation
-export { wellknownApi, createWellknownSelector } from '@forgerock/sdk-oidc'; - -// Import locally for use in selector below -import { wellknownApi } from '@forgerock/sdk-oidc'; +import { wellknownApi, createWellknownSelector } from '@forgerock/sdk-oidc'; + +export { wellknownApi, createWellknownSelector };packages/journey-client/src/lib/wellknown.utils.test.ts (1)
64-69: Consider adding a comment explaining intentional type casts.The type assertions (
as AsyncJourneyClientConfig,as JourneyClientConfig) are used to bypass TypeScript's checks and test edge cases with invalid inputs. A brief comment would clarify this intent for future maintainers.const config: JourneyConfigInput = { serverConfig: { baseUrl: 'https://am.example.com/am/', wellknown: '', }, - } as AsyncJourneyClientConfig; + } as AsyncJourneyClientConfig; // Intentionally cast to test runtime behavior with empty wellknown
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important
At least one additional CI pipeline execution has run since the conclusion below was written and it may no longer be applicable.
Nx Cloud is proposing a fix for your failed CI:
These changes fix the e2e test failure by replacing RTK Query with native fetch API in the wellknown configuration resolution. The original implementation created a temporary Redux store to fetch wellknown config, but RTK Query APIs are singletons with global middleware that caused conflicts when multiple journey client instances were created (e.g., after logout). By using fetch directly, we eliminate the store singleton issues while maintaining the wellknown endpoint discovery functionality.
Tip
✅ We verified this fix by re-running @forgerock/journey-suites:e2e-ci--src/protect.test.ts.
Suggested Fix changes
diff --git a/packages/journey-client/src/lib/client.store.ts b/packages/journey-client/src/lib/client.store.ts
index 35c130bd..d7f3ac61 100644
--- a/packages/journey-client/src/lib/client.store.ts
+++ b/packages/journey-client/src/lib/client.store.ts
@@ -17,7 +17,6 @@ import { journeyApi } from './journey.api.js';
import { setConfig } from './journey.slice.js';
import { createStorage } from '@forgerock/storage';
import { createJourneyObject } from './journey.utils.js';
-import { wellknownApi } from './wellknown.api.js';
import {
hasWellknownConfig,
inferRealmFromIssuer,
@@ -80,19 +79,22 @@ async function resolveAsyncConfig(
throw error;
}
- // Create a temporary store to fetch well-known (we need the RTK Query infrastructure)
- const tempConfig: InternalJourneyClientConfig = {
- serverConfig: { baseUrl: baseUrl || '', paths, timeout },
- realmPath: config.realmPath,
- };
- const tempStore = createJourneyStore({ config: tempConfig, logger: log });
-
- // Fetch the well-known configuration
- const { data: wellknownResponse, error: fetchError } = await tempStore.dispatch(
- wellknownApi.endpoints.configuration.initiate(wellknown),
- );
+ // Fetch the well-known configuration directly using fetch API
+ // We avoid using RTK Query here to prevent store singleton issues
+ let wellknownResponse: any;
+ try {
+ const response = await fetch(wellknown, {
+ headers: {
+ Accept: 'application/json',
+ },
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+ }
- if (fetchError || !wellknownResponse) {
+ wellknownResponse = await response.json();
+ } catch (fetchError: any) {
const genericError = createWellknownError(fetchError);
log.error(`${genericError.error}: ${genericError.message}`);
throw new Error(genericError.message);
Or Apply changes locally with:
npx nx-cloud apply-locally o3Fs-SUDD
Apply fix locally with your editor ↗ View interactive diff ↗
🎓 Learn more about Self-Healing CI on nx.dev
e2e/am-mock-api/package.json
Outdated
| "body-parser": "^2.2.0", | ||
| "body-parser": "^2.2.2", | ||
| "cookie-parser": "^1.4.7", | ||
| "cors": "^2.8.5", | ||
| "express": "^4.21.2", | ||
| "express": "^5.2.1", | ||
| "superagent": "^10.2.3", | ||
| "uuid": "^13.0.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/express": "^4.17.17" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is because i rebased my open deps pr because i was having issues with commands that were fixed via upgrading
| export default function (app) { | ||
| // Passthrough route that enforces authentication | ||
| app.all('/resource/*', async (req, res, next) => { | ||
| app.all('/resource/{*splat}', async (req, res, next) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed when i rebased open-deps (part of this express upgrade)
| "lint-staged": "^15.0.0", | ||
| "madge": "8.0.0", | ||
| "nx": "21.2.3", | ||
| "nx": "22.3.3", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all of this is because of dependency upgrades
| return async () => { | ||
| await serverInfo.set(serverSlice); | ||
| const setResult = await serverInfo.set(serverSlice); | ||
| if (isGenericError(setResult)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
helps prevent type casting.
| end_session_endpoint: 'https://example.com/logout', | ||
| pushed_authorization_request_endpoint: '', | ||
| check_session_iframe: '', | ||
| introspection_endpoint: '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per the https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata, only a few properties are REQUIRED - most are optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/journey-client/src/lib/journey.api.ts (1)
118-186: Guard against missingjourneyslice to avoid a TypeError.If the store is misconfigured,
state.journeycan be undefined and throw before the explicit error is raised.🛡️ Suggested defensive guard
- const state = api.getState() as JourneyRootState; - const config = state.journey.config; + const state = api.getState() as JourneyRootState; + const config = state?.journey?.config; if (!config?.serverConfig) { throw new Error('Server configuration is missing.'); } @@ - const state = api.getState() as JourneyRootState; - const config = state.journey.config; + const state = api.getState() as JourneyRootState; + const config = state?.journey?.config; if (!config?.serverConfig) { throw new Error('Server configuration is missing.'); } @@ - const state = api.getState() as JourneyRootState; - const config = state.journey.config; + const state = api.getState() as JourneyRootState; + const config = state?.journey?.config; if (!config?.serverConfig) { throw new Error('Server configuration is missing.'); }
🤖 Fix all issues with AI agents
In `@e2e/am-mock-api/package.json`:
- Line 14: Update the devDependency entry for "@types/express" to a
v5-compatible range (e.g., "^5.0.0") so it matches the installed "express" v5.x
and avoids type mismatches; modify the "@types/express" version in package.json
(devDependencies) and then reinstall/update the lockfile (npm/yarn) to ensure
the new types are applied.
In `@package.json`:
- Around line 62-73: Run the NX migration to apply breaking-change updates by
executing npx nx migrate latest and npx nx migrate --run-migrations, then update
configuration related to the nx-release-publish target (verify its release
config structure matches NX 22 expectations), ensure any custom plugins use
createNodesV2 and that TypeScript settings explicitly set
useLegacyTypescriptPlugin if needed (defaults changed to false), and remove
references or reliance on removed items like NX_DISABLE_DB, experimental JS
executor inlining, and legacy options; finally run the workspace
lint/build/tests to confirm everything works.
- Around line 87-88: Upgrade to Vitest 4.0.9 may introduce breaking changes; run
the full test suite (unit, integration, and snapshot tests) and verify
mocking/reporters after bumping "@vitest/coverage-v8" and "@vitest/ui". If
failures occur, update test config and code references: replace any legacy
pool/worker options with modern names (e.g., maxThreads → maxWorkers), ensure
coverage settings use coverage.include and provider: 'v8' (remove
coverage.all/coverage.extensions), adapt any deprecated test API signatures and
mocking/snapshot usage, and regenerate snapshots where appropriate; confirm
reporter output still matches expected formats.
In `@packages/davinci-client/src/lib/config.types.test-d.ts`:
- Around line 94-122: Tests assert that introspection_endpoint and
revocation_endpoint are required, but the comment (and RFC 8414) says they're
optional; fix by making the test and comment consistent: update the comment near
WellKnownResponse to state that only issuer, authorization_endpoint,
token_endpoint, and userinfo_endpoint are required, then remove the expectTypeOf
assertions for introspection_endpoint and revocation_endpoint (the other
expectTypeOf calls for
issuer/authorization_endpoint/token_endpoint/userinfo_endpoint should remain),
or alternatively change the WellKnownResponse type to mark
introspection_endpoint and revocation_endpoint optional if you control that
type; reference symbols: WellKnownResponse and the expectTypeOf assertions in
the test.
In `@packages/journey-client/package.json`:
- Around line 33-34: Remove the build/test tools from the runtime dependencies:
delete the "vite" and "vitest-canvas-mock" entries from the dependencies block
so they exist only under devDependencies; locate the package.json dependencies
array (look for the "vite" and "vitest-canvas-mock" keys) and remove those keys,
leaving the current devDependencies entries intact.
In `@packages/journey-client/src/lib/wellknown.api.ts`:
- Line 14: Add createWellknownError to the barrel export so consumers can import
it alongside wellknownApi and createWellknownSelector; update the export
statement in wellknown.api.ts (currently exporting wellknownApi and
createWellknownSelector) to also export createWellknownError from
'@forgerock/sdk-oidc' to maintain API parity with davinci-client and support
usage in client.store.ts and wellknown.utils.ts.
In `@packages/journey-client/src/lib/wellknown.utils.ts`:
- Around line 38-46: The type guard hasWellknownConfig currently only checks for
serverConfig.wellknown and can incorrectly narrow JourneyConfigInput to
AsyncJourneyClientConfig; update hasWellknownConfig to also validate that
config.serverConfig has a non-empty string baseUrl (i.e., check 'baseUrl' in
config.serverConfig && typeof config.serverConfig.baseUrl === 'string' &&
config.serverConfig.baseUrl.length > 0) so the guard reliably asserts
AsyncJourneyClientConfig.
In `@tools/user-scripts/package.json`:
- Around line 25-26: The package.json currently lists "vitest" under
dependencies; remove the duplicate "vitest" entry from the dependencies object
so vitest remains only in devDependencies (leave "@effect/vitest" as-is if
intended); update the dependencies block to delete the "vitest" key to ensure
test-only packages are not shipped in runtime dependencies.
🧹 Nitpick comments (2)
package.json (1)
52-52: Emptydependenciesobject is unnecessary.The root package.json typically doesn't need a
dependenciesfield for a monorepo. If this was added intentionally for a specific tooling requirement, consider adding a comment explaining its purpose; otherwise, it can be removed.packages/oidc-client/src/lib/wellknown.api.ts (1)
12-38: Use the shared selector factory instead of recreating selectors.The
createWellknownSelectorhelper from@forgerock/sdk-oidcreturns a memoized selector function, which can be directly called with state. Refactoring to use it aligns with the documented intent and avoids recreating the selector on each call.♻️ Proposed refactor
-import { createSelector } from '@reduxjs/toolkit'; - import type { RootState } from './client.types.js'; /** * Re-export the shared wellknown RTK Query API from `@forgerock/sdk-oidc`. @@ export { wellknownApi, createWellknownSelector } from '@forgerock/sdk-oidc'; // Import locally for use in selector below -import { wellknownApi } from '@forgerock/sdk-oidc'; +import { wellknownApi, createWellknownSelector } from '@forgerock/sdk-oidc'; @@ export function wellknownSelector(wellknownUrl: string, state: RootState) { - const selector = createSelector( - wellknownApi.endpoints.configuration.select(wellknownUrl), - (result) => result?.data, - ); - return selector(state); + return createWellknownSelector(wellknownUrl)(state); }
| * @param value - The value to check | ||
| * @returns True if value is a non-null object | ||
| */ | ||
| function isObject(value: unknown): value is Record<string, unknown> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't add a generic to this since the type guard would become unsafe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/journey-client/src/lib/config.types.ts`:
- Around line 11-30: The JourneyClientConfig docs require baseUrl but the type
inherits optional serverConfig from BaseConfig; update JourneyClientConfig to
override serverConfig as required with baseUrl enforced (e.g., replace the
inherited optional serverConfig with a non-optional field that ensures baseUrl:
string is present) so the type matches the documentation; alternatively, if
serverConfig may remain optional, update the doc comment to remove the
"required" wording — change either the JourneyClientConfig type (override
serverConfig) or the doc text to keep them consistent (refer to
JourneyClientConfig, BaseConfig, and serverConfig/baseUrl in your change).
🧹 Nitpick comments (7)
e2e/davinci-app/package.json (1)
19-19: Optional: drop emptydevDependenciesblock.
Keeps the manifest leaner if no dev-only deps are required.♻️ Proposed cleanup
- "devDependencies": {},package.json (1)
52-52: Optional: remove emptydependencies.
Avoids a redundant block if not needed.♻️ Proposed cleanup
- "dependencies": {},packages/journey-client/src/lib/device/device-profile.test.ts (1)
10-10: Type update fromSpyInstancetoMockis correct.The change aligns with Vitest's API evolution where
SpyInstancewas deprecated in favor ofMock. However, the explicit callable signatures in the generic parameter are verbose and may not be necessary.Consider simplifying to:
let warnSpy: Mock<typeof console.warn>;This achieves the same type safety with less boilerplate.
Also applies to: 89-92
packages/sdk-utilities/src/lib/wellknown/wellknown.utils.test.ts (1)
12-72: Test coverage is good; consider simplifying nested describe blocks.The test cases cover the main validation scenarios well. However, the nested
describeblocks are redundant—each wraps only a singleit()and duplicates the test description.♻️ Suggested simplification
describe('isValidWellknownUrl', () => { - describe('isValidWellknownUrl_HttpsUrl_ReturnsTrue', () => { - it('should return true for HTTPS URL', () => { - expect(isValidWellknownUrl('https://am.example.com/.well-known/openid-configuration')).toBe( - true, - ); - }); - }); + it('should return true for HTTPS URL', () => { + expect(isValidWellknownUrl('https://am.example.com/.well-known/openid-configuration')).toBe( + true, + ); + }); // ... similarly for other test casesAdditionally, consider adding edge cases:
- URLs without ports (e.g.,
https://am.example.com/.well-known/openid-configuration)- URLs with query strings or fragments
- Null/undefined inputs (if the function signature allows)
packages/journey-client/src/lib/config.types.ts (1)
32-50: Reduce duplication by extending PathsConfig.
WellknownServerConfigmirrorsPathsConfigfields. ExtendingPathsConfigkeeps future additions consistent.♻️ Proposed refactor
-export interface WellknownServerConfig { - /** Base URL for AM-specific endpoints (authenticate, sessions) */ - baseUrl: string; - /** URL to the OIDC well-known configuration endpoint */ - wellknown: string; - /** Custom path overrides for endpoints */ - paths?: PathsConfig['paths']; - /** Request timeout in milliseconds */ - timeout?: number; -} +export interface WellknownServerConfig extends PathsConfig { + /** URL to the OIDC well-known configuration endpoint */ + wellknown: string; +}packages/journey-client/src/lib/journey.api.ts (1)
118-123: Consider extracting config retrieval into a helper function.The same config retrieval and validation pattern is repeated in
start,next, andterminateendpoints (lines 118-123, 152-157, 183-188). A helper could reduce duplication:♻️ Optional refactor
function getConfigFromState(api: BaseQueryApi): { realmPath?: string; serverConfig: ServerConfig } { const state = api.getState() as JourneyRootState; const config = state.journey.config; if (!config?.serverConfig) { throw new Error('Server configuration is missing.'); } return { realmPath: config.realmPath, serverConfig: config.serverConfig }; }Then in each endpoint:
-const state = api.getState() as JourneyRootState; -const config = state.journey.config; -if (!config?.serverConfig) { - throw new Error('Server configuration is missing.'); -} -const { realmPath, serverConfig } = config; +const { realmPath, serverConfig } = getConfigFromState(api);packages/journey-client/src/lib/client.store.ts (1)
131-135: Structured error information is discarded.
createWellknownErrorreturns aGenericErrorwitherror,message,type, andstatusfields, but onlymessageis used when throwing. Consider preserving the structured error or using a custom error class:♻️ Preserve structured error information
Option 1 - Create a custom error class:
class WellknownError extends Error { constructor(public readonly genericError: GenericError) { super(genericError.message); this.name = 'WellknownError'; } } // Usage: throw new WellknownError(genericError);Option 2 - Add cause to the error:
-throw new Error(genericError.message); +throw new Error(genericError.message, { cause: genericError });
85a4e00 to
95eee18
Compare
cerebrl
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good; left a few comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this file even needed now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think i can remove the re-exports and move them to where its used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need these tests anymore if the wellknown effect in the OIDC module is also tested? I would think we could move or delete these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe These tests are needed - they test journey-client specific code:
- hasWellknownConfig - type guard specific to journey-client's config types
- inferRealmFromIssuer - AM-specific utility that lives in journey-client
| import { createSelector } from '@reduxjs/toolkit'; | ||
| import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'; | ||
|
|
||
| import type { WellKnownResponse } from '@forgerock/sdk-types'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's try to be consistent with how we write "wellknown". It's mostly written wellknown, but some instances, like this, we have wellKnown.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the difference here is that it's a type, versus a variable name. Would you still want the type lower case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just would like consistency with how we write the word. I think historically, we've written it as wellknown. If we change it to wellKnown, then we need to update all the other instances to match. Again, I'm just advocating for consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right but this is a Type. we typically capitalize types. I'm not sticking to this, if we want to write it lower case I will but theres the consistency in how we write the word, and consistency in how we write types.
Just not sure which one takes "precedence".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/davinci-client/src/lib/client.store.ts`:
- Around line 252-257: The catch blocks produce unhelpful "undefined"/"null"
strings by using String(err); change the error extraction in the resume and
update catch handlers to guard nullish thrown values: compute errorMessage with
something like err instanceof Error ? err.message : (err == null ? '' :
String(err)), use log.error(errorMessage) and keep the existing fallback when
building the returned error object so the fallback 'An unexpected error
occurred...' is used; apply the same fix to the update catch at the block that
constructs errorMessage around Line 339 (update/resume catch handlers and the
errorMessage variable/log.error usage).
🧹 Nitpick comments (1)
packages/davinci-client/src/lib/client.store.utils.ts (1)
16-16: Consider creating a localwellknown.api.tswrapper for consistency with other clients.While the direct import from
@forgerock/sdk-oidcwill work (the dependency is properly configured and the export exists), other clients in the workspace (oidc-client,journey-client) follow a pattern of wrapping this import in a localwellknown.api.tsfile. Adopting this pattern indavinci-clientwould improve consistency across the codebase and make it easier to manage the wellknown API if changes are needed.
upgrades nx dependencies and touch points
Re-implement well known configuration and abstract into reusable package
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/sdk-types/src/lib/legacy-config.types.ts (1)
50-79:⚠️ Potential issue | 🟠 MajorAdd a backward-compatible alias for the renamed type.
Renaming a public exported type breaks downstream TypeScript builds. If this is not a major release, provide a compatibility alias (or deprecate the old name).🧩 Suggested compatibility alias
export interface WellknownResponse { issuer: string; authorization_endpoint: string; pushed_authorization_request_endpoint?: string; token_endpoint: string; userinfo_endpoint: string; end_session_endpoint: string; ping_end_idp_session_endpoint?: string; introspection_endpoint: string; revocation_endpoint: string; jwks_uri?: string; device_authorization_endpoint?: string; claims_parameter_supported?: boolean; request_parameter_supported?: boolean; request_uri_parameter_supported?: boolean; require_pushed_authorization_requests?: boolean; scopes_supported?: string[]; response_types_supported?: string[]; response_modes_supported?: string[]; grant_types_supported?: string[]; subject_types_supported?: string[]; id_token_signing_alg_values_supported?: string[]; userinfo_signing_alg_values_supported?: string[]; request_object_signing_alg_values_supported?: string[]; token_endpoint_auth_methods_supported?: string[]; token_endpoint_auth_signing_alg_values_supported?: string[]; claim_types_supported?: string[]; claims_supported?: string[]; code_challenge_methods_supported?: string[]; } + +/** `@deprecated` Use WellknownResponse */ +export type WellKnownResponse = WellknownResponse;
🤖 Fix all issues with AI agents
In `@nx.json`:
- Around line 150-155: The CI is invoking the wrong target name: the Vitest
plugin configured testTargetName as "nxTest" but the workflow and targetDefaults
use "test", so CI won't run tests and nxTest won't inherit cache/settings;
either change the plugin option testTargetName to "test" and update package.json
scripts that call "nx nxTest" to "nx test", or update the CI workflow command to
use "nxTest" and add corresponding targetDefaults entries for "nxTest" (copy
inputs, outputs, dependsOn, cache settings from the existing "test" defaults) so
the generated nxTest targets run in CI and inherit the same configuration.
In `@packages/oidc-client/src/lib/config.types.ts`:
- Around line 25-27: Rename the PascalCase property WellknownResponse on the
InternalDaVinciConfig interface to camelCase wellknownResponse to match
TypeScript conventions and the equivalent type in davinci-client; update the
property name in InternalDaVinciConfig (extending OidcConfig) and any references
to InternalDaVinciConfig.WellknownResponse so they use wellknownResponse to keep
naming consistent across packages.
🧹 Nitpick comments (6)
package.json (1)
52-52: Consider removing the emptydependenciesblock.If no runtime deps exist, dropping the empty object keeps the root manifest cleaner.
Proposed change
- "dependencies": {},e2e/davinci-app/package.json (1)
19-19: Consider removing the emptydevDependenciesblock.If unused, it’s safe to drop for cleanliness.
Proposed change
- "devDependencies": {},packages/oidc-client/src/lib/wellknown.api.ts (1)
8-38: Use the sharedcreateWellknownSelectorto avoid drift.
The doc comment says it wraps the shared selector, but the code re-implements it. Using the shared helper keeps behavior consistent and removes duplication.🔧 Suggested refactor
-import { createSelector } from '@reduxjs/toolkit'; - import type { RootState } from './client.types.js'; /** * Re-export the shared wellknown RTK Query API from `@forgerock/sdk-oidc`. * * The wellknown API provides OIDC endpoint discovery functionality via * the `.well-known/openid-configuration` endpoint. */ -export { wellknownApi, createWellknownSelector } from '@forgerock/sdk-oidc'; +export { wellknownApi, createWellknownSelector } from '@forgerock/sdk-oidc'; -// Import locally for use in selector below -import { wellknownApi } from '@forgerock/sdk-oidc'; +// Import locally for use in selector below +import { wellknownApi, createWellknownSelector } from '@forgerock/sdk-oidc'; export function wellknownSelector(wellknownUrl: string, state: RootState) { - const selector = createSelector( - wellknownApi.endpoints.configuration.select(wellknownUrl), - (result) => result?.data, - ); - return selector(state); + const selector = createWellknownSelector(wellknownUrl); + return selector(state); }packages/journey-client/src/lib/wellknown.utils.test.ts (1)
48-61: Consider adding a test case for emptybaseUrl.The
hasWellknownConfigimplementation checksconfig.serverConfig.baseUrl.length > 0, but there's no test verifying this behavior. Consider adding a test to ensure emptybaseUrlreturnsfalse.📝 Suggested additional test
describe('hasWellknownConfig_EmptyBaseUrl_ReturnsFalse', () => { it('should return false when baseUrl is an empty string', () => { const config: JourneyConfigInput = { serverConfig: { baseUrl: '', wellknown: 'https://am.example.com/.well-known/openid-configuration', }, } as AsyncJourneyClientConfig; const result = hasWellknownConfig(config); expect(result).toBe(false); }); });packages/oidc-client/src/lib/authorize.request.ts (1)
22-33: JSDoc type reference is inconsistent with actual parameter type.Line 25 references
{WellKnownResponse}in the JSDoc but the actual parameter type at line 33 isWellknownResponse(lowercase 'k'). Update the JSDoc to match.📝 Proposed fix
/** * `@function` authorizeµ * `@description` Creates an authorization URL for the OIDC client. - * `@param` {WellKnownResponse} wellknown - The well-known configuration for the OIDC server. + * `@param` {WellknownResponse} wellknown - The well-known configuration for the OIDC server. * `@param` {OidcConfig} config - The OIDC client configuration.packages/oidc-client/src/lib/authorize.request.utils.ts (1)
47-59: Minor JSDoc formatting inconsistency.Line 51 is missing a space before the dash in the parameter description:
wellknown-vsconfig-on line 52.📝 Proposed fix
- * `@param` {WellknownResponse} wellknown- The well-known configuration for the OIDC server. - * `@param` { OidcConfig } config- The OIDC client configuration. - * `@param` { GetAuthorizationUrlOptions } options- Optional parameters for the authorization request. + * `@param` {WellknownResponse} wellknown - The well-known configuration for the OIDC server. + * `@param` {OidcConfig} config - The OIDC client configuration. + * `@param` {GetAuthorizationUrlOptions} options - Optional parameters for the authorization request.
| "plugin": "@nx/vitest", | ||
| "options": { | ||
| "testTargetName": "nxTest" | ||
| }, | ||
| "include": ["packages/**/**/*", "e2e/**/**/*", "tools/**/**/*"] | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the full nx.json file to see targetDefaults structure
cat nx.json | head -200Repository: ForgeRock/ping-javascript-sdk
Length of output: 4536
🏁 Script executed:
# Search for testTargetName and nxTest references
rg -n "testTargetName|nxTest" .Repository: ForgeRock/ping-javascript-sdk
Length of output: 2267
🏁 Script executed:
# Look for test target references in CI workflows
find .github/workflows -type f -name "*.yml" -o -name "*.yaml" | head -20Repository: ForgeRock/ping-javascript-sdk
Length of output: 200
🏁 Script executed:
# Search for nx test/affected calls in workflows and scripts
rg -n "nx\s+(affected|run-many|test)" .github/workflows/ 2>/dev/null || echo "No matches in workflows"
rg -n "\bnx\s+test\b|\bnx\s+affected.*test" . --type yml --type yaml 2>/dev/null || echo "Checking workflows separately"Repository: ForgeRock/ping-javascript-sdk
Length of output: 292
🏁 Script executed:
# Check for targetDefaults entries for test-related targets
rg -n -A5 '"targetDefaults"' nx.jsonRepository: ForgeRock/ping-javascript-sdk
Length of output: 222
CI workflow will not run vitest tests due to target name mismatch.
The @nx/vitest plugin generates targets named nxTest, but .github/workflows/ci-fork.yml:58 explicitly calls nx affected -t ... test ..., which refers to a target named test that doesn't exist. This means vitest tests won't execute in CI.
Additionally, targetDefaults only includes test, test:watch, and test:coverage with no corresponding nxTest entries, so the generated nxTest targets won't inherit the cache, inputs, or outputs settings defined for test.
Choose one approach:
- Rename
testTargetNametotestand update all package.json test scripts to callnx testinstead ofnx nxTest, OR - Update CI workflow to call
nx affected -t ... nxTest ...and addtargetDefaults.nxTestentries mirroring thetestdefaults (inputs, outputs, cache, dependsOn).
🤖 Prompt for AI Agents
In `@nx.json` around lines 150 - 155, The CI is invoking the wrong target name:
the Vitest plugin configured testTargetName as "nxTest" but the workflow and
targetDefaults use "test", so CI won't run tests and nxTest won't inherit
cache/settings; either change the plugin option testTargetName to "test" and
update package.json scripts that call "nx nxTest" to "nx test", or update the CI
workflow command to use "nxTest" and add corresponding targetDefaults entries
for "nxTest" (copy inputs, outputs, dependsOn, cache settings from the existing
"test" defaults) so the generated nxTest targets run in CI and inherit the same
configuration.
| export interface InternalDaVinciConfig extends OidcConfig { | ||
| wellknownResponse: WellKnownResponse; | ||
| WellknownResponse: WellknownResponse; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Property name uses PascalCase instead of camelCase.
The property WellknownResponse on InternalDaVinciConfig uses PascalCase, which is inconsistent with TypeScript conventions and differs from the equivalent property in packages/davinci-client/src/lib/config.types.ts (line 15) which uses wellknownResponse.
🔧 Proposed fix
export interface InternalDaVinciConfig extends OidcConfig {
- WellknownResponse: WellknownResponse;
+ wellknownResponse: WellknownResponse;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export interface InternalDaVinciConfig extends OidcConfig { | |
| wellknownResponse: WellKnownResponse; | |
| WellknownResponse: WellknownResponse; | |
| } | |
| export interface InternalDaVinciConfig extends OidcConfig { | |
| wellknownResponse: WellknownResponse; | |
| } |
🤖 Prompt for AI Agents
In `@packages/oidc-client/src/lib/config.types.ts` around lines 25 - 27, Rename
the PascalCase property WellknownResponse on the InternalDaVinciConfig interface
to camelCase wellknownResponse to match TypeScript conventions and the
equivalent type in davinci-client; update the property name in
InternalDaVinciConfig (extending OidcConfig) and any references to
InternalDaVinciConfig.WellknownResponse so they use wellknownResponse to keep
naming consistent across packages.
JIRA Ticket
https://pingidentity.atlassian.net/browse/SDKS-4665
Description
Add support for well known endpoint
Summary by CodeRabbit
New Features
Improvements
Tests