Skip to content

SDKS-4670: Add support for extension in PhoneNumberCollector#573

Open
ancheetah wants to merge 3 commits intomainfrom
SDKS-4670-phone-ext
Open

SDKS-4670: Add support for extension in PhoneNumberCollector#573
ancheetah wants to merge 3 commits intomainfrom
SDKS-4670-phone-ext

Conversation

@ancheetah
Copy link
Copy Markdown
Collaborator

@ancheetah ancheetah commented Apr 17, 2026

JIRA Ticket

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

Description

Added PhoneNumberExtensionCollector — a new first-class collector type for DaVinci PHONE_NUMBER fields that include an extension. When a field has showExtension: true, the SDK now produces a PhoneNumberExtensionCollector instead of a PhoneNumberCollector.

Screenshot 2026-04-30 at 11 24 03 AM

New Types (collector.types.ts)

  • PhoneNumberExtensionInputValue{ countryCode: string; phoneNumber: string; extension: string }
  • PhoneNumberExtensionOutputValue{ countryCode?: string; phoneNumber?: string; extension?: string }
  • PhoneNumberExtensionCollectorObjectValueCollector with extensionLabel: string as a direct property on output
  • Added to ObjectValueCollectorTypes, InferValueObjectCollectorType, and ObjectValueCollectors

New Types (davinci.types.ts)

  • PhoneNumberExtensionField — extends PhoneNumberField with showExtension: boolean and extensionLabel: string
  • Added to ComplexValueFields

Updated Functions (collector.utils.ts)

returnObjectCollector

  • Field constraint widened to include PhoneNumberExtensionField
  • prefillData parameter type widened to PhoneNumberOutputValue | PhoneNumberExtensionOutputValue

returnObjectValueCollector

  • When showExtension === true: produces a PhoneNumberExtensionCollector with extensionLabel on output and extension in input.value
  • Otherwise: produces a PhoneNumberCollector as before
  • extensionLabel uses a sentinel null so an empty-string label is correctly included via extensionLabel !== null conditional spread

Reducer (node.reducer.ts)

  • PhoneNumberExtensionCollector added to the initial state type union
  • New node/update handler validates and applies { countryCode, phoneNumber, extension } to collector.input.value
  • node/next PHONE_NUMBER prefill cast updated to PhoneNumberOutputValue | PhoneNumberExtensionOutputValue

Breaking Changes

None. PhoneNumberInputValue and PhoneNumberOutputValue are unchanged from main. returnObjectCollector's signature changes are purely additive.


Test Coverage

  • Unit tests updated in collector.utils.test.ts (48 passing) and node.reducer.test.ts (29 passing)
  • Both PhoneNumberCollector and PhoneNumberExtensionCollector are covered in the e2e test suite (phone-number-field.test.ts, form-fields.test.ts), with the e2e app's object-value.ts component updated to render both collector variants.

Summary by CodeRabbit

  • New Features

    • Added support for phone number fields with extensions. When configured with showExtension: true, users can now input both a phone number and an extension value, with both values captured in form submissions.
  • Chores

    • Updated gitignore rules.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 17, 2026

🦋 Changeset detected

Latest commit: b271274

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@forgerock/davinci-client Minor
@forgerock/device-client Minor
@forgerock/journey-client Minor
@forgerock/oidc-client Minor
@forgerock/protect Minor
@forgerock/sdk-types Minor
@forgerock/sdk-utilities Minor
@forgerock/iframe-manager Minor
@forgerock/sdk-logger Minor
@forgerock/sdk-oidc Minor
@forgerock/sdk-request-middleware Minor
@forgerock/storage Minor

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

📝 Walkthrough

Walkthrough

Adds a PhoneNumberExtensionCollector and PhoneNumberExtensionField types; updates collector factories, client/store typings, reducer logic, UI rendering, and tests so PHONE_NUMBER fields with showExtension:true expose an extension input and propagate extension values through update and submit flows.

Changes

Phone number extension feature

Layer / File(s) Summary
Type declarations
packages/davinci-client/src/lib/collector.types.ts, packages/davinci-client/src/lib/davinci.types.ts, packages/davinci-client/src/lib/node.types.ts
Add PhoneNumberExtensionCollector, PhoneNumberExtensionField, PhoneNumberExtensionInputValue/PhoneNumberExtensionOutputValue; update unions to include the extension variant; minor reorder in PhoneNumberField.
Collector factory / utils
packages/davinci-client/src/lib/collector.utils.ts
returnObjectCollector/returnObjectValueCollector accept PhoneNumberExtensionField, populate extension in defaults/prefill, conditionally emit extensionLabel, and select PhoneNumberExtensionCollector when showExtension is true.
Collector utils tests
packages/davinci-client/src/lib/collector.utils.test.ts
Add tests for showExtension:true path asserting PhoneNumberExtensionCollector, extension presence in input/output, extensionLabel emission, and prefill behavior.
Client/store typing
packages/davinci-client/src/lib/client.store.ts
Expand davinci.update value union to include PhoneNumberExtensionInputValue.
Reducer logic & tests
packages/davinci-client/src/lib/node.reducer.ts, packages/davinci-client/src/lib/node.reducer.test.ts
Initialize PHONE_NUMBER collectors with either OutputValue shape, accept PhoneNumberExtensionInputValue in updates, add runtime handling for PhoneNumberExtensionCollector; tests added/updated to cover default, prefill, and update flows including extension.
Node type-level tests
packages/davinci-client/src/lib/collector.types.test-d.ts, packages/davinci-client/src/lib/node.types.test-d.ts
Extend compile-time assertions to validate PhoneNumberExtensionCollector mapping, structural shapes, and include extension collector in Collectors union tests.
UI wiring & component
e2e/davinci-app/components/object-value.ts, e2e/davinci-app/main.ts
objectValueComponent widened to handle PhoneNumberExtensionCollector (renders phone + extension inputs and emits typed PhoneNumberExtensionInputValue); renderForm branch updated to route extension collectors into the same component.
E2E tests
e2e/davinci-suites/src/form-fields.test.ts, e2e/davinci-suites/src/phone-number-field.test.ts
E2E tests updated to fill/assert extension input, adjust selectors and submitted payload expectations, harden POST body parsing, and assert extension visibility where appropriate.
Changeset & misc
/.changeset/long-singers-do.md, .gitignore
New changeset declaring minor release for @forgerock/davinci-client; .gitignore updated to ignore .polaris-setup-progress.json and fix newline.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant UI as ObjectValueComponent
  participant Client as DavinciClient.update
  participant Reducer as NodeReducer
  participant Store as ClientStore
  participant Server as SubmitHandler

  User->>UI: enter phoneNumber + extension
  UI->>Client: update(PhoneNumberExtensionInputValue)
  Client->>Reducer: dispatch updateCollectorValues
  Reducer->>Store: persist collector.input.value {phoneNumber,countryCode,extension}
  User->>UI: submit form
  UI->>Server: POST form with collector outputs (includes extension)
  Server->>Store: process submitted values
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • cerebrl
  • ryanbas21

Poem

🐰
I hopped through types and fields with cheer,
A tiny box for numbers and more,
Now extensions tag along so near,
Payloads stretch a bit and soar,
Hooray — another field to adore!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding extension support to PhoneNumberCollector, which aligns with the comprehensive changeset.
Description check ✅ Passed The description comprehensively covers the JIRA ticket, lists new types, updated functions, reducer changes, and test coverage, with clear explanations of the implementation approach.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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-4670-phone-ext

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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

@nx-cloud
Copy link
Copy Markdown
Contributor

nx-cloud Bot commented Apr 17, 2026

View your CI Pipeline Execution ↗ for commit b271274

Command Status Duration Result
nx run-many -t build --no-agents ✅ Succeeded <1s View ↗
nx affected -t build lint test typecheck e2e-ci ✅ Succeeded 7m 17s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-04 19:04:58 UTC

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a 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 (2)
packages/davinci-client/src/lib/davinci.types.ts (1)

154-162: ⚠️ Potential issue | 🟡 Minor

showExtension as required may bite older DaVinci environments.

Marking showExtension: boolean as required enforces it at the type level, but DaVinci responses in older/unupdated environments may omit the field. Consider making it optional (showExtension?: boolean) and defaulting to false in collector.utils.ts to preserve backward compatibility. Otherwise, this is effectively a runtime coupling on a specific DaVinci version.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/davinci-client/src/lib/davinci.types.ts` around lines 154 - 162, The
PhoneNumberField type currently requires showExtension which breaks with older
DaVinci payloads; make showExtension optional by changing its declaration to
showExtension?: boolean in the PhoneNumberField type and update the code that
consumes it (see collector.utils.ts) to treat missing values as false by default
(i.e., when accessing field.showExtension, coerce undefined to false). Ensure
all usages of PhoneNumberField and any destructuring in collector.utils.ts
handle the optional property.
packages/davinci-client/src/lib/collector.utils.ts (1)

646-665: ⚠️ Potential issue | 🟡 Minor

Confirm field.showExtension is always present from DaVinci.

PhoneNumberField.showExtension is declared as a required boolean in davinci.types.ts, and options = { showExtension: field.showExtension } passes it through directly. However, PhoneNumberOptions.showExtension is optional in collector.types.ts. If DaVinci ever returns a PHONE field without showExtension (older environments or feature-flag rollouts), options.showExtension will be undefined rather than a safe default. Consider adding a defensive default to avoid ambiguity:

Suggested fix
-    options = { showExtension: field.showExtension };
+    options = { showExtension: field.showExtension ?? false };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/davinci-client/src/lib/collector.utils.ts` around lines 646 - 665,
The code passes field.showExtension directly into options but
PhoneNumberOptions.showExtension is optional; make this defensive by ensuring
options.showExtension is always a boolean (e.g., use nullish coalescing or
Boolean conversion) so it defaults when PhoneNumberField may omit it; update the
assignment of options (the variable named options and the property
field.showExtension) to coerce a safe default (for example false) rather than
letting undefined through.
🧹 Nitpick comments (2)
packages/davinci-client/src/lib/collector.types.test-d.ts (1)

410-432: Output value in the type-check literal is missing extension.

The concrete PhoneNumberCollector literal at line 428 sets output.value: { countryCode: '+1', phoneNumber: '5555555555' } without extension. That's fine because PhoneNumberOutputValue.extension is optional, but the companion test at line 382 does include extension: '' in both input and output values — consistency here would better document the intended shape and guard against future regressions if extension is ever tightened to required on the output type.

-          value: { countryCode: '+1', phoneNumber: '5555555555' },
+          value: { countryCode: '+1', phoneNumber: '5555555555', extension: '' },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/davinci-client/src/lib/collector.types.test-d.ts` around lines 410 -
432, The test literal for PhoneNumberCollector omits the optional extension
field in output.value; update the PhoneNumberCollector test object (the variable
named collector used in the spec) so its output.value includes extension: '' to
match the input.value and the PhoneNumberOutputValue shape (i.e., set
output.value to { countryCode: '+1', phoneNumber: '5555555555', extension: '' })
so the literal remains consistent with PhoneNumberCollector and guards against
future tightening of the type.
packages/davinci-client/src/lib/collector.utils.ts (1)

680-686: Inconsistent options fallback in output spread.

...(options && { options: options || [] }) mixes object/array semantics. For PhoneNumberCollector, options is { showExtension: boolean } (an object), so the inner || [] fallback would yield a type‑incompatible empty array. It's also dead code — the outer && already guarantees options is truthy. Consider simplifying to avoid future confusion:

♻️ Proposed simplification
-      ...(options && { options: options || [] }),
-      ...(defaultValue && { value: defaultValue }),
+      ...(options !== undefined && { options }),
+      ...(defaultValue !== undefined && { value: defaultValue }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/davinci-client/src/lib/collector.utils.ts` around lines 680 - 686,
The spread for options in the output object mixes array fallback and redundant
checks; replace ...(options && { options: options || [] }) with a simple
...(options && { options }) (or equivalently include options only when defined)
inside the output object in collector.utils.ts (the object that builds output: {
key, label, type, ... }). This avoids returning an incompatible [] for
PhoneNumberCollector (where options is an object) and removes the dead || []
code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/davinci-client/src/lib/collector.types.ts`:
- Around line 309-311: The PhoneNumberOptions interface currently makes
showExtension optional, but downstream code and collector.utils.ts
unconditionally sets options: { showExtension: field.showExtension }, so update
the type to reflect reality by changing PhoneNumberOptions to require
showExtension: boolean; also check collector.utils.ts and any other creators to
ensure they return a boolean (coerce if necessary) so the required type is
always satisfied across producers and consumers.
- Around line 297-307: The change made PhoneNumberInputValue.extension to be
required in collector.types.ts but tests and consumers still construct
PhoneNumberInputValue without extension; update all tests and any call sites
that create PhoneNumberInputValue (look for usages constructing objects with
countryCode and phoneNumber) to include extension: '' or appropriate value, and
add a changeset entry documenting this public breaking change so consumers are
aware; ensure PhoneNumberInputValue, PhoneNumberOutputValue, and any utility
that fallbacks extension remain consistent.

---

Outside diff comments:
In `@packages/davinci-client/src/lib/collector.utils.ts`:
- Around line 646-665: The code passes field.showExtension directly into options
but PhoneNumberOptions.showExtension is optional; make this defensive by
ensuring options.showExtension is always a boolean (e.g., use nullish coalescing
or Boolean conversion) so it defaults when PhoneNumberField may omit it; update
the assignment of options (the variable named options and the property
field.showExtension) to coerce a safe default (for example false) rather than
letting undefined through.

In `@packages/davinci-client/src/lib/davinci.types.ts`:
- Around line 154-162: The PhoneNumberField type currently requires
showExtension which breaks with older DaVinci payloads; make showExtension
optional by changing its declaration to showExtension?: boolean in the
PhoneNumberField type and update the code that consumes it (see
collector.utils.ts) to treat missing values as false by default (i.e., when
accessing field.showExtension, coerce undefined to false). Ensure all usages of
PhoneNumberField and any destructuring in collector.utils.ts handle the optional
property.

---

Nitpick comments:
In `@packages/davinci-client/src/lib/collector.types.test-d.ts`:
- Around line 410-432: The test literal for PhoneNumberCollector omits the
optional extension field in output.value; update the PhoneNumberCollector test
object (the variable named collector used in the spec) so its output.value
includes extension: '' to match the input.value and the PhoneNumberOutputValue
shape (i.e., set output.value to { countryCode: '+1', phoneNumber: '5555555555',
extension: '' }) so the literal remains consistent with PhoneNumberCollector and
guards against future tightening of the type.

In `@packages/davinci-client/src/lib/collector.utils.ts`:
- Around line 680-686: The spread for options in the output object mixes array
fallback and redundant checks; replace ...(options && { options: options || []
}) with a simple ...(options && { options }) (or equivalently include options
only when defined) inside the output object in collector.utils.ts (the object
that builds output: { key, label, type, ... }). This avoids returning an
incompatible [] for PhoneNumberCollector (where options is an object) and
removes the dead || [] code.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9343cbc3-031f-4e2b-b31e-cae954dcdb2c

📥 Commits

Reviewing files that changed from the base of the PR and between 9088443 and 866974e.

📒 Files selected for processing (9)
  • .changeset/long-singers-do.md
  • e2e/davinci-app/components/object-value.ts
  • e2e/davinci-suites/src/form-fields.test.ts
  • packages/davinci-client/src/lib/collector.types.test-d.ts
  • packages/davinci-client/src/lib/collector.types.ts
  • packages/davinci-client/src/lib/collector.utils.test.ts
  • packages/davinci-client/src/lib/collector.utils.ts
  • packages/davinci-client/src/lib/davinci.types.ts
  • packages/davinci-client/src/lib/node.reducer.test.ts

Comment thread packages/davinci-client/src/lib/collector.types.ts
Comment thread packages/davinci-client/src/lib/collector.types.ts Outdated
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 17, 2026

Codecov Report

❌ Patch coverage is 85.96491% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 17.61%. Comparing base (5d6747a) to head (b271274).
⚠️ Report is 90 commits behind head on main.

Files with missing lines Patch % Lines
packages/davinci-client/src/lib/node.reducer.ts 57.89% 8 Missing ⚠️

❌ Your project status has failed because the head coverage (17.61%) 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     #573       +/-   ##
===========================================
- Coverage   70.90%   17.61%   -53.29%     
===========================================
  Files          53      154      +101     
  Lines        2021    24243    +22222     
  Branches      377     1159      +782     
===========================================
+ Hits         1433     4271     +2838     
- Misses        588    19972    +19384     
Files with missing lines Coverage Δ
packages/davinci-client/src/lib/client.store.ts 0.29% <ø> (ø)
packages/davinci-client/src/lib/collector.types.ts 100.00% <ø> (ø)
packages/davinci-client/src/lib/collector.utils.ts 83.46% <100.00%> (ø)
packages/davinci-client/src/lib/davinci.types.ts 100.00% <ø> (ø)
packages/davinci-client/src/lib/node.types.ts 100.00% <ø> (ø)
packages/davinci-client/src/lib/node.reducer.ts 70.22% <57.89%> (ø)

... and 96 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 17, 2026

Open in StackBlitz

@forgerock/davinci-client

pnpm add https://pkg.pr.new/@forgerock/davinci-client@573

@forgerock/device-client

pnpm add https://pkg.pr.new/@forgerock/device-client@573

@forgerock/journey-client

pnpm add https://pkg.pr.new/@forgerock/journey-client@573

@forgerock/oidc-client

pnpm add https://pkg.pr.new/@forgerock/oidc-client@573

@forgerock/protect

pnpm add https://pkg.pr.new/@forgerock/protect@573

@forgerock/sdk-types

pnpm add https://pkg.pr.new/@forgerock/sdk-types@573

@forgerock/sdk-utilities

pnpm add https://pkg.pr.new/@forgerock/sdk-utilities@573

@forgerock/iframe-manager

pnpm add https://pkg.pr.new/@forgerock/iframe-manager@573

@forgerock/sdk-logger

pnpm add https://pkg.pr.new/@forgerock/sdk-logger@573

@forgerock/sdk-oidc

pnpm add https://pkg.pr.new/@forgerock/sdk-oidc@573

@forgerock/sdk-request-middleware

pnpm add https://pkg.pr.new/@forgerock/sdk-request-middleware@573

@forgerock/storage

pnpm add https://pkg.pr.new/@forgerock/storage@573

commit: b271274

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 17, 2026

Deployed 515784a to https://ForgeRock.github.io/ping-javascript-sdk/pr-573/515784a101b4b09f00ae11b0fb09325dce99cbb6 branch gh-pages in ForgeRock/ping-javascript-sdk

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 17, 2026

📦 Bundle Size Analysis

📦 Bundle Size Analysis

🚨 Significant Changes

🔻 @forgerock/device-client - 0.0 KB (-10.0 KB, -100.0%)
🔻 @forgerock/journey-client - 0.0 KB (-91.9 KB, -100.0%)

📊 Minor Changes

📈 @forgerock/davinci-client - 48.9 KB (+0.3 KB)

➖ No Changes

@forgerock/device-client - 10.0 KB
@forgerock/oidc-client - 25.2 KB
@forgerock/sdk-utilities - 11.2 KB
@forgerock/sdk-types - 7.9 KB
@forgerock/protect - 144.6 KB
@forgerock/journey-client - 91.9 KB
@forgerock/storage - 1.5 KB
@forgerock/sdk-oidc - 4.8 KB
@forgerock/sdk-request-middleware - 4.5 KB
@forgerock/sdk-logger - 1.6 KB
@forgerock/iframe-manager - 2.4 KB


14 packages analyzed • Baseline from latest main build

Legend

🆕 New package
🔺 Size increased
🔻 Size decreased
➖ No change

ℹ️ How bundle sizes are calculated
  • Current Size: Total gzipped size of all files in the package's dist directory
  • Baseline: Comparison against the latest build from the main branch
  • Files included: All build outputs except source maps and TypeScript build cache
  • Exclusions: .map, .tsbuildinfo, and .d.ts.map files

🔄 Updated automatically on each push to this PR

@ancheetah ancheetah force-pushed the SDKS-4670-phone-ext branch from 866974e to 9aa183c Compare April 17, 2026 16:28
@ancheetah ancheetah requested review from cerebrl and ryanbas21 April 17, 2026 16:29
Copy link
Copy Markdown
Collaborator

@ryanbas21 ryanbas21 left a comment

Choose a reason for hiding this comment

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

Leaving some comments for discussion. I think we can make this non-breaking

Comment thread packages/davinci-client/src/lib/collector.types.ts
Comment thread packages/davinci-client/src/lib/collector.types.ts Outdated
key: field.key,
label: field.label,
type: field.type,
...(options && { options: options || [] }),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This fallback is no longer really necessary since options always has the property of showExtension?

I think this may be a time for us to pause and re-evaluate this structure of making collectors. This function's becoming overloaded with logic and I think it's only going to be harder to manage what is happening here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is a bit messy because options can be an array of device options or a phone options object (showExtension). I would change this to options ?? null

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.

Since options is required and it's either an [] or a phone extension object, we don't even need null, we can just do options,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's chat on Slack about the use of this options object for extensionLabel. I think it's actually the wrong place to for this property, and is possibly confusing us.

Comment thread packages/davinci-client/src/lib/collector.types.ts
required: boolean;
defaultCountryCode: string | null;
validatePhoneNumber: boolean;
showExtension: boolean;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this always going to be there or is it possible this can be optional?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I have no clue! It seemed to still show up when I toggled it off.

Comment thread packages/davinci-client/src/lib/collector.utils.ts Outdated
Copy link
Copy Markdown
Contributor

@vatsalparikh vatsalparikh left a comment

Choose a reason for hiding this comment

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

Added a few comments.

Ryan already mentioned about separating device authentication collector type from phone number collector type

key: field.key,
label: field.label,
type: field.type,
...(options && { options: options || [] }),
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.

Since options is required and it's either an [] or a phone extension object, we don't even need null, we can just do options,

Comment thread e2e/davinci-app/components/object-value.ts Outdated
@@ -0,0 +1,7 @@
---
'@forgerock/davinci-client': minor
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.

Should we mark this as major if it is a breaking change?

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@e2e/davinci-app/components/object-value.ts`:
- Around line 160-177: The change blocks clearing extension values by returning
early when extensionValue is empty; update the handler for extensionInput.change
(the event listener using extensionInput and phoneInput) to allow empty values
so clearing updates state: remove the early return and always construct a
PhoneNumberExtensionInputValue (use extension: extensionValue || '' and
countryCode: collector.output.value?.countryCode || '') and call
phoneNumberExtensionUpdater(phoneNumberExtensionInputValue) so an empty
extension clears the stored value.

In `@e2e/davinci-suites/src/form-fields.test.ts`:
- Around line 46-49: The test accesses parsedData.parameters.data without
guarding for missing POST body; update the extraction of data (variables
postData/parsedData/data) to safely handle absent or malformed bodies by
checking postData and parsedData.parameters exist before accessing .data (e.g.,
use optional chaining or provide default objects), and ensure data is assigned a
safe default when missing so no TypeError is thrown during the test.

In `@packages/davinci-client/src/lib/collector.types.ts`:
- Around line 402-407: The input.validation type on
PhoneNumberExtensionCollector is too narrow; update the type declaration for
input.validation in the PhoneNumberExtensionCollector (or the related input
interface) to include ValidationPhoneNumber alongside ValidationRequired so that
returnObjectCollector can push validatePhoneNumber rules for PHONE_NUMBER fields
(including extension-enabled ones). Locate the input shape referenced as input:
{ key: string; value: PhoneNumberExtensionInputValue; type: string; validation:
ValidationRequired[] | null; } and change the validation union to accept
ValidationPhoneNumber[] (or a union type like (ValidationRequired |
ValidationPhoneNumber)[] | null) so validatePhoneNumber and other phone-specific
validators are allowed. Ensure references to returnObjectCollector and
validatePhoneNumber remain type-safe after the change.

In `@packages/davinci-client/src/lib/node.reducer.ts`:
- Around line 326-333: The null case isn't guarded before doing property checks
on action.payload.value in the extension update path; update the validation in
the reducer so you first confirm action.payload.value is a non-null object
(e.g., check value !== null && typeof value === 'object' or use a truthy object
check) before running the 'phoneNumber' / 'countryCode' / 'extension' in checks
so null payloads throw the same predictable Error('Value argument must be an
object') instead of causing a runtime crash.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6d44dea6-6496-49d2-8bd6-4e68463a3807

📥 Commits

Reviewing files that changed from the base of the PR and between 866974e and 1529c56.

📒 Files selected for processing (14)
  • .changeset/long-singers-do.md
  • e2e/davinci-app/components/object-value.ts
  • e2e/davinci-app/main.ts
  • e2e/davinci-suites/src/form-fields.test.ts
  • packages/davinci-client/src/lib/client.store.ts
  • packages/davinci-client/src/lib/collector.types.test-d.ts
  • packages/davinci-client/src/lib/collector.types.ts
  • packages/davinci-client/src/lib/collector.utils.test.ts
  • packages/davinci-client/src/lib/collector.utils.ts
  • packages/davinci-client/src/lib/davinci.types.ts
  • packages/davinci-client/src/lib/node.reducer.test.ts
  • packages/davinci-client/src/lib/node.reducer.ts
  • packages/davinci-client/src/lib/node.types.test-d.ts
  • packages/davinci-client/src/lib/node.types.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/davinci-client/src/lib/node.types.test-d.ts
  • packages/davinci-client/src/lib/client.store.ts
  • packages/davinci-client/src/lib/node.types.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • .changeset/long-singers-do.md
  • packages/davinci-client/src/lib/collector.utils.test.ts
  • packages/davinci-client/src/lib/node.reducer.test.ts

Comment thread e2e/davinci-app/components/object-value.ts
Comment on lines +46 to +49
const postData = request.postData();
const parsedData = postData ? JSON.parse(postData) : {};
const data = parsedData.parameters.data;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard parameters.data access when POST body is absent.

At Line 47, parsedData can be {}, but Line 48 still assumes parsedData.parameters.data exists. This can fail with a TypeError and hide the real failure cause.

🔧 Proposed fix
 const postData = request.postData();
-const parsedData = postData ? JSON.parse(postData) : {};
-const data = parsedData.parameters.data;
+expect(postData).toBeTruthy();
+const parsedData = JSON.parse(postData!);
+const data = parsedData?.parameters?.data;
+expect(data).toBeTruthy();
📝 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.

Suggested change
const postData = request.postData();
const parsedData = postData ? JSON.parse(postData) : {};
const data = parsedData.parameters.data;
const postData = request.postData();
expect(postData).toBeTruthy();
const parsedData = JSON.parse(postData!);
const data = parsedData?.parameters?.data;
expect(data).toBeTruthy();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/davinci-suites/src/form-fields.test.ts` around lines 46 - 49, The test
accesses parsedData.parameters.data without guarding for missing POST body;
update the extraction of data (variables postData/parsedData/data) to safely
handle absent or malformed bodies by checking postData and parsedData.parameters
exist before accessing .data (e.g., use optional chaining or provide default
objects), and ensure data is assigned a safe default when missing so no
TypeError is thrown during the test.

Comment thread packages/davinci-client/src/lib/collector.types.ts
Comment thread packages/davinci-client/src/lib/node.reducer.ts
key: field.key,
label: field.label,
type: field.type,
...(options && { options: options || [] }),
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

options can now be an object or array...

Copy link
Copy Markdown
Contributor

@nx-cloud nx-cloud Bot left a 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 has identified a possible root cause for your failed CI:

We determined this timeout failure in @forgerock/api-report:test is unrelated to the PR's changes, as the api-report project is not touched and its tests use entirely synthetic fixtures independent of davinci-client. The CI machine appears to be under resource pressure from the broader build, causing computationally intensive api-extractor tests to exceed their 5000ms timeout threshold.

No code changes were suggested for this issue.

Trigger a rerun:

Rerun CI

Nx Cloud View detailed reasoning on Nx Cloud ↗


🎓 Learn more about Self-Healing CI on nx.dev

Copy link
Copy Markdown
Collaborator

@cerebrl cerebrl left a comment

Choose a reason for hiding this comment

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

I think we are super close with the exception of the use of options. Let's chat in Slack about it.

key: string;
label: string;
type: string;
options: PhoneNumberExtensionOptions;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this really an "option", now that we have a dedicated collector for it. To me, this seems to be an additional label. Is there anything that would prevent us from putting it at the same level as label?

output: {
    key: string;
    label: string;
    type: string;
    extensionLabel: string;
    value: PhoneNumberExtensionOutputValue;
};

I ask because the intention of options was to communicate the "options" from which a user chooses, like the options of a select element, for example.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I actually wanted to put it at the same level as label initially but wasn't sure if this went against any collector patterns. I'm going to go ahead and make this change but we can still discuss in Slack.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Ok it's been updated. You can view the changes in the last commit. Lmk if it looks good and I'll squash and merge.

key: field.key,
label: field.label,
type: field.type,
...(options && { options: options || [] }),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's chat on Slack about the use of this options object for extensionLabel. I think it's actually the wrong place to for this property, and is possibly confusing us.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
e2e/davinci-suites/src/phone-number-field.test.ts (1)

108-108: Use a stricter absence assertion for the extension field.

The test currently uses getByText('Extension').not.toBeVisible(), which relies on broad text matching and a visibility negation. Per Playwright semantics, not.toBeVisible() succeeds when the locator matches zero elements, but toHaveCount(0) is more semantically precise for asserting complete DOM absence. Additionally, getByRole with a specific role is more robust than getByText, which could inadvertently match unrelated "Extension" text elsewhere on the page.

Suggested test adjustment
-    await expect(page.getByText('Extension')).not.toBeVisible(); // Tests standard PhoneNumberCollector
+    await expect(page.getByRole('textbox', { name: 'Extension' })).toHaveCount(0); // Tests standard PhoneNumberCollector
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/davinci-suites/src/phone-number-field.test.ts` at line 108, Replace the
broad visibility negation using page.getByText('Extension') with a stricter
DOM-absence assertion: locate the extension field by role (e.g.,
page.getByRole('textbox', { name: 'Extension' })) and assert
expect(...).toHaveCount(0) instead of expect(...).not.toBeVisible(); update the
test code where expect(page.getByText('Extension')).not.toBeVisible() is used to
use page.getByRole(...) and expect(...).toHaveCount(0) so the assertion verifies
the element is completely absent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@e2e/davinci-suites/src/phone-number-field.test.ts`:
- Line 108: Replace the broad visibility negation using
page.getByText('Extension') with a stricter DOM-absence assertion: locate the
extension field by role (e.g., page.getByRole('textbox', { name: 'Extension' }))
and assert expect(...).toHaveCount(0) instead of expect(...).not.toBeVisible();
update the test code where expect(page.getByText('Extension')).not.toBeVisible()
is used to use page.getByRole(...) and expect(...).toHaveCount(0) so the
assertion verifies the element is completely absent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c8c3d661-e128-4282-94d7-65affe4b7e6a

📥 Commits

Reviewing files that changed from the base of the PR and between 1529c56 and d946302.

📒 Files selected for processing (16)
  • .changeset/long-singers-do.md
  • .gitignore
  • e2e/davinci-app/components/object-value.ts
  • e2e/davinci-app/main.ts
  • e2e/davinci-suites/src/form-fields.test.ts
  • e2e/davinci-suites/src/phone-number-field.test.ts
  • packages/davinci-client/src/lib/client.store.ts
  • packages/davinci-client/src/lib/collector.types.test-d.ts
  • packages/davinci-client/src/lib/collector.types.ts
  • packages/davinci-client/src/lib/collector.utils.test.ts
  • packages/davinci-client/src/lib/collector.utils.ts
  • packages/davinci-client/src/lib/davinci.types.ts
  • packages/davinci-client/src/lib/node.reducer.test.ts
  • packages/davinci-client/src/lib/node.reducer.ts
  • packages/davinci-client/src/lib/node.types.test-d.ts
  • packages/davinci-client/src/lib/node.types.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/davinci-client/src/lib/node.types.test-d.ts
  • .gitignore
  • packages/davinci-client/src/lib/node.types.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • e2e/davinci-app/main.ts
  • .changeset/long-singers-do.md
  • packages/davinci-client/src/lib/client.store.ts
  • e2e/davinci-suites/src/form-fields.test.ts
  • packages/davinci-client/src/lib/node.reducer.ts
  • packages/davinci-client/src/lib/collector.types.test-d.ts
  • packages/davinci-client/src/lib/collector.utils.test.ts
  • packages/davinci-client/src/lib/node.reducer.test.ts
  • e2e/davinci-app/components/object-value.ts

@ancheetah ancheetah force-pushed the SDKS-4670-phone-ext branch from d946302 to 507902e Compare April 30, 2026 15:37
@ancheetah ancheetah requested a review from cerebrl April 30, 2026 15:46
Comment on lines +331 to +334
throw new Error('Index argument must be a string');
}
if (typeof action.payload.value !== 'object') {
throw new Error('Value argument must be an object');
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We need to keep reducers pure.

!('countryCode' in action.payload.value) ||
!('extension' in action.payload.value)
) {
throw new Error(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

throwing in a reducer is impure.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We throw in this reducer for all the other collector categories

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

we shouldn't then, that's bad.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I agree this could make our node updates fragile but since the reducer has historically been written this way I don't think we should fix this right now. We can create a a ticket to fix and test this in the future.

Copy link
Copy Markdown
Contributor

@vatsalparikh vatsalparikh left a comment

Choose a reason for hiding this comment

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

Minor comment on whether it makes sense to combine types, looks good overall! Approving!

phoneNumber?: string;
}

export interface PhoneNumberExtensionInputValue {
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.

What's the need for two different types here when both PhoneNumberExtensionInputValue and PhoneNumberExtensionOutputValue have the same properties? While one type does have properties as optional I don't see the benefit of separating those properties. I looked at how they are used in the code and using separate types makes it harder readability wise. I think we can just use PhoneNumberExtensionOutputValue and call it PhoneNumberExtensionValue, unless we have a pattern of always separating input and output types, regardless of properties.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This makes the types more strict. They represent different things. Output is what we get from DaVinci. These are prefilled values that may or may not be provided by the flow. Input is what we collect from the end user send to DaVinci. These properties are required. I suppose we could do something like PhoneOutput = Partial<PhoneInput> to make it a little cleaner but there's not much of a benefit. And if the requirements change later on it will be harder to modify these types. Lmk what you think.

Comment thread e2e/davinci-app/components/object-value.ts Outdated
Copy link
Copy Markdown
Contributor

@SteinGabriel SteinGabriel left a comment

Choose a reason for hiding this comment

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

Minor finding.

defaultValue = {
countryCode: prefilledCountryCode ? prefilledCountryCode : field.defaultCountryCode || '',
phoneNumber: prefilledPhone || '',
extension: prefilledExtension ?? '',
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.

Nbd, but ?? '' might be redundant here, since prefilledExtension value defaults to empty string on line 674.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

prefillData.extension is an optional property so this can be string | undefined.

@ancheetah ancheetah force-pushed the SDKS-4670-phone-ext branch from 507902e to b271274 Compare May 4, 2026 18:56
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a 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)
e2e/davinci-app/components/object-value.ts (1)

88-104: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

PhoneNumberCollector guard blocks clearing and has a misleading error message.

if (!selectedValue) prevents the updater from being called when the user clears the phone field, leaving stale state — the same problem that was already caught and fixed for the extension input. The error message ('No value found for the selected option') is also a copy-paste from the DeviceAuthenticationCollector branch and is semantically wrong here.

🛠 Proposed fix
     phoneInput.addEventListener('change', (event) => {
       const target = event.target as HTMLInputElement;
       const selectedValue = target.value;

-      if (!selectedValue) {
-        console.error('No value found for the selected option');
-        return;
-      }
-
       const phoneNumberInputValue: PhoneNumberInputValue = {
         phoneNumber: selectedValue,
         countryCode: collector.output.value?.countryCode || '',
       };
       const phoneNumberUpdater = updater as Updater<PhoneNumberCollector>;
       phoneNumberUpdater(phoneNumberInputValue);
     });
🤖 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 `@e2e/davinci-app/components/object-value.ts` around lines 88 - 104, The change
handler for phoneInput (the listener that constructs PhoneNumberInputValue and
calls updater as Updater<PhoneNumberCollector>) currently bails out on falsy
selectedValue and logs a wrong error message; remove that guard so the updater
is always called even when the field is cleared, populate
PhoneNumberInputValue.phoneNumber with the empty string when selectedValue is
empty, and either remove or replace the incorrect log message ('No value found
for the selected option') with a correct one (e.g., 'Phone input cleared') so
stale state is not retained by PhoneNumberCollector and the updater(…) is
invoked on clears.
♻️ Duplicate comments (1)
e2e/davinci-suites/src/form-fields.test.ts (1)

46-48: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

parsedData.parameters.data is still unguarded after the partial fix.

If postData is absent, parsedData defaults to {} and Line 48 immediately throws TypeError: Cannot read properties of undefined (reading 'data'). The guard on postData doesn't protect the downstream access.

🛠 Proposed fix
-  const postData = request.postData();
-  const parsedData = postData ? JSON.parse(postData) : {};
-  const data = parsedData.parameters.data;
+  const postData = request.postData();
+  expect(postData).toBeTruthy();
+  const parsedData = JSON.parse(postData!);
+  const data = parsedData?.parameters?.data;
+  expect(data).toBeTruthy();
🤖 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 `@e2e/davinci-suites/src/form-fields.test.ts` around lines 46 - 48, The code
unguards parsedData.parameters before accessing .data, causing a TypeError when
postData is absent; update the extraction so you safely handle missing
parameters and data (e.g., use optional chaining and a sensible default).
Specifically, change the logic around request.postData(), parsedData and data so
that parsedData is parsed only when present and data is read as
parsedData.parameters?.data (or parsedData?.parameters?.data) with a fallback
(e.g., {} or null) to avoid the runtime exception; target the variables
postData, parsedData and data in the test to apply this safe-access fix.
🤖 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 `@e2e/davinci-app/components/object-value.ts`:
- Line 129: Replace the invalid assignment to the readonly style property by
setting the element's cssText: find the statement assigning to divEl.style (the
line "divEl.style = 'display: flex; gap: 8px;';") and change it to assign the
CSS string to divEl.style.cssText so TypeScript's readonly CSSStyleDeclaration
typing is respected.

---

Outside diff comments:
In `@e2e/davinci-app/components/object-value.ts`:
- Around line 88-104: The change handler for phoneInput (the listener that
constructs PhoneNumberInputValue and calls updater as
Updater<PhoneNumberCollector>) currently bails out on falsy selectedValue and
logs a wrong error message; remove that guard so the updater is always called
even when the field is cleared, populate PhoneNumberInputValue.phoneNumber with
the empty string when selectedValue is empty, and either remove or replace the
incorrect log message ('No value found for the selected option') with a correct
one (e.g., 'Phone input cleared') so stale state is not retained by
PhoneNumberCollector and the updater(…) is invoked on clears.

---

Duplicate comments:
In `@e2e/davinci-suites/src/form-fields.test.ts`:
- Around line 46-48: The code unguards parsedData.parameters before accessing
.data, causing a TypeError when postData is absent; update the extraction so you
safely handle missing parameters and data (e.g., use optional chaining and a
sensible default). Specifically, change the logic around request.postData(),
parsedData and data so that parsedData is parsed only when present and data is
read as parsedData.parameters?.data (or parsedData?.parameters?.data) with a
fallback (e.g., {} or null) to avoid the runtime exception; target the variables
postData, parsedData and data in the test to apply this safe-access fix.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 62800af6-f3d4-4daf-b182-ec8f06107272

📥 Commits

Reviewing files that changed from the base of the PR and between d946302 and b271274.

📒 Files selected for processing (16)
  • .changeset/long-singers-do.md
  • .gitignore
  • e2e/davinci-app/components/object-value.ts
  • e2e/davinci-app/main.ts
  • e2e/davinci-suites/src/form-fields.test.ts
  • e2e/davinci-suites/src/phone-number-field.test.ts
  • packages/davinci-client/src/lib/client.store.ts
  • packages/davinci-client/src/lib/collector.types.test-d.ts
  • packages/davinci-client/src/lib/collector.types.ts
  • packages/davinci-client/src/lib/collector.utils.test.ts
  • packages/davinci-client/src/lib/collector.utils.ts
  • packages/davinci-client/src/lib/davinci.types.ts
  • packages/davinci-client/src/lib/node.reducer.test.ts
  • packages/davinci-client/src/lib/node.reducer.ts
  • packages/davinci-client/src/lib/node.types.test-d.ts
  • packages/davinci-client/src/lib/node.types.ts
✅ Files skipped from review due to trivial changes (6)
  • .changeset/long-singers-do.md
  • .gitignore
  • packages/davinci-client/src/lib/node.types.test-d.ts
  • packages/davinci-client/src/lib/client.store.ts
  • packages/davinci-client/src/lib/node.reducer.ts
  • packages/davinci-client/src/lib/node.reducer.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • e2e/davinci-app/main.ts
  • packages/davinci-client/src/lib/collector.types.test-d.ts
  • packages/davinci-client/src/lib/davinci.types.ts
  • e2e/davinci-suites/src/phone-number-field.test.ts
  • packages/davinci-client/src/lib/collector.utils.ts
  • packages/davinci-client/src/lib/collector.utils.test.ts

extensionInput.setAttribute('placeholder', 'Enter extension');

const divEl = document.createElement('div');
divEl.style = 'display: flex; gap: 8px;';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

TypeScript lib.dom.d.ts ElementCSSInlineStyle style readonly CSSStyleDeclaration 2025

💡 Result:

In TypeScript's lib.dom.d.ts (as of 2024/2025 DOM updates), the ElementCSSInlineStyle interface declares the style property as readonly CSSStyleDeclaration. This means you cannot reassign the style property itself (e.g., element.style = someOtherDeclaration), but you can mutate the returned CSSStyleDeclaration object by setting individual properties (e.g., element.style.color = 'red'), using cssText (e.g., element.style.cssText = 'color: red'), or calling methods like setProperty. This design matches the DOM spec and browser behavior: the style property returns a live CSSStyleDeclaration object tied to the element's inline styles, which is mutable despite the readonly getter. Direct string assignment like element.style = 'color: red' works in browsers (forwarded to cssText), but TypeScript types it as readonly to prevent replacing the object, avoiding type errors for incompatible assignments. A long-open GitHub issue (#38838) requests allowing string setters per spec, but it remains open in the Backlog as of 2025. No changes in 2025 DOM updates (e.g., PR #60987, #61647) alter this; recent updates add CSS properties and accessors but keep style readonly. For dynamic keys, cast or use setProperty. Example: const el = document.createElement('div') as HTMLElement; el.style.color = 'red'; // OK el.style.cssText = 'color: red; font-size: 16px'; // OK el.style.setProperty('background', 'blue'); // OK el.style = /* CSSStyleDeclaration */; // Error: readonly

Citations:


🏁 Script executed:

# Check if the file exists and read around line 129
file_path="e2e/davinci-app/components/object-value.ts"
if [ -f "$file_path" ]; then
  echo "=== File exists ==="
  # Show lines around 129 with context
  sed -n '120,140p' "$file_path" | cat -n
else
  echo "File not found: $file_path"
  # Try to find similar files
  find . -name "object-value.ts" -type f 2>/dev/null
fi

Repository: ForgeRock/ping-javascript-sdk

Length of output: 1080


🏁 Script executed:

# Check for tsconfig files and TypeScript configuration
echo "=== Looking for tsconfig files ==="
find . -name "tsconfig*.json" -type f 2>/dev/null | head -20

echo ""
echo "=== Checking project structure around the file ==="
ls -la e2e/davinci-app/components/ 2>/dev/null | head -20

Repository: ForgeRock/ping-javascript-sdk

Length of output: 1851


🏁 Script executed:

# Check the tsconfig files for davinci-app
echo "=== e2e/davinci-app/tsconfig.json ==="
cat e2e/davinci-app/tsconfig.json

echo ""
echo "=== e2e/davinci-app/tsconfig.app.json ==="
cat e2e/davinci-app/tsconfig.app.json

Repository: ForgeRock/ping-javascript-sdk

Length of output: 1186


divEl.style = '...' is a TypeScript compile error (Cannot assign to 'style' because it is a read-only property).

The style property is typed as readonly CSSStyleDeclaration in TypeScript's DOM type definitions. Direct string assignment is not permitted, even though browsers forward it to cssText. Use divEl.style.cssText instead.

🛠 Proposed fix
-    divEl.style = 'display: flex; gap: 8px;';
+    divEl.style.cssText = 'display: flex; gap: 8px;';
📝 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.

Suggested change
divEl.style = 'display: flex; gap: 8px;';
divEl.style.cssText = 'display: flex; gap: 8px;';
🤖 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 `@e2e/davinci-app/components/object-value.ts` at line 129, Replace the invalid
assignment to the readonly style property by setting the element's cssText: find
the statement assigning to divEl.style (the line "divEl.style = 'display: flex;
gap: 8px;';") and change it to assign the CSS string to divEl.style.cssText so
TypeScript's readonly CSSStyleDeclaration typing is respected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

6 participants