Skip to content

SDKS-5102: Add Metadata, Image, and FIDO2 Error Capabilities - #126

Open
SteinGabriel wants to merge 1 commit into
mainfrom
SDKS-5102
Open

SDKS-5102: Add Metadata, Image, and FIDO2 Error Capabilities#126
SteinGabriel wants to merge 1 commit into
mainfrom
SDKS-5102

Conversation

@SteinGabriel

@SteinGabriel SteinGabriel commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

https://pingidentity.atlassian.net/browse/SDKS-5102

Updates the reactjs-todo-davinci sample app to demonstrate three new @forgerock/davinci-client capabilities: the MetadataCollector (pausing a DaVinci flow to invoke a third-party SDK), the ImageCollector (Forms image rendering), and the typed FIDO2 client error contract. Each is added as a reference example for developers integrating DaVinci flows.

Changes

reactjs-todo-davinci/client/components/davinci-client

  • metadata.js (new) — MetadataComponent for MetadataCollector. Calls a runThirdPartySdk(config) stand-in against collector.output.config, then reports that SDK's outcome back to DaVinci: its success value via updater(sdkResult.value), or a structured MetadataError ({code, message} object literal, since the SDK exposes MetadataError as a type with no builder function) on failure. Checks updater's own return for an error before calling setNext(). Renders explicit "Success" and "Failure" buttons so both branches have a deterministic trigger, mirroring the SDK repo's own e2e fixture.
  • image.js (new) — ImageComponent for ImageCollector, rendering <img src alt data-testid="form-image">, wrapped in <a href> when output.href is present. parseSafeHref restricts the href to http:/https: schemes, as the SDK's type doc requires consumers to sanitize this value.
  • fido.js — new describeFidoError helper branches displayed copy on the typed GenericError.type returned by fido().register()/authenticate(): fido_error passes the SDK message through as an expected WebAuthn/browser failure, anything else gets generic unexpected-error copy. Error logging now uses labeled console.error calls.
  • form.jsImageCollector and MetadataCollector cases added to mapCollectorsToComponents, following the existing switch-statement pattern.
  • readonly.js — applies theme.textClass and mb-3 to both the ReadOnlyCollector and RichTextCollector render branches. Found during manual testing: the metadata flow's trailing message step rendered with class="", unstyled and invisible against the dark theme.

reactjs-todo-davinci (docs / manifest)

  • README.mdImageCollector and MetadataCollector added to the supported-collectors list.
  • package.json — dependency keys reordered alphabetically. @forgerock/davinci-client stays at "latest".

Tests

  • e2e/davinci-image.spec.js (new) — asserts the image renders with non-empty src/alt and no hyperlink wrapper, and that the wrapper appears when output.href is present. test.describe.skip.
  • e2e/davinci-metadata.spec.js (new) — asserts the flow advances on the Success path and on the Failure path (structured error reported, flow still advances). test.describe.skip.
  • e2e/davinci-fido.spec.js — the two existing failure tests now assert the branched fido_error copy directly rather than only checking the generic fallback is absent. Remains test.describe.skip for the same pre-existing WebAuthn registration limitation.

Unverified coverage — please read before approving

The image and metadata collector paths are not covered by a passing e2e run. Both new specs are test.describe.skip with acrValue = 'TBD', because they require DaVinci flow policy IDs that emit an IMAGE field and a METADATA action, which are not yet available. A green CI run on this PR does not exercise either new component. The FIDO2 spec is likewise still skipped (pre-existing).

The metadata component was verified manually against a real Metadata Flow, which is how the readonly.js styling bug was found. The image component has not been verified against a live flow.

MetadataCollector is not in a published @forgerock/davinci-client release. It only exists on PR #727 (SDKS-5100-metadata-collector); the latest published version is 2.1.0. package.json declares "latest" and the lockfile resolves entirely to the npm registry, so npm ci is clean and no ephemeral build URL is committed. To exercise the metadata path locally before #727 merges, apply an uncommitted override:

npm install @forgerock/davinci-client@https://pkg.pr.new/@forgerock/davinci-client@727 -w javascript/reactjs-todo-davinci

Revert that before committing. Once #727 publishes, "latest" resolves correctly with no change needed here.

How to test

1. Metadata collector

  1. npm ci from the repo root, then apply the pkg.pr.new override above.
  2. npm run start:reactjs-todo-dv from /javascript.
  3. Navigate to ?acrValue=<metadata-flow-policy-id> and sign in.
  4. Confirm the DaVinci-supplied config payload renders in the <pre> block.
  5. Click Success — the simulated third-party SDK resolves with a value, updater reports it, and the flow advances.
  6. Restart the flow and click Failure — a METADATA_PROCESSING_ERROR is reported via updater and the flow still advances. Confirm the trailing message step is legible (this is the readonly.js fix).

2. Image collector

  1. Navigate to ?acrValue=<image-flow-policy-id> and sign in.
  2. Confirm the image renders with the flow's src and alt.
  3. For a flow supplying href, confirm the image is wrapped in a same-tab link.

Verify the href sanitizer

Configure a flow whose image href uses a javascript: scheme, or temporarily hardcode one. Confirm the image renders unwrapped rather than as a link.

3. FIDO2 typed error branching

  1. Navigate to a FIDO2-enabled flow in a browser where WebAuthn will fail (no authenticator, or cancel the prompt).
  2. Confirm the alert reads "Your device or browser could not complete this request." for a fido_error, not the generic "Something unexpected went wrong." copy.

Summary by CodeRabbit

  • New Features

    • Added support for image and metadata collection steps.
    • Images can display safely with optional links and error messages.
    • Metadata steps now support Success and Failure actions with loading feedback.
    • Added documentation for the newly supported collector types.
  • Bug Fixes

    • Improved FIDO error messages shown to users.
    • Applied theme styling consistently to read-only content.
  • Tests

    • Strengthened FIDO error-flow checks.
    • Added coverage for image and metadata flows.

@SteinGabriel SteinGabriel added the do not merge Do not merge label Jul 29, 2026
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@SteinGabriel, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ad76af94-8dc4-4b21-afab-13be791f6b5b

📥 Commits

Reviewing files that changed from the base of the PR and between 19c58da and 4d19084.

📒 Files selected for processing (8)
  • javascript/reactjs-todo-davinci/README.md
  • javascript/reactjs-todo-davinci/client/components/davinci-client/fido.js
  • javascript/reactjs-todo-davinci/client/components/davinci-client/form.js
  • javascript/reactjs-todo-davinci/client/components/davinci-client/image.js
  • javascript/reactjs-todo-davinci/client/components/davinci-client/metadata.js
  • javascript/reactjs-todo-davinci/client/components/davinci-client/readonly.js
  • javascript/reactjs-todo-davinci/e2e/davinci-fido.spec.js
  • javascript/reactjs-todo-davinci/e2e/davinci-image.spec.js
📝 Walkthrough

Walkthrough

The React DaVinci client now supports image and metadata collectors, including safe image links and metadata continuation actions. FIDO error messages use typed SDK errors, read-only content adopts theme styling, and related E2E coverage and documentation were updated.

Changes

DaVinci collector updates

Layer / File(s) Summary
Image collector rendering
javascript/reactjs-todo-davinci/README.md, javascript/reactjs-todo-davinci/client/components/davinci-client/form.js, javascript/reactjs-todo-davinci/client/components/davinci-client/image.js, javascript/reactjs-todo-davinci/e2e/davinci-image.spec.js
Adds ImageCollector support, renders images with validated HTTP(S) links, and adds skipped image-flow tests.
Metadata collector flow
javascript/reactjs-todo-davinci/client/components/davinci-client/metadata.js, javascript/reactjs-todo-davinci/e2e/davinci-metadata.spec.js
Adds metadata configuration display, success/failure actions, SDK result handling, updater integration, and skipped E2E scenarios.
FIDO errors and themed read-only output
javascript/reactjs-todo-davinci/client/components/davinci-client/fido.js, javascript/reactjs-todo-davinci/client/components/davinci-client/readonly.js, javascript/reactjs-todo-davinci/e2e/davinci-fido.spec.js
Uses typed FIDO errors for displayed messages, strengthens failure assertions, and applies theme text classes to read-only content.
Dependency declaration ordering
javascript/reactjs-todo-davinci/package.json
Reorders two existing dependencies without changing versions.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant MetadataComponent
  participant ThirdPartySDK
  participant CollectorUpdater
  participant FormFlow
  User->>MetadataComponent: Select Success or Failure
  MetadataComponent->>ThirdPartySDK: Run with metadata config
  ThirdPartySDK-->>MetadataComponent: Return success or error
  MetadataComponent->>CollectorUpdater: Submit result
  CollectorUpdater-->>MetadataComponent: Return update status
  MetadataComponent->>FormFlow: Advance on success
Loading

Possibly related PRs

Suggested reviewers: vatsalparikh

Poem

I’m a bunny with images and metadata in sight,
Safe little links and themed text shining bright.
FIDO errors now speak clear and true,
While Success and Failure hop through.
Tests thump their paws: “The flow is right!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main additions: MetadataCollector, ImageCollector, and FIDO2 error handling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch SDKS-5102

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
javascript/reactjs-todo-davinci/client/components/davinci-client/metadata.js (1)

64-81: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Always clear loading state when an SDK operation rejects.

A rejected third-party SDK call or thrown updater bypasses line 81, leaving both actions disabled with no user-facing error. Wrap the sequence in try/catch/finally.

Proposed fix
   async function handleContinue(shouldSucceed) {
     setIsLoading(true);
     setError(null);

-    const sdkResult = await runThirdPartySdk(collector.output.config, shouldSucceed);
-    const updateResult =
-      sdkResult && 'error' in sdkResult
-        ? updater({ code: 'METADATA_PROCESSING_ERROR', message: sdkResult.error })
-        : updater(sdkResult.value);
-
-    if (updateResult && 'error' in updateResult) {
-      setError(updateResult.error?.message || 'Update error');
-      console.error('Error updating metadata collector:', updateResult.error);
-    } else {
-      await submitForm();
+    try {
+      const sdkResult = await runThirdPartySdk(collector.output.config, shouldSucceed);
+      const updateResult =
+        sdkResult && 'error' in sdkResult
+          ? updater({ code: 'METADATA_PROCESSING_ERROR', message: sdkResult.error })
+          : updater(sdkResult.value);
+
+      if (updateResult && 'error' in updateResult) {
+        setError(updateResult.error?.message || 'Update error');
+      } else {
+        await submitForm();
+      }
+    } catch (error) {
+      console.error('Error processing metadata collector:', error);
+      setError('Metadata processing failed');
+    } finally {
+      setIsLoading(false);
     }
-
-    setIsLoading(false);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@javascript/reactjs-todo-davinci/client/components/davinci-client/metadata.js`
around lines 64 - 81, Update handleContinue to wrap the runThirdPartySdk,
updater, and submitForm sequence in try/catch/finally. Catch rejected SDK calls
or thrown updater errors, surface the failure through setError, and ensure
setIsLoading(false) runs in finally so both actions are re-enabled.
javascript/reactjs-todo-davinci/e2e/davinci-image.spec.js (1)

15-36: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Add policy-independent tests that run in CI.

Both new E2E suites are skipped with TBD flow IDs, so CI does not exercise image URL filtering or metadata success/failure continuation.

  • javascript/reactjs-todo-davinci/e2e/davinci-image.spec.js#L15-L36: retain the policy-backed placeholder, but add runnable component coverage for allowed, malformed, and unsafe href values.
  • javascript/reactjs-todo-davinci/e2e/davinci-metadata.spec.js#L15-L36: retain the policy-backed placeholder, but add runnable component coverage for successful updates, returned update errors, and rejected SDK calls.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@javascript/reactjs-todo-davinci/e2e/davinci-image.spec.js` around lines 15 -
36, Add runnable, policy-independent component coverage while retaining the
skipped policy-backed tests in
javascript/reactjs-todo-davinci/e2e/davinci-image.spec.js lines 15-36: cover
allowed, malformed, and unsafe href values. Also add runnable coverage in
javascript/reactjs-todo-davinci/e2e/davinci-metadata.spec.js lines 15-36 for
successful metadata updates, returned update errors, and rejected SDK calls,
using the existing image and metadata test symbols.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@javascript/reactjs-todo-davinci/e2e/davinci-fido.spec.js`:
- Around line 111-116: Update the alert text assertions in the FIDO error test
to avoid requiring an exact match against the alert container, which also
includes the Try Again button. Use toContainText for both failure assertions, or
target the alert’s inner error-message div while preserving the existing
expected messages.

---

Nitpick comments:
In
`@javascript/reactjs-todo-davinci/client/components/davinci-client/metadata.js`:
- Around line 64-81: Update handleContinue to wrap the runThirdPartySdk,
updater, and submitForm sequence in try/catch/finally. Catch rejected SDK calls
or thrown updater errors, surface the failure through setError, and ensure
setIsLoading(false) runs in finally so both actions are re-enabled.

In `@javascript/reactjs-todo-davinci/e2e/davinci-image.spec.js`:
- Around line 15-36: Add runnable, policy-independent component coverage while
retaining the skipped policy-backed tests in
javascript/reactjs-todo-davinci/e2e/davinci-image.spec.js lines 15-36: cover
allowed, malformed, and unsafe href values. Also add runnable coverage in
javascript/reactjs-todo-davinci/e2e/davinci-metadata.spec.js lines 15-36 for
successful metadata updates, returned update errors, and rejected SDK calls,
using the existing image and metadata test symbols.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3f0ae4e5-1d46-45ef-bf00-3105bc033830

📥 Commits

Reviewing files that changed from the base of the PR and between 360d26f and 19c58da.

📒 Files selected for processing (10)
  • javascript/reactjs-todo-davinci/README.md
  • javascript/reactjs-todo-davinci/client/components/davinci-client/fido.js
  • javascript/reactjs-todo-davinci/client/components/davinci-client/form.js
  • javascript/reactjs-todo-davinci/client/components/davinci-client/image.js
  • javascript/reactjs-todo-davinci/client/components/davinci-client/metadata.js
  • javascript/reactjs-todo-davinci/client/components/davinci-client/readonly.js
  • javascript/reactjs-todo-davinci/e2e/davinci-fido.spec.js
  • javascript/reactjs-todo-davinci/e2e/davinci-image.spec.js
  • javascript/reactjs-todo-davinci/e2e/davinci-metadata.spec.js
  • javascript/reactjs-todo-davinci/package.json

Comment thread javascript/reactjs-todo-davinci/e2e/davinci-fido.spec.js

@ancheetah ancheetah left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments. Idk how I feel about including metadata and image e2e tests. I feel this duplicates what's already in the sdk repo.

*/
function describeFidoError(fidoError) {
if (fidoError.type === 'fido_error') {
return fidoError.message || 'Your device or browser could not complete this request.';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we return fidoError.code instead so that we can assert a specific error in the e2e test? For example, if the prompt is cancelled, you should get a NotAllowedError code.
Example:
https://github.com/ForgeRock/ping-javascript-sdk/blob/main/e2e/davinci-suites/src/fido.test.ts#L239

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

describeFidoError now returns { message, code }, exposed via data-error-code on the alert. I've added assertions on it in both failure tests, matching the pattern SDK e2e suite.
Thanks!

Comment on lines +73 to +74
setError(describeFidoError(response));
console.error('Fido error:', response);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is an error, we still need to update the collector with that error and send it to DaVinci. Are we doing that here?
https://github.com/ForgeRock/ping-javascript-sdk/blob/main/e2e/davinci-app/components/fido.ts#L33-L37

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the error branch now calls updater(response) and send it to DaVinci.
Thanks for pointing this out.

"@forgerock/oidc-client": "latest",
"@forgerock/sdk-utilities": "latest",
"@forgerock/protect": "latest",
"@forgerock/sdk-utilities": "latest",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need sdk utilities package?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, @forgerock/sdk-utilities itself is pre-existing, used for makeOidcConfig/makeDavinciConfig. For some reason it got automatically reordered at some point. I restored it back to how it was before.

"webpack-dev-server": "^5.1.0"
},
"dependencies": {
"@forgerock/davinci-client": "latest",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to test this with a beta you can grab it from here:
ForgeRock/ping-javascript-sdk#730 (comment)

Please mark this PR with DO NOT MERGE label so we don't accidentally merge it before the 2.2 release.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's what I've done for local testing. I used pkg.pr.new to install the SDK from that PR.
The "do not merge" label was applied when this PR was created. It'll be merged only after these features are released.

feat(reactjs-todo-davinci): branch FIDO2 error UI on typed error contract

chore(reactjs-todo-davinci): temporarily depend on davinci-client PR #727 build for MetadataCollector

feat(reactjs-todo-davinci): add MetadataCollector component

test(reactjs-todo-davinci): add image/metadata e2e specs, extend fido error assertion

fix(reactjs-todo-davinci): import getMetadataError from SDK utils subpath

fix(reactjs-todo-davinci): sanitize ImageCollector href scheme before render

fix(reactjs-todo-davinci): build MetadataError literal, drop removed getMetadataError import

fix(reactjs-todo-davinci): redact metadata payload display, flag unsafe storage of sensitive data

test(reactjs-todo-davinci): assert positive fido_error copy instead of negative check

fix(reactjs-todo-davinci): log error details with labeled console.error, matching codebase convention

docs(reactjs-todo-davinci): add ImageCollector, MetadataCollector to README

feat(reactjs-todo-davinci): redesign MetadataCollector around third-party SDK invocation

fix(e2e): use toContainText for fido alert assertions

fix(davinci): report fido error to updater before local display

chore(reactjs-todo-davinci): revert unnecessary dependency reorder

test(reactjs-todo-davinci): trim e2e specs to sample-specific coverage, drop duplicate metadata spec
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do not merge Do not merge

Development

Successfully merging this pull request may close these issues.

2 participants