Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .changeset/little-lamps-float.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
'@forgerock/davinci-client': patch
---
Comment on lines +1 to +3
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 | ⚡ Quick win

Use a breaking-change bump for this release.

Line 2 sets this as a patch, but this PR removes/renames a public exported type (CollectorInputTypesCollectorValueTypes). That is a compile-time breaking API change for TypeScript consumers.

Suggested changeset fix
 ---
-'`@forgerock/davinci-client`': patch
+'`@forgerock/davinci-client`': major
 ---
📝 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
---
'@forgerock/davinci-client': patch
---
---
'`@forgerock/davinci-client`': major
---
🤖 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 @.changeset/little-lamps-float.md around lines 1 - 3, The changeset currently
marks '`@forgerock/davinci-client`' as 'patch' but you renamed a public TypeScript
export from CollectorInputTypes to CollectorValueTypes which is a breaking API
change; update the changeset entry to use a breaking bump (change the release
type from 'patch' to 'major' for '`@forgerock/davinci-client`') and include a
short note in the changeset text explaining the exported type rename (mention
CollectorInputTypes → CollectorValueTypes) so release tooling and consumers are
aware it's a breaking change.


Fixed collector value types and simplified node reducer imports

### `client.types.ts`

- Renamed `CollectorInputTypes` → `CollectorValueTypes` and added `DeviceValue` to the union.
- Rewrote `CollectorValueType<T>` conditional type: grouped branches by return type (string, boolean, string[], specialized, category catch-alls), fixed `DeviceAuthenticationCollector` to return `DeviceValue` instead of `string`, added `never` for `ActionCollector` and `NoValueCollector`, and added a `SingleValueAutoCollector` catch-all.

### `node.reducer.ts` / `client.store.ts`

- Replaced ~30 individual collector type imports with `Collectors` (from `node.types`) and `CollectorValueTypes` (from `client.types`), collapsing verbose inline union annotations to single-type references.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,5 @@ GEMINI.md

# Polaris
.polaris-setup-progress.json

.polaris/
36 changes: 23 additions & 13 deletions packages/davinci-client/api-report/davinci-client.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,6 @@ export interface CollectorErrors {
target: string;
}

// @public (undocumented)
export type CollectorInputTypes = string | string[] | boolean | PhoneNumberInputValue | PhoneNumberExtensionInputValue | FidoRegistrationInputValue | FidoAuthenticationInputValue;
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.

hmm, this would be a breaking change, no?


// @public
export interface CollectorRichContent {
// (undocumented)
Expand All @@ -194,8 +191,16 @@ export type Collectors = FlowCollector | PasswordCollector | ValidatedPasswordCo
// @public
export type CollectorValueType<T> = T extends {
type: 'PasswordCollector';
} ? string : T extends {
} | {
type: 'ValidatedPasswordCollector';
} | {
type: 'SingleSelectCollector';
} | {
type: 'DeviceRegistrationCollector';
} | {
type: 'ProtectCollector';
} | {
type: 'PollingCollector';
} ? string : T extends {
type: 'TextCollector';
category: 'SingleValueCollector';
Expand All @@ -205,14 +210,10 @@ export type CollectorValueType<T> = T extends {
} ? string : T extends {
type: 'ValidatedBooleanCollector';
} ? boolean : T extends {
type: 'SingleSelectCollector';
} ? string : T extends {
type: 'MultiSelectCollector';
} ? string[] : T extends {
type: 'DeviceRegistrationCollector';
} ? string : T extends {
type: 'DeviceAuthenticationCollector';
} ? string : T extends {
} ? DeviceValue : T extends {
type: 'PhoneNumberCollector';
} ? PhoneNumberInputValue : T extends {
type: 'PhoneNumberExtensionCollector';
Expand All @@ -224,9 +225,18 @@ export type CollectorValueType<T> = T extends {
category: 'SingleValueCollector';
} ? string : T extends {
category: 'ValidatedSingleValueCollector';
} ? string : T extends {
category: 'SingleValueAutoCollector';
} ? string : T extends {
category: 'MultiValueCollector';
} ? string[] : CollectorInputTypes;
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.

also seems to have been removed here?

} ? string[] : T extends {
category: 'ActionCollector';
} ? never : T extends {
category: 'NoValueCollector';
} ? never : CollectorValueTypes;

// @public (undocumented)
export type CollectorValueTypes = string | string[] | boolean | DeviceValue | PhoneNumberInputValue | PhoneNumberExtensionInputValue | FidoRegistrationInputValue | FidoAuthenticationInputValue;

// @public (undocumented)
export type ComplexValueFields = DeviceAuthenticationField | DeviceRegistrationField | PhoneNumberField | PhoneNumberExtensionField | FidoRegistrationField | FidoAuthenticationField | PollingField;
Expand Down Expand Up @@ -1187,8 +1197,8 @@ value: Record<string, unknown>;
}, string>;

// @public
export const nodeCollectorReducer: Reducer<(ValidatedTextCollector | ValidatedBooleanCollector | ValidatedPasswordCollector | DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | PhoneNumberExtensionCollector | ProtectCollector | FidoRegistrationCollector | FidoAuthenticationCollector | PollingCollector | TextCollector | PasswordCollector | SingleSelectCollector | UnknownCollector | IdpCollector | FlowCollector | SubmitCollector | ReadOnlyCollector | RichTextCollector | QrCodeCollector | AgreementCollector | ActionCollector<"ActionCollector"> | SingleValueCollector<"SingleValueCollector"> | MultiSelectCollector)[]> & {
getInitialState: () => (ValidatedTextCollector | ValidatedBooleanCollector | ValidatedPasswordCollector | DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | PhoneNumberExtensionCollector | ProtectCollector | FidoRegistrationCollector | FidoAuthenticationCollector | PollingCollector | TextCollector | PasswordCollector | SingleSelectCollector | UnknownCollector | IdpCollector | FlowCollector | SubmitCollector | ReadOnlyCollector | RichTextCollector | QrCodeCollector | AgreementCollector | ActionCollector<"ActionCollector"> | SingleValueCollector<"SingleValueCollector"> | MultiSelectCollector)[];
export const nodeCollectorReducer: Reducer<Collectors[]> & {
getInitialState: () => Collectors[];
};

// @public (undocumented)
Expand Down Expand Up @@ -1918,7 +1928,7 @@ export type UnknownField = Record<string, unknown>;
// @public (undocumented)
export const updateCollectorValues: ActionCreatorWithPayload< {
id: string;
value: string | string[] | boolean | PhoneNumberInputValue | PhoneNumberExtensionInputValue | FidoRegistrationInputValue | FidoAuthenticationInputValue;
value: CollectorValueTypes;
index?: number;
}, string>;

Expand Down
36 changes: 23 additions & 13 deletions packages/davinci-client/api-report/davinci-client.types.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,6 @@ export interface CollectorErrors {
target: string;
}

// @public (undocumented)
export type CollectorInputTypes = string | string[] | boolean | PhoneNumberInputValue | PhoneNumberExtensionInputValue | FidoRegistrationInputValue | FidoAuthenticationInputValue;
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.

also removed here?


// @public
export interface CollectorRichContent {
// (undocumented)
Expand All @@ -194,8 +191,16 @@ export type Collectors = FlowCollector | PasswordCollector | ValidatedPasswordCo
// @public
export type CollectorValueType<T> = T extends {
type: 'PasswordCollector';
} ? string : T extends {
} | {
type: 'ValidatedPasswordCollector';
} | {
type: 'SingleSelectCollector';
} | {
type: 'DeviceRegistrationCollector';
} | {
type: 'ProtectCollector';
} | {
type: 'PollingCollector';
} ? string : T extends {
type: 'TextCollector';
category: 'SingleValueCollector';
Expand All @@ -205,14 +210,10 @@ export type CollectorValueType<T> = T extends {
} ? string : T extends {
type: 'ValidatedBooleanCollector';
} ? boolean : T extends {
type: 'SingleSelectCollector';
} ? string : T extends {
type: 'MultiSelectCollector';
} ? string[] : T extends {
type: 'DeviceRegistrationCollector';
} ? string : T extends {
type: 'DeviceAuthenticationCollector';
} ? string : T extends {
} ? DeviceValue : T extends {
type: 'PhoneNumberCollector';
} ? PhoneNumberInputValue : T extends {
type: 'PhoneNumberExtensionCollector';
Expand All @@ -224,9 +225,18 @@ export type CollectorValueType<T> = T extends {
category: 'SingleValueCollector';
} ? string : T extends {
category: 'ValidatedSingleValueCollector';
} ? string : T extends {
category: 'SingleValueAutoCollector';
} ? string : T extends {
category: 'MultiValueCollector';
} ? string[] : CollectorInputTypes;
} ? string[] : T extends {
category: 'ActionCollector';
} ? never : T extends {
category: 'NoValueCollector';
} ? never : CollectorValueTypes;

// @public (undocumented)
export type CollectorValueTypes = string | string[] | boolean | DeviceValue | PhoneNumberInputValue | PhoneNumberExtensionInputValue | FidoRegistrationInputValue | FidoAuthenticationInputValue;

// @public (undocumented)
export type ComplexValueFields = DeviceAuthenticationField | DeviceRegistrationField | PhoneNumberField | PhoneNumberExtensionField | FidoRegistrationField | FidoAuthenticationField | PollingField;
Expand Down Expand Up @@ -1184,8 +1194,8 @@ value: Record<string, unknown>;
}, string>;

// @public
export const nodeCollectorReducer: Reducer<(ValidatedTextCollector | ValidatedBooleanCollector | ValidatedPasswordCollector | DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | PhoneNumberExtensionCollector | ProtectCollector | FidoRegistrationCollector | FidoAuthenticationCollector | PollingCollector | TextCollector | PasswordCollector | SingleSelectCollector | UnknownCollector | IdpCollector | FlowCollector | SubmitCollector | ReadOnlyCollector | RichTextCollector | QrCodeCollector | AgreementCollector | ActionCollector<"ActionCollector"> | SingleValueCollector<"SingleValueCollector"> | MultiSelectCollector)[]> & {
getInitialState: () => (ValidatedTextCollector | ValidatedBooleanCollector | ValidatedPasswordCollector | DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | PhoneNumberExtensionCollector | ProtectCollector | FidoRegistrationCollector | FidoAuthenticationCollector | PollingCollector | TextCollector | PasswordCollector | SingleSelectCollector | UnknownCollector | IdpCollector | FlowCollector | SubmitCollector | ReadOnlyCollector | RichTextCollector | QrCodeCollector | AgreementCollector | ActionCollector<"ActionCollector"> | SingleValueCollector<"SingleValueCollector"> | MultiSelectCollector)[];
export const nodeCollectorReducer: Reducer<Collectors[]> & {
getInitialState: () => Collectors[];
};

// @public (undocumented)
Expand Down Expand Up @@ -1915,7 +1925,7 @@ export type UnknownField = Record<string, unknown>;
// @public (undocumented)
export const updateCollectorValues: ActionCreatorWithPayload< {
id: string;
value: string | string[] | boolean | PhoneNumberInputValue | PhoneNumberExtensionInputValue | FidoRegistrationInputValue | FidoAuthenticationInputValue;
value: CollectorValueTypes;
index?: number;
}, string>;

Expand Down
17 changes: 2 additions & 15 deletions packages/davinci-client/src/lib/client.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,9 @@ import type {
SingleValueCollectors,
MultiSelectCollector,
ObjectValueCollectors,
PhoneNumberInputValue,
AutoCollectors,
PollingCollector,
MultiValueCollectors,
FidoRegistrationInputValue,
FidoAuthenticationInputValue,
PhoneNumberExtensionInputValue,
} from './collector.types.js';
import type {
InitFlow,
Expand All @@ -55,6 +51,7 @@ import type {
Updater,
Validator,
Poller,
CollectorValueTypes,
} from './client.types.js';
import { returnValidator } from './collector.utils.js';
import { returnPasswordPolicyValidator } from './password-policy.rules.js';
Expand Down Expand Up @@ -335,17 +332,7 @@ export async function davinci<ActionType extends ActionTypes = ActionTypes>({
);
}

return function (
value:
| string
| string[]
| boolean
| PhoneNumberInputValue
| PhoneNumberExtensionInputValue
| FidoRegistrationInputValue
| FidoAuthenticationInputValue,
index?: number,
) {
return function (value: CollectorValueTypes, index?: number) {
try {
store.dispatch(nodeSlice.actions.update({ id, value, index }));
return null;
Expand Down
6 changes: 3 additions & 3 deletions packages/davinci-client/src/lib/client.types.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { describe, expectTypeOf, it } from 'vitest';
import type { GenericError } from '@forgerock/sdk-types';

import type {
CollectorInputTypes,
CollectorValueTypes,
InitFlow,
InternalErrorResponse,
Updater,
Expand Down Expand Up @@ -173,13 +173,13 @@ describe('Client Types', () => {

describe('Updater', () => {
it('should accept string, boolean, or object value and optional index', () => {
const updater: Updater = (value: CollectorInputTypes, index?: number) => {
const updater: Updater = (value: CollectorValueTypes, index?: number) => {
return {
error: { message: 'Invalid value', code: 'INVALID', type: 'state_error' },
type: 'internal_error',
};
};
expectTypeOf(updater).parameter(0).toEqualTypeOf<CollectorInputTypes>();
expectTypeOf(updater).parameter(0).toEqualTypeOf<CollectorValueTypes>();
expectTypeOf(updater).parameter(1).toBeNullable();
});

Expand Down
72 changes: 44 additions & 28 deletions packages/davinci-client/src/lib/client.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
FidoAuthenticationInputValue,
PhoneNumberInputValue,
PhoneNumberExtensionInputValue,
DeviceValue,
AutoCollectors,
MultiValueCollectors,
ObjectValueCollectors,
Expand All @@ -29,14 +30,16 @@ export interface InternalErrorResponse {

export type InitFlow = () => Promise<FlowNode | InternalErrorResponse>;

export type CollectorInputTypes =
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 could also be breaking?

export type CollectorValueTypes =
| string
| string[]
| boolean
| DeviceValue
| PhoneNumberInputValue
| PhoneNumberExtensionInputValue
| FidoRegistrationInputValue
| FidoAuthenticationInputValue;

/**
* Maps collector types to the specific value type they accept.
* This enables type narrowing when using the update method with specific collector types.
Expand All @@ -49,39 +52,52 @@ export type CollectorInputTypes =
* }
* ```
*/
export type CollectorValueType<T> = T extends { type: 'PasswordCollector' }
? string
: T extends { type: 'ValidatedPasswordCollector' }
export type CollectorValueType<T> =
// string input types
T extends
| { type: 'PasswordCollector' }
| { type: 'ValidatedPasswordCollector' }
| { type: 'SingleSelectCollector' }
| { type: 'DeviceRegistrationCollector' }
| { type: 'ProtectCollector' }
| { type: 'PollingCollector' }
? string
: T extends { type: 'TextCollector'; category: 'SingleValueCollector' }
: // TextCollector branches must remain compound — category is the only discriminant
T extends { type: 'TextCollector'; category: 'SingleValueCollector' }
? string
: T extends { type: 'TextCollector'; category: 'ValidatedSingleValueCollector' }
? string
: T extends { type: 'ValidatedBooleanCollector' }
: // boolean input types
T extends { type: 'ValidatedBooleanCollector' }
? boolean
: T extends { type: 'SingleSelectCollector' }
? string
: T extends { type: 'MultiSelectCollector' }
? string[]
: T extends { type: 'DeviceRegistrationCollector' }
? string
: T extends { type: 'DeviceAuthenticationCollector' }
? string
: T extends { type: 'PhoneNumberCollector' }
? PhoneNumberInputValue
: T extends { type: 'PhoneNumberExtensionCollector' }
? PhoneNumberExtensionInputValue
: T extends { type: 'FidoRegistrationCollector' }
? FidoRegistrationInputValue
: T extends { type: 'FidoAuthenticationCollector' }
? FidoAuthenticationInputValue
: T extends { category: 'SingleValueCollector' }
: // string[] input types
T extends { type: 'MultiSelectCollector' }
? string[]
: // specialized input types
T extends { type: 'DeviceAuthenticationCollector' }
? DeviceValue
: T extends { type: 'PhoneNumberCollector' }
? PhoneNumberInputValue
: T extends { type: 'PhoneNumberExtensionCollector' }
? PhoneNumberExtensionInputValue
: T extends { type: 'FidoRegistrationCollector' }
? FidoRegistrationInputValue
: T extends { type: 'FidoAuthenticationCollector' }
? FidoAuthenticationInputValue
: // category catch-alls
T extends { category: 'SingleValueCollector' }
? string
: T extends { category: 'ValidatedSingleValueCollector' }
? string
: T extends { category: 'SingleValueAutoCollector' }
? string
: T extends { category: 'ValidatedSingleValueCollector' }
? string
: T extends { category: 'MultiValueCollector' }
? string[]
: CollectorInputTypes;
: T extends { category: 'MultiValueCollector' }
? string[]
: T extends { category: 'ActionCollector' }
? never
: T extends { category: 'NoValueCollector' }
? never
: CollectorValueTypes;

/**
* A function type that updates a collector's value. Accepts values appropriate for the collector type.
Expand Down
Loading
Loading