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.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 17, 2026

🦋 Changeset detected

Latest commit: 507902e

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

Warning

Rate limit exceeded

@ancheetah has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 22 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d40f2ac5-5ae4-46e4-8dcd-c11c6a2e29cb

📥 Commits

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

📒 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
📝 Walkthrough

Walkthrough

Adds a PhoneNumberExtensionCollector and related types; updates collector factories, reducer, client update typing, UI rendering, and tests so phone fields can include an extension input and propagate extension values through update/submit flows.

Changes

Cohort / File(s) Summary
Changeset Metadata
/.changeset/long-singers-do.md
New changeset declaring a minor release for @forgerock/davinci-client.
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/OutputValue; update unions and include extension variant; minor reordering of PhoneNumberField property.
Collector utils & factory
packages/davinci-client/src/lib/collector.utils.ts, packages/davinci-client/src/lib/collector.utils.test.ts
returnObjectCollector/returnObjectValueCollector handle showExtension: true, include extension in defaultValue/prefill and add extensionLabel to output; tests added for extension paths.
Reducer & store types/logic
packages/davinci-client/src/lib/node.reducer.ts, packages/davinci-client/src/lib/client.store.ts, packages/davinci-client/src/lib/node.types.test-d.ts, packages/davinci-client/src/lib/node.types.ts
Reducer and action typing extended to accept PhoneNumberExtensionInputValue; initialization and update branches added for extension collectors; client.update typing expanded to accept extension input value; type-tests updated.
Type-level tests
packages/davinci-client/src/lib/collector.types.test-d.ts
Added compile-time assertions mapping 'PhoneNumberExtensionCollector' to the new collector type and structural/value assertions.
Node reducer tests
packages/davinci-client/src/lib/node.reducer.test.ts
Updated tests for phone collectors to assert extension default/prefill and update behavior; new suite for PhoneNumberExtensionCollector.
E2E app & component
e2e/davinci-app/components/object-value.ts, e2e/davinci-app/main.ts
objectValueComponent and render logic updated to recognize PhoneNumberExtensionCollector; component renders phone+extension inputs and dispatches typed updater payload including extension.
E2E tests
e2e/davinci-suites/src/form-fields.test.ts, e2e/davinci-suites/src/phone-number-field.test.ts
E2E tests updated to fill and assert extension field, use new selectors, and harden request-body parsing; phone-entry label adjusted and extension visibility asserted.
Misc & infra
.gitignore
Ignored new local config file .polaris-setup-progress.json and fixed newline for existing ignore entry.

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

  • vatsalparikh
  • ryanbas21
  • cerebrl

Poem

🐰
I hopped through types and fields with cheer,
Added 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 accurately summarizes the main change: adding support for phone number extensions in the PhoneNumberCollector, which is the primary objective reflected across all modified files.
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.
Description check ✅ Passed The PR description comprehensively addresses the template requirements and provides detailed context for the changes, including JIRA ticket, description, types, functions, reducer updates, breaking changes, and test coverage.

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

✨ Finishing Touches
🧪 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 38 minutes and 22 seconds.

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 507902e

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

☁️ Nx Cloud last updated this comment at 2026-04-30 15:45:22 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.64%. Comparing base (5d6747a) to head (507902e).
⚠️ Report is 87 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.64%) 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.64%   -53.27%     
===========================================
  Files          53      154      +101     
  Lines        2021    24199    +22178     
  Branches      377     1160      +783     
===========================================
+ Hits         1433     4269     +2836     
- Misses        588    19930    +19342     
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 95 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: 507902e

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 17, 2026

Deployed 3f8eb6c to https://ForgeRock.github.io/ping-javascript-sdk/pr-573/3f8eb6c8a64611a2fb53b12e9ca2e48de795a9d4 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 (-90.3 KB, -100.0%)

📊 Minor Changes

📈 @forgerock/davinci-client - 48.7 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 - 90.3 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 on lines +160 to +177
extensionInput.addEventListener('change', (event) => {
const target = event.target as HTMLInputElement;
const extensionValue = target.value;
const phoneValue = phoneInput.value;

if (!extensionValue) {
console.error('No value found for extension');
return;
}

const phoneNumberExtensionInputValue: PhoneNumberExtensionInputValue = {
phoneNumber: phoneValue,
countryCode: collector.output.value?.countryCode || '',
extension: extensionValue,
};

phoneNumberExtensionUpdater(phoneNumberExtensionInputValue);
});
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 | 🟠 Major

Allow clearing extension values instead of blocking empty updates.

At Line 165, returning early on empty extension prevents users from clearing a previously entered extension, which can leave stale data in collector state.

🔧 Proposed fix
     extensionInput.addEventListener('change', (event) => {
@@
-      if (!extensionValue) {
-        console.error('No value found for extension');
-        return;
-      }
-
       const phoneNumberExtensionInputValue: PhoneNumberExtensionInputValue = {
         phoneNumber: phoneValue,
         countryCode: collector.output.value?.countryCode || '',
         extension: extensionValue,
       };
📝 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
extensionInput.addEventListener('change', (event) => {
const target = event.target as HTMLInputElement;
const extensionValue = target.value;
const phoneValue = phoneInput.value;
if (!extensionValue) {
console.error('No value found for extension');
return;
}
const phoneNumberExtensionInputValue: PhoneNumberExtensionInputValue = {
phoneNumber: phoneValue,
countryCode: collector.output.value?.countryCode || '',
extension: extensionValue,
};
phoneNumberExtensionUpdater(phoneNumberExtensionInputValue);
});
extensionInput.addEventListener('change', (event) => {
const target = event.target as HTMLInputElement;
const extensionValue = target.value;
const phoneValue = phoneInput.value;
const phoneNumberExtensionInputValue: PhoneNumberExtensionInputValue = {
phoneNumber: phoneValue,
countryCode: collector.output.value?.countryCode || '',
extension: extensionValue,
};
phoneNumberExtensionUpdater(phoneNumberExtensionInputValue);
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/davinci-app/components/object-value.ts` around lines 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.

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

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.

5 participants