diff --git a/.changeset/brave-pears-help.md b/.changeset/brave-pears-help.md
new file mode 100644
index 00000000..da1ade1c
--- /dev/null
+++ b/.changeset/brave-pears-help.md
@@ -0,0 +1,5 @@
+---
+'@forgerock/davinci-client': minor
+---
+
+adding support for fields in DROPDOWN, CHECKBOX, COMBOBOX, RADIO, FLOW_LINK.
diff --git a/.changeset/config.json b/.changeset/config.json
index 8acb5a94..20254db4 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -7,13 +7,14 @@
     }
   ],
   "commit": false,
-  "fixed": [],
+  "fixed": [["@forgerock/*"]],
+  "privatePackages": false,
   "linked": [],
   "access": "public",
   "baseBranch": "main",
   "updateInternalDependencies": "patch",
   "ignore": [
-    "@forgerock/*",
+    "@forgerock/device-client",
     "@forgerock/davinci-app",
     "@forgerock/davinci-suites",
     "@forgerock/mock-api-v2"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ae0cab0e..1605cad9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -34,7 +34,7 @@ jobs:
       - run: git branch --track main origin/main
 
       - run: pnpm exec nx-cloud record -- nx format:check
-      - run: pnpm exec nx affected -t build lint test docs e2e-ci
+      - run: pnpm exec nx affected -t typecheck build lint test docs e2e-ci
 
       - uses: codecov/codecov-action@v5
         with:
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index d2b465f2..a1dde2d4 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -76,7 +76,7 @@ jobs:
           NPM_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
 
       - name: Send GitHub Action data to a Slack workflow
-        if: steps.changesets.outputs.published === 'true'
+        if: steps.changesets.outputs.published == 'true'
         uses: slackapi/slack-github-action@v2.0.0
         with:
           payload-delimiter: '_'
diff --git a/contributing_docs/testing.md b/contributing_docs/testing.md
new file mode 100644
index 00000000..ad82f892
--- /dev/null
+++ b/contributing_docs/testing.md
@@ -0,0 +1,17 @@
+# Testing
+
+## Testing Types
+
+You can test types using vitest. It's important to note that testing types does not actually _run_ a test file.
+
+When you test types, these are statically analyzed by the compiler.
+
+Vitest defaults state that all files matching `*.test-d.ts` are considered type-tests
+
+From the vitest docs:
+
+```
+Under the hood Vitest calls tsc or vue-tsc, depending on your config, and parses results. Vitest will also print out type errors in your source code, if it finds any. You can disable it with typecheck.ignoreSourceErrors config option.
+
+Keep in mind that Vitest doesn't run these files, they are only statically analyzed by the compiler. Meaning, that if you use a dynamic name or test.each or test.for, the test name will not be evaluated - it will be displayed as is.
+```
diff --git a/e2e/davinci-app/components/flow-link.ts b/e2e/davinci-app/components/flow-link.ts
index 757e3012..73d82fdc 100644
--- a/e2e/davinci-app/components/flow-link.ts
+++ b/e2e/davinci-app/components/flow-link.ts
@@ -1,4 +1,4 @@
-import { FlowCollector, InitFlow } from '@forgerock/davinci-client/types';
+import type { FlowCollector, InitFlow } from '@forgerock/davinci-client/types';
 
 export default function flowLinkComponent(
   formEl: HTMLFormElement,
diff --git a/e2e/davinci-app/components/password.ts b/e2e/davinci-app/components/password.ts
index 9e9fec5c..ba601312 100644
--- a/e2e/davinci-app/components/password.ts
+++ b/e2e/davinci-app/components/password.ts
@@ -1,4 +1,4 @@
-import { PasswordCollector, Updater } from '@forgerock/davinci-client/types';
+import type { PasswordCollector, Updater } from '@forgerock/davinci-client/types';
 
 export default function passwordComponent(
   formEl: HTMLFormElement,
diff --git a/e2e/davinci-app/components/protect.ts b/e2e/davinci-app/components/protect.ts
index f88c6b93..c7b398d7 100644
--- a/e2e/davinci-app/components/protect.ts
+++ b/e2e/davinci-app/components/protect.ts
@@ -1,4 +1,4 @@
-import { TextCollector, Updater } from '@forgerock/davinci-client/types';
+import type { TextCollector, Updater } from '@forgerock/davinci-client/types';
 
 export default function (formEl: HTMLFormElement, collector: TextCollector, updater: Updater) {
   // create paragraph element with text of "Loading ... "
diff --git a/e2e/davinci-app/components/social-login-button.ts b/e2e/davinci-app/components/social-login-button.ts
index 593b2dd0..96cca3f9 100644
--- a/e2e/davinci-app/components/social-login-button.ts
+++ b/e2e/davinci-app/components/social-login-button.ts
@@ -1,4 +1,4 @@
-import { SocialLoginCollector } from '@forgerock/davinci-client/types';
+import type { SocialLoginCollector } from '@forgerock/davinci-client/types';
 
 export default function submitButtonComponent(
   formEl: HTMLFormElement,
diff --git a/e2e/davinci-app/components/submit-button.ts b/e2e/davinci-app/components/submit-button.ts
index f082394c..52d1435d 100644
--- a/e2e/davinci-app/components/submit-button.ts
+++ b/e2e/davinci-app/components/submit-button.ts
@@ -1,4 +1,4 @@
-import { SubmitCollector } from '@forgerock/davinci-client/types';
+import type { SubmitCollector } from '@forgerock/davinci-client/types';
 
 export default function submitButtonComponent(formEl: HTMLFormElement, collector: SubmitCollector) {
   const button = document.createElement('button');
diff --git a/e2e/davinci-app/components/text.ts b/e2e/davinci-app/components/text.ts
index a645d178..a05e27c2 100644
--- a/e2e/davinci-app/components/text.ts
+++ b/e2e/davinci-app/components/text.ts
@@ -1,4 +1,4 @@
-import { TextCollector, Updater } from '@forgerock/davinci-client/types';
+import type { TextCollector, Updater } from '@forgerock/davinci-client/types';
 
 export default function usernameComponent(
   formEl: HTMLFormElement,
diff --git a/e2e/davinci-app/package.json b/e2e/davinci-app/package.json
index def4c2f9..e42344e8 100644
--- a/e2e/davinci-app/package.json
+++ b/e2e/davinci-app/package.json
@@ -1,14 +1,17 @@
 {
   "name": "@forgerock/davinci-app",
+  "version": "0.0.0",
   "description": "Ping DaVinci Client Test App",
   "type": "module",
   "private": true,
+  "nx": {
+    "tags": ["scope:app"]
+  },
   "dependencies": {
     "@forgerock/davinci-client": "workspace:*",
     "@forgerock/javascript-sdk": "4.6.0"
   },
   "devDependencies": {},
-  "version": "0.0.0",
   "scripts": {
     "build": "nx exec -- vite build --watch false",
     "serve": "vite dev",
diff --git a/e2e/davinci-app/tsconfig.app.json b/e2e/davinci-app/tsconfig.app.json
index 4284d543..e9aa43a6 100644
--- a/e2e/davinci-app/tsconfig.app.json
+++ b/e2e/davinci-app/tsconfig.app.json
@@ -4,6 +4,6 @@
     "outDir": "../../dist/out-tsc",
     "moduleResolution": "Bundler"
   },
-  "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"],
-  "include": ["src/**/*.ts"]
+  "exclude": ["**/*.spec.ts", "**/*.test.ts"],
+  "include": ["./main.ts", "components/**/*.ts"]
 }
diff --git a/e2e/davinci-app/tsconfig.json b/e2e/davinci-app/tsconfig.json
index 2a4c942c..4b6c908d 100644
--- a/e2e/davinci-app/tsconfig.json
+++ b/e2e/davinci-app/tsconfig.json
@@ -7,6 +7,8 @@
     "lib": ["ESNext", "DOM"],
     "strict": true,
     "resolveJsonModule": true,
+    "moduleDetection": "force",
+    "verbatimModuleSyntax": true,
     "isolatedModules": true,
     "esModuleInterop": true,
     "noUnusedLocals": true,
diff --git a/e2e/davinci-suites/package.json b/e2e/davinci-suites/package.json
index fec3e1e4..64e2f5cf 100644
--- a/e2e/davinci-suites/package.json
+++ b/e2e/davinci-suites/package.json
@@ -7,6 +7,9 @@
   "main": "src/index.js",
   "author": "",
   "license": "ISC",
+  "nx": {
+    "implicitDependencies": ["@forgerock/davinci-app", "@forgerock/mock-api-v2"]
+  },
   "repository": {
     "type": "git",
     "url": "git+https://github.com/ForgeRock/ping-javascript-sdk.git"
diff --git a/nx.json b/nx.json
index 41e1f80e..848ff012 100644
--- a/nx.json
+++ b/nx.json
@@ -12,6 +12,9 @@
     "noMarkdown": ["!{projectRoot}/**/*.md"]
   },
   "targetDefaults": {
+    "typecheck": {
+      "dependsOn": ["build", "^build"]
+    },
     "docs": {
       "dependsOn": ["build", "^build", "^docs"],
       "cache": true,
diff --git a/packages/davinci-client/package.json b/packages/davinci-client/package.json
index ca0a7c78..48a63d0b 100644
--- a/packages/davinci-client/package.json
+++ b/packages/davinci-client/package.json
@@ -6,6 +6,10 @@
   "typings": "./dist/index.d.ts",
   "type": "module",
   "files": ["dist"],
+  "sideEffects": ["./src/types.js"],
+  "nx": {
+    "tags": ["scope:package"]
+  },
   "repository": {
     "type": "git",
     "url": "git+https://github.com:ForgeRock/forgerock-javascript-sdk.git",
@@ -19,9 +23,6 @@
     "@reduxjs/toolkit": "catalog:",
     "immer": "catalog:"
   },
-  "devDependencies": {
-    "vitest": "^1.4.0"
-  },
   "exports": {
     ".": {
       "import": "./dist/index.js",
@@ -31,6 +32,7 @@
   },
   "scripts": {
     "build": "nx exec -- vite build",
+    "serve": "nx exec -- vite dev",
     "test": "vitest",
     "test:watch": "vitest --watch",
     "test:coverage": "vitest --coverage",
diff --git a/packages/davinci-client/src/lib/client.store.ts b/packages/davinci-client/src/lib/client.store.ts
index 05fc8112..881d190d 100644
--- a/packages/davinci-client/src/lib/client.store.ts
+++ b/packages/davinci-client/src/lib/client.store.ts
@@ -57,7 +57,10 @@ export async function davinci({ config }: { config: DaVinciConfig }) {
       if (!action.action) {
         console.error('Missing `argument.action`');
         return async function () {
-          return { error: { message: 'Missing argument.action', type: 'argument_error' } };
+          return {
+            error: { message: 'Missing argument.action', type: 'argument_error' },
+            type: 'internal_error',
+          };
         };
       }
 
@@ -107,6 +110,7 @@ export async function davinci({ config }: { config: DaVinciConfig }) {
         return function () {
           return {
             error: { message: 'Argument for `collector` has no ID', type: 'argument_error' },
+            type: 'internal_error',
           };
         };
       }
@@ -118,6 +122,7 @@ export async function davinci({ config }: { config: DaVinciConfig }) {
         return function () {
           console.error('Collector not found');
           return {
+            type: 'internal_error',
             error: { message: 'Collector not found', type: 'state_error' },
           };
         };
@@ -127,6 +132,7 @@ export async function davinci({ config }: { config: DaVinciConfig }) {
         console.error('Collector is not a SingleValueCollector and cannot be updated');
         return function () {
           return {
+            type: 'internal_error',
             error: {
               message: 'Collector is not a SingleValueCollector and cannot be updated',
               type: 'state_error',
@@ -141,7 +147,10 @@ export async function davinci({ config }: { config: DaVinciConfig }) {
           return null;
         } catch (err) {
           const error = err as Error;
-          return { error: { message: error.message, type: 'internal_error' } };
+          return {
+            type: 'internal_error',
+            error: { message: error.message, type: 'internal_error' },
+          };
         }
       };
     },
diff --git a/packages/davinci-client/src/lib/client.types.test-d.ts b/packages/davinci-client/src/lib/client.types.test-d.ts
new file mode 100644
index 00000000..e2566f5a
--- /dev/null
+++ b/packages/davinci-client/src/lib/client.types.test-d.ts
@@ -0,0 +1,188 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+import { describe, expectTypeOf, it } from 'vitest';
+import type { InitFlow, InternalErrorResponse, Updater } from './client.types.js';
+import type { GenericError } from './error.types.js';
+import type { ErrorNode, FailureNode, ContinueNode, StartNode, SuccessNode } from './node.types.js';
+
+describe('Client Types', () => {
+  it('should allow function returning error', async () => {
+    // This test isn't excellent but without narrowing inside the function we cant
+    // narrow the promise type enough without some help on the generic
+    const withError = async (): Promise<InternalErrorResponse> => {
+      const result = await Promise.resolve<InternalErrorResponse>({
+        error: { message: 'Test error', type: 'argument_error' as const },
+        type: 'internal_error' as const,
+      });
+      return result;
+    };
+
+    expectTypeOf(withError()).resolves.toMatchTypeOf<InternalErrorResponse>();
+  });
+  it('should allow function returning node types', () => {
+    const withErrorNode: InitFlow = async () => ({
+      cache: {
+        key: 'string',
+      },
+      client: {
+        status: 'error',
+      },
+      error: {
+        type: 'argument_error',
+        status: 'failure',
+        message: 'failed',
+      },
+      httpStatus: 400,
+      server: {
+        status: 'error',
+      },
+      status: 'error',
+    });
+
+    const withFailureNode: InitFlow = async () => ({
+      cache: {
+        key: '',
+      },
+      client: {
+        status: 'failure',
+      },
+      error: {
+        type: 'state_error',
+        status: 'failure',
+        message: 'failed',
+      },
+      httpStatus: 404,
+      server: null,
+      status: 'failure',
+    });
+
+    const withContinueNode: InitFlow = async () => ({
+      cache: {
+        key: 'cachekey',
+      },
+      client: {
+        action: 'action',
+        collectors: [],
+        description: 'the description',
+        name: 'continue_node_name',
+        status: 'continue',
+      },
+      error: null,
+      httpStatus: 200,
+      server: {
+        eventName: 'continue_event',
+        status: 'continue',
+      },
+      status: 'continue',
+    });
+
+    const withStartNode: InitFlow = async () => ({
+      cache: null,
+      client: {
+        status: 'start',
+      },
+      error: null,
+      server: {
+        status: 'start',
+      },
+      status: 'start',
+    });
+
+    const withSuccessNode: InitFlow = async () => ({
+      cache: {
+        key: 'key',
+      },
+      client: {
+        authorization: {
+          code: 'code123412',
+          state: 'code123213',
+        },
+        status: 'success',
+      },
+      error: null,
+      httpStatus: 200,
+      server: {
+        eventName: 'success_event',
+        id: 'theid',
+        interactionId: '213123',
+        interactionToken: '123213',
+        status: 'success',
+      },
+      status: 'success',
+    });
+
+    // Test return types
+    // @ts-expect-error - This is a problem because ErrorResponse does not have a discriminator that separates it from FlowNode (see `error` key in both types.)
+    expectTypeOf(withErrorNode).returns.resolves.toMatchTypeOf<ErrorNode>();
+    // @ts-expect-error - This is a problem because ErrorResponse does not have a discriminator that separates it from FlowNode (see `error` key in both types.)
+    expectTypeOf(withFailureNode).returns.resolves.toMatchTypeOf<FailureNode>();
+    // @ts-expect-error - This is a problem because ErrorResponse does not have a discriminator that separates it from FlowNode (see `error` key in both types.)
+    expectTypeOf(withContinueNode).returns.resolves.toMatchTypeOf<ContinueNode>();
+    // @ts-expect-error - This is a problem because ErrorResponse does not have a discriminator that separates it from FlowNode (see `error` key in both types.)
+    expectTypeOf(withStartNode).returns.resolves.toMatchTypeOf<StartNode>();
+    // @ts-expect-error - This is a problem because ErrorResponse does not have a discriminator that separates it from FlowNode (see `error` key in both types.)
+    expectTypeOf(withSuccessNode).returns.resolves.toMatchTypeOf<SuccessNode>();
+
+    // Test that all are valid InitFlow types
+    expectTypeOf(withErrorNode).toMatchTypeOf<InitFlow>();
+    expectTypeOf(withFailureNode).toMatchTypeOf<InitFlow>();
+    expectTypeOf(withContinueNode).toMatchTypeOf<InitFlow>();
+    expectTypeOf(withStartNode).toMatchTypeOf<InitFlow>();
+    expectTypeOf(withSuccessNode).toMatchTypeOf<InitFlow>();
+  });
+
+  it('should enforce async function return type', () => {
+    // @ts-expect-error - Should not allow non-promise return
+    const invalid: InitFlow = () => ({
+      cache: {
+        key: 'key',
+      },
+      client: {
+        action: 'continue',
+        collectors: [],
+        status: 'continue',
+      },
+      error: null,
+      httpStatus: 200,
+      server: {
+        status: 'continue',
+      },
+      status: 'continue',
+    });
+
+    expectTypeOf<InitFlow>().toBeFunction();
+
+    // @ts-expect-error - Should not allow non-promise return - we expect this to error
+    expectTypeOf<InitFlow>().returns.toEqualTypeOf<InitFlow>;
+  });
+});
+
+describe('Updater', () => {
+  it('should accept string value and optional index', () => {
+    const updater: Updater = (value: string, index?: number) => {
+      return {
+        error: { message: 'Invalid value', code: 'INVALID', type: 'state_error' },
+        type: 'internal_error',
+      };
+    };
+
+    expectTypeOf(updater).parameter(0).toBeString();
+    expectTypeOf(updater).parameter(1).toBeNullable();
+    expectTypeOf(updater).parameter(1).toBeNullable();
+  });
+
+  it('should return error or null', () => {
+    const withError: Updater = () => ({
+      error: { message: 'Invalid value', code: 'INVALID', type: 'state_error' },
+      type: 'internal_error',
+    });
+
+    const withoutError: Updater = () => null;
+
+    expectTypeOf(withError).returns.toMatchTypeOf<{ error: GenericError } | null>();
+    expectTypeOf(withoutError).returns.toMatchTypeOf<{ error: GenericError } | null>();
+
+    // Test both are valid Updater types
+    expectTypeOf(withError).toMatchTypeOf<Updater>();
+    expectTypeOf(withoutError).toMatchTypeOf<Updater>();
+  });
+});
diff --git a/packages/davinci-client/src/lib/client.types.ts b/packages/davinci-client/src/lib/client.types.ts
index 4eea4b10..fa2b4ec1 100644
--- a/packages/davinci-client/src/lib/client.types.ts
+++ b/packages/davinci-client/src/lib/client.types.ts
@@ -1,8 +1,13 @@
-import { GenericError } from './error.types';
-import { ErrorNode, FailureNode, ContinueNode, StartNode, SuccessNode } from './node.types';
+import { GenericError } from './error.types.js';
+import { ErrorNode, FailureNode, ContinueNode, StartNode, SuccessNode } from './node.types.js';
 
-export type InitFlow =
-  | (() => Promise<{ error: GenericError }>)
-  | (() => Promise<ContinueNode | ErrorNode | StartNode | SuccessNode | FailureNode>);
+export type FlowNode = ContinueNode | ErrorNode | StartNode | SuccessNode | FailureNode;
 
-export type Updater = (value: string, index?: number) => { error: GenericError } | null;
+export interface InternalErrorResponse {
+  error: GenericError;
+  type: 'internal_error';
+}
+
+export type InitFlow = () => Promise<FlowNode | InternalErrorResponse>;
+
+export type Updater = (value: string, index?: number) => InternalErrorResponse | null;
diff --git a/packages/davinci-client/src/lib/collector.types.test-d.ts b/packages/davinci-client/src/lib/collector.types.test-d.ts
new file mode 100644
index 00000000..02766118
--- /dev/null
+++ b/packages/davinci-client/src/lib/collector.types.test-d.ts
@@ -0,0 +1,355 @@
+import { describe, expectTypeOf, it } from 'vitest';
+import type {
+  SingleValueCollectorTypes,
+  SingleValueCollectorWithValue,
+  SingleValueCollectorNoValue,
+  ActionCollectorTypes,
+  ActionCollectorWithUrl,
+  ActionCollectorNoUrl,
+  TextCollector,
+  PasswordCollector,
+  FlowCollector,
+  SocialLoginCollector,
+  SubmitCollector,
+  SingleSelectCollector,
+  MultiValueCollectorWithValue,
+  MultiSelectCollector,
+  InferSingleValueCollectorType,
+  InferMultiValueCollectorType,
+  InferActionCollectorType,
+} from './collector.types.js';
+
+describe('Collector Types', () => {
+  describe('SingleValueCollector Types', () => {
+    it('should validate TextCollector structure', () => {
+      expectTypeOf<TextCollector>().toMatchTypeOf<SingleValueCollectorWithValue<'TextCollector'>>();
+      expectTypeOf<TextCollector>()
+        .toHaveProperty('category')
+        .toEqualTypeOf<'SingleValueCollector'>();
+      expectTypeOf<TextCollector>().toHaveProperty('type').toEqualTypeOf<'TextCollector'>();
+      expectTypeOf<TextCollector['output']>().toHaveProperty('value');
+      expectTypeOf<TextCollector['output']['value']>().toBeString();
+    });
+
+    it('should validate PasswordCollector structure', () => {
+      expectTypeOf<PasswordCollector>().toMatchTypeOf<
+        SingleValueCollectorNoValue<'PasswordCollector'>
+      >();
+      expectTypeOf<PasswordCollector>()
+        .toHaveProperty('category')
+        .toEqualTypeOf<'SingleValueCollector'>();
+      expectTypeOf<PasswordCollector>().toHaveProperty('type');
+      expectTypeOf<PasswordCollector['output']>().toEqualTypeOf<{
+        key: string;
+        label: string;
+        type: string;
+      }>();
+    });
+
+    it('should validate SingleCollector structure', () => {
+      expectTypeOf<SingleSelectCollector>().toMatchTypeOf<
+        SingleValueCollectorWithValue<'SingleSelectCollector'>
+      >();
+      expectTypeOf<SingleSelectCollector>()
+        .toHaveProperty('category')
+        .toEqualTypeOf<'SingleValueCollector'>();
+      expectTypeOf<SingleSelectCollector>()
+        .toHaveProperty('type')
+        .toEqualTypeOf<'SingleSelectCollector'>();
+      expectTypeOf<SingleSelectCollector['output']>().toHaveProperty('value');
+    });
+
+    it('should validate MultiSelectCollector structure', () => {
+      expectTypeOf<MultiSelectCollector>().toMatchTypeOf<
+        MultiValueCollectorWithValue<'MultiSelectCollector'>
+      >();
+      expectTypeOf<MultiSelectCollector>()
+        .toHaveProperty('category')
+        .toEqualTypeOf<'MultiValueCollector'>();
+      expectTypeOf<MultiSelectCollector>()
+        .toHaveProperty('type')
+        .toEqualTypeOf<'MultiSelectCollector'>();
+      expectTypeOf<MultiSelectCollector['output']>().toHaveProperty('value');
+    });
+  });
+
+  describe('ActionCollector Types', () => {
+    it('should validate SocialLoginCollector structure', () => {
+      expectTypeOf<SocialLoginCollector>().toMatchTypeOf<
+        ActionCollectorWithUrl<'SocialLoginCollector'>
+      >();
+      expectTypeOf<SocialLoginCollector>()
+        .toHaveProperty('category')
+        .toEqualTypeOf<'ActionCollector'>();
+      expectTypeOf<SocialLoginCollector>()
+        .toHaveProperty('type')
+        .toEqualTypeOf<'SocialLoginCollector'>();
+      expectTypeOf<SocialLoginCollector['output']>().toHaveProperty('url');
+    });
+
+    it('should validate FlowCollector structure', () => {
+      expectTypeOf<FlowCollector>().toMatchTypeOf<ActionCollectorNoUrl<'FlowCollector'>>();
+      expectTypeOf<FlowCollector>().toHaveProperty('category').toEqualTypeOf<'ActionCollector'>();
+      expectTypeOf<FlowCollector>().toHaveProperty('type').toEqualTypeOf<'FlowCollector'>();
+      expectTypeOf<FlowCollector['output']>().not.toHaveProperty('url');
+    });
+
+    it('should validate SubmitCollector structure', () => {
+      expectTypeOf<SubmitCollector>().toMatchTypeOf<ActionCollectorNoUrl<'SubmitCollector'>>();
+      expectTypeOf<SubmitCollector>().toHaveProperty('category').toEqualTypeOf<'ActionCollector'>();
+      expectTypeOf<SubmitCollector>().toHaveProperty('type').toEqualTypeOf<'SubmitCollector'>();
+      expectTypeOf<SubmitCollector['output']>().not.toHaveProperty('url');
+    });
+  });
+
+  describe('Type Inference', () => {
+    it('should correctly infer SingleValueCollector types', () => {
+      expectTypeOf<InferSingleValueCollectorType<'TextCollector'>>().toEqualTypeOf<TextCollector>();
+
+      expectTypeOf<
+        InferSingleValueCollectorType<'PasswordCollector'>
+      >().toEqualTypeOf<PasswordCollector>();
+
+      expectTypeOf<
+        InferSingleValueCollectorType<'SingleSelectCollector'>
+      >().toEqualTypeOf<SingleSelectCollector>();
+    });
+
+    it('should handle generic SingleValueCollector type', () => {
+      type Generic = InferSingleValueCollectorType<'SingleValueCollector'>;
+      expectTypeOf<Generic>().toMatchTypeOf<
+        | SingleValueCollectorWithValue<'SingleValueCollector'>
+        | SingleValueCollectorNoValue<'SingleValueCollector'>
+      >();
+    });
+  });
+
+  describe('Base Type Validations', () => {
+    it('should validate SingleValueCollectorTypes contains all valid types', () => {
+      const validTypes: SingleValueCollectorTypes[] = [
+        'TextCollector',
+        'PasswordCollector',
+        'SingleSelectCollector',
+      ];
+
+      // Type assertion to ensure SingleValueCollectorTypes includes all these values
+      expectTypeOf<SingleValueCollectorTypes>().toEqualTypeOf<(typeof validTypes)[number]>();
+    });
+
+    it('should validate ActionCollectorTypes contains all valid types', () => {
+      const validTypes: ActionCollectorTypes[] = [
+        'SocialLoginCollector',
+        'FlowCollector',
+        'SubmitCollector',
+      ];
+
+      // Type assertion to ensure ActionCollectorTypes includes all these values
+      expectTypeOf<ActionCollectorTypes>().toEqualTypeOf<(typeof validTypes)[number]>();
+    });
+
+    it('should validate base type constraints', () => {
+      // Test SingleValueCollectorWithValue constraints
+      const withValue: SingleValueCollectorWithValue<'TextCollector'> = {
+        category: 'SingleValueCollector',
+        type: 'TextCollector',
+        error: null,
+        id: 'test',
+        name: 'Test',
+        input: {
+          key: 'test',
+          value: 'test',
+          type: 'string',
+        },
+        output: {
+          key: 'test',
+          label: 'Test',
+          type: 'string',
+          value: 'test',
+        },
+      };
+      expectTypeOf(withValue).toMatchTypeOf<SingleValueCollectorWithValue<'TextCollector'>>();
+
+      // Test SingleValueCollectorNoValue constraints
+      const noValue: SingleValueCollectorNoValue<'PasswordCollector'> = {
+        category: 'SingleValueCollector',
+        type: 'PasswordCollector',
+        error: null,
+        id: 'test',
+        name: 'Test',
+        input: {
+          key: 'test',
+          value: '',
+          type: 'string',
+        },
+        output: {
+          key: 'test',
+          label: 'Test',
+          type: 'string',
+        },
+      };
+      expectTypeOf(noValue).toMatchTypeOf<SingleValueCollectorNoValue<'PasswordCollector'>>();
+
+      // Test ActionCollectorWithUrl constraints
+      const withUrl: ActionCollectorWithUrl<'SocialLoginCollector'> = {
+        category: 'ActionCollector',
+        type: 'SocialLoginCollector',
+        error: null,
+        id: 'test',
+        name: 'Test',
+        output: {
+          key: 'test',
+          label: 'Test',
+          type: 'button',
+          url: 'https://example.com',
+        },
+      };
+      expectTypeOf(withUrl).toMatchTypeOf<ActionCollectorWithUrl<'SocialLoginCollector'>>();
+
+      // Test ActionCollectorNoUrl constraints
+      const noUrl: ActionCollectorNoUrl<'SubmitCollector'> = {
+        category: 'ActionCollector',
+        type: 'SubmitCollector',
+        error: null,
+        id: 'test',
+        name: 'Test',
+        output: {
+          key: 'test',
+          label: 'Test',
+          type: 'button',
+        },
+      };
+      expectTypeOf(noUrl).toMatchTypeOf<ActionCollectorNoUrl<'SubmitCollector'>>();
+    });
+  });
+  describe('InferSingleValueCollectorFromSingleValueCollectorType', () => {
+    it('should correctly infer TextCollector Type', () => {
+      const tCollector: InferSingleValueCollectorType<'TextCollector'> = {
+        category: 'SingleValueCollector',
+        error: null,
+        type: 'TextCollector',
+        id: '',
+        name: '',
+        input: {
+          key: '',
+          value: '',
+          type: '',
+        },
+        output: {
+          key: '',
+          label: '',
+          type: '',
+          value: '',
+        },
+      };
+
+      expectTypeOf(tCollector).toMatchTypeOf<TextCollector>();
+    });
+    it('should correctly infer PasswordCollector Type', () => {
+      const tCollector: InferSingleValueCollectorType<'PasswordCollector'> = {
+        category: 'SingleValueCollector',
+        error: null,
+        type: 'PasswordCollector',
+        id: '',
+        name: '',
+        input: {
+          key: '',
+          value: '',
+          type: '',
+        },
+        output: {
+          key: '',
+          label: '',
+          type: '',
+        },
+      };
+
+      expectTypeOf(tCollector).toMatchTypeOf<PasswordCollector>();
+    });
+    it('should correctly infer SingleValueCollector Type', () => {
+      const tCollector: InferSingleValueCollectorType<'SingleValueCollector'> = {
+        category: 'SingleValueCollector',
+        error: null,
+        type: 'SingleValueCollector',
+        id: '',
+        name: '',
+        input: {
+          key: '',
+          value: '',
+          type: '',
+        },
+        output: {
+          key: '',
+          label: '',
+          type: '',
+          value: '',
+        },
+      };
+
+      expectTypeOf(tCollector).toMatchTypeOf<
+        SingleValueCollectorWithValue<'SingleValueCollector'>
+      >();
+    });
+    it('should correctly infer MultiSelectCollector Type', () => {
+      const tCollector: InferMultiValueCollectorType<'MultiSelectCollector'> = {
+        category: 'MultiValueCollector',
+        error: null,
+        type: 'MultiSelectCollector',
+        id: '',
+        name: '',
+        input: {
+          key: '',
+          value: [''],
+          type: '',
+        },
+        output: {
+          key: '',
+          label: '',
+          type: '',
+          value: [''],
+          options: [{ label: '', value: '' }],
+        },
+      };
+
+      expectTypeOf(tCollector).toMatchTypeOf<MultiSelectCollector>();
+    });
+    it('should correctly infer SingleSelectCollector Type', () => {
+      const tCollector: InferSingleValueCollectorType<'SingleSelectCollector'> = {
+        category: 'SingleValueCollector',
+        error: null,
+        type: 'SingleSelectCollector',
+        id: '',
+        name: '',
+        input: {
+          key: '',
+          value: '',
+          type: '',
+        },
+        output: {
+          key: '',
+          label: '',
+          type: '',
+          value: '',
+          options: [{ label: '', value: '' }],
+        },
+      };
+
+      expectTypeOf(tCollector).toMatchTypeOf<SingleSelectCollector>();
+    });
+    it('should correctly infer FlowCollector Type', () => {
+      const tCollector: InferActionCollectorType<'FlowCollector'> = {
+        category: 'ActionCollector',
+        error: null,
+        type: 'FlowCollector',
+        id: '',
+        name: '',
+        output: {
+          key: '',
+          label: '',
+          type: '',
+        },
+      };
+
+      expectTypeOf(tCollector).toMatchTypeOf<FlowCollector>();
+    });
+  });
+});
diff --git a/packages/davinci-client/src/lib/collector.types.ts b/packages/davinci-client/src/lib/collector.types.ts
index 0b6bc653..0b72e855 100644
--- a/packages/davinci-client/src/lib/collector.types.ts
+++ b/packages/davinci-client/src/lib/collector.types.ts
@@ -2,9 +2,15 @@
  * @interface SingleValueCollector - Represents a request to collect a single value from the user, like email or password.
  */
 export type SingleValueCollectorTypes =
-  | 'TextCollector'
   | 'PasswordCollector'
-  | 'SingleValueCollector';
+  | 'SingleValueCollector'
+  | 'SingleSelectCollector'
+  | 'TextCollector';
+
+interface SelectorOptions {
+  label: string;
+  value: string;
+}
 
 export interface SingleValueCollectorWithValue<T extends SingleValueCollectorTypes> {
   category: 'SingleValueCollector';
@@ -25,6 +31,26 @@ export interface SingleValueCollectorWithValue<T extends SingleValueCollectorTyp
   };
 }
 
+export interface SingleSelectCollectorWithValue<T extends SingleValueCollectorTypes> {
+  category: 'SingleValueCollector';
+  error: string | null;
+  type: T;
+  id: string;
+  name: string;
+  input: {
+    key: string;
+    value: string | number | boolean;
+    type: string;
+  };
+  output: {
+    key: string;
+    label: string;
+    type: string;
+    value: string;
+    options: SelectorOptions[];
+  };
+}
+
 export interface SingleValueCollectorNoValue<T extends SingleValueCollectorTypes> {
   category: 'SingleValueCollector';
   error: string | null;
@@ -43,15 +69,134 @@ export interface SingleValueCollectorNoValue<T extends SingleValueCollectorTypes
   };
 }
 
-export type SingleValueCollectors =
-  | SingleValueCollectorWithValue<'SingleValueCollector'>
-  | SingleValueCollectorWithValue<'TextCollector'>
-  | SingleValueCollectorNoValue<'PasswordCollector'>;
+export interface SingleSelectCollectorNoValue<T extends SingleValueCollectorTypes> {
+  category: 'SingleValueCollector';
+  error: string | null;
+  type: T;
+  id: string;
+  name: string;
+  input: {
+    key: string;
+    value: string | number | boolean;
+    type: string;
+  };
+  output: {
+    key: string;
+    label: string;
+    type: string;
+    options: SelectorOptions[];
+  };
+}
+
+/**
+ * Type to help infer the collector based on the collector type
+ * Used specifically in the returnSingleValueCollector wrapper function.
+ * When given a type, it can narrow which type it is returning
+ *
+ * Note: You can see this type in action in the test file or in the collector.utils file.
+ */
+export type InferSingleValueCollectorType<T extends SingleValueCollectorTypes> =
+  T extends 'TextCollector'
+    ? TextCollector
+    : T extends 'SingleSelectCollector'
+      ? SingleSelectCollector
+      : T extends 'PasswordCollector'
+        ? PasswordCollector
+        : /**
+           * At this point, we have not passed in a collector type
+           * or we have explicitly passed in 'SingleValueCollector'
+           * So we can return either a SingleValueCollector with value
+           * or without a value.
+           **/
+          | SingleValueCollectorWithValue<'SingleValueCollector'>
+            | SingleValueCollectorNoValue<'SingleValueCollector'>;
 
+/**
+ * SINGLE-VALUE COLLECTOR TYPES
+ */
 export type SingleValueCollector<T extends SingleValueCollectorTypes> =
   | SingleValueCollectorWithValue<T>
   | SingleValueCollectorNoValue<T>;
 
+export type SingleValueCollectors =
+  | SingleValueCollectorNoValue<'PasswordCollector'>
+  | SingleSelectCollectorWithValue<'SingleSelectCollector'>
+  | SingleValueCollectorWithValue<'SingleValueCollector'>
+  | SingleValueCollectorWithValue<'TextCollector'>;
+
+export type PasswordCollector = SingleValueCollectorNoValue<'PasswordCollector'>;
+export type TextCollector = SingleValueCollectorWithValue<'TextCollector'>;
+export type SingleSelectCollector = SingleSelectCollectorWithValue<'SingleSelectCollector'>;
+
+/**
+ * @interface MultiValueCollector - Represents a request to collect a single value from the user, like email or password.
+ */
+export type MultiValueCollectorTypes = 'MultiSelectCollector' | 'MultiValueCollector';
+
+export interface MultiValueCollectorWithValue<T extends MultiValueCollectorTypes> {
+  category: 'MultiValueCollector';
+  error: string | null;
+  type: T;
+  id: string;
+  name: string;
+  input: {
+    key: string;
+    value: string[];
+    type: string;
+  };
+  output: {
+    key: string;
+    label: string;
+    type: string;
+    value: string[];
+    options: SelectorOptions[];
+  };
+}
+
+export interface MultiValueCollectorNoValue<T extends MultiValueCollectorTypes> {
+  category: 'MultiValueCollector';
+  error: string | null;
+  type: T;
+  id: string;
+  name: string;
+  input: {
+    key: string;
+    value: string[];
+    type: string;
+  };
+  output: {
+    key: string;
+    label: string;
+    type: string;
+    value: string[];
+    options: SelectorOptions[];
+  };
+}
+
+/**
+ * Type to help infer the collector based on the collector type
+ * Used specifically in the returnMultiValueCollector wrapper function.
+ * When given a type, it can narrow which type it is returning
+ *
+ * Note: You can see this type in action in the test file or in the collector.utils file.
+ */
+export type InferMultiValueCollectorType<T extends MultiValueCollectorTypes> =
+  T extends 'MultiSelectCollector'
+    ? MultiValueCollectorWithValue<'MultiSelectCollector'>
+    :
+        | MultiValueCollectorWithValue<'MultiValueCollector'>
+        | MultiValueCollectorNoValue<'MultiValueCollector'>;
+
+export type MultiValueCollectors =
+  | MultiValueCollectorWithValue<'MultiValueCollector'>
+  | MultiValueCollectorWithValue<'MultiSelectCollector'>;
+
+export type MultiValueCollector<T extends MultiValueCollectorTypes> =
+  | MultiValueCollectorWithValue<T>
+  | MultiValueCollectorNoValue<T>;
+
+export type MultiSelectCollector = MultiValueCollectorWithValue<'MultiSelectCollector'>;
+
 /**
  * @interface ActionCollector - Represents a user option to perform an action, like submitting a form or choosing another flow.
  */
@@ -92,6 +237,15 @@ export type ActionCollector<T extends ActionCollectorTypes> =
   | ActionCollectorNoUrl<T>
   | ActionCollectorWithUrl<T>;
 
+export type InferActionCollectorType<T extends ActionCollectorTypes> =
+  T extends 'SocialLoginCollector'
+    ? SocialLoginCollector
+    : T extends 'SubmitCollector'
+      ? SubmitCollector
+      : T extends 'FlowCollector'
+        ? FlowCollector
+        : ActionCollectorWithUrl<'ActionCollector'> | ActionCollectorNoUrl<'ActionCollector'>;
+
 export type ActionCollectors =
   | ActionCollectorWithUrl<'SocialLoginCollector'>
   | ActionCollectorNoUrl<'ActionCollector'>
@@ -99,7 +253,5 @@ export type ActionCollectors =
   | ActionCollectorNoUrl<'SubmitCollector'>;
 
 export type FlowCollector = ActionCollectorNoUrl<'FlowCollector'>;
-export type PasswordCollector = SingleValueCollectorNoValue<'PasswordCollector'>;
-export type TextCollector = SingleValueCollectorWithValue<'TextCollector'>;
 export type SocialLoginCollector = ActionCollectorWithUrl<'SocialLoginCollector'>;
 export type SubmitCollector = ActionCollectorNoUrl<'SubmitCollector'>;
diff --git a/packages/davinci-client/src/lib/collector.utils.test.ts b/packages/davinci-client/src/lib/collector.utils.test.ts
index 7197a7a7..b0bc6222 100644
--- a/packages/davinci-client/src/lib/collector.utils.test.ts
+++ b/packages/davinci-client/src/lib/collector.utils.test.ts
@@ -1,145 +1,381 @@
 import { describe, it, expect } from 'vitest';
+import {
+  returnActionCollector,
+  returnFlowCollector,
+  returnSocialLoginCollector,
+  returnSubmitCollector,
+  returnSingleValueCollector,
+  returnPasswordCollector,
+  returnTextCollector,
+  returnSingleSelectCollector,
+  returnMultiSelectCollector,
+} from './collector.utils.js';
+import type { DaVinciField, StandardFieldValue } from './davinci.types.js';
 
-import { returnActionCollector } from './collector.utils.js';
-import { returnSingleValueCollector } from './collector.utils.js';
+describe('Action Collectors', () => {
+  describe('returnFlowCollector', () => {
+    const mockField: DaVinciField = {
+      key: 'flow-key',
+      label: 'Flow Label',
+      type: 'BUTTON',
+    };
 
-import type { DaVinciField } from './davinci.types.d.ts';
+    it('should create a valid flow collector', () => {
+      const result = returnFlowCollector(mockField, 1);
+      expect(result).toEqual({
+        category: 'ActionCollector',
+        error: null,
+        type: 'FlowCollector',
+        id: 'flow-key-1',
+        name: 'flow-key',
+        output: {
+          key: mockField.key,
+          label: mockField.label,
+          type: mockField.type,
+        },
+      });
+    });
 
-describe('The returnActionCollector function', () => {
-  const mockField: DaVinciField = {
+    it('should handle error cases properly', () => {
+      const invalidField = {} as StandardFieldValue;
+      const result = returnFlowCollector(invalidField, 1);
+      expect(result.error).toContain('Key is not found');
+      expect(result.error).toContain('Label is not found');
+      expect(result.error).toContain('Type is not found');
+    });
+  });
+
+  describe('returnSocialLoginCollector', () => {
+    const mockSocialField: DaVinciField = {
+      key: 'google-login',
+      label: 'Continue with Google',
+      type: 'BUTTON',
+      links: {
+        authenticate: {
+          href: 'https://auth.example.com/google',
+        },
+      },
+    };
+
+    it('should create a valid social login collector with authentication URL', () => {
+      const result = returnSocialLoginCollector(mockSocialField, 1);
+      expect(result).toEqual({
+        category: 'ActionCollector',
+        error: null,
+        type: 'SocialLoginCollector',
+        id: 'google-login-1',
+        name: 'google-login',
+        output: {
+          key: mockSocialField.key,
+          label: mockSocialField.label,
+          type: mockSocialField.type,
+          url: 'https://auth.example.com/google',
+        },
+      });
+    });
+
+    it('should handle missing authentication URL', () => {
+      const fieldWithoutUrl: DaVinciField = {
+        key: 'google-login',
+        label: 'Continue with Google',
+        type: 'BUTTON',
+      };
+      // this type could be more comprehensive
+      // that is why casting as any here works
+      const result = returnSocialLoginCollector(fieldWithoutUrl, 1);
+      expect(result.output.url).toBeNull();
+    });
+
+    it('should handle error cases properly', () => {
+      const invalidField = {} as StandardFieldValue;
+      const result = returnSocialLoginCollector(invalidField, 1);
+      expect(result.error).toContain('Key is not found');
+      expect(result.type).toBe('SocialLoginCollector');
+    });
+  });
+
+  describe('returnSubmitCollector', () => {
+    const mockField: DaVinciField = {
+      key: 'submit-key',
+      label: 'Submit Form',
+      type: 'SUBMIT_BUTTON',
+    };
+
+    it('should create a valid submit collector', () => {
+      const result = returnSubmitCollector(mockField, 1);
+      expect(result).toEqual({
+        category: 'ActionCollector',
+        error: null,
+        type: 'SubmitCollector',
+        id: 'submit-key-1',
+        name: 'submit-key',
+        output: {
+          key: mockField.key,
+          label: mockField.label,
+          type: mockField.type,
+        },
+      });
+    });
+
+    it('should handle error cases properly', () => {
+      const invalidField = {} as StandardFieldValue;
+      const result = returnSubmitCollector(invalidField, 1);
+      expect(result.error).toContain('Key is not found');
+      expect(result.type).toBe('SubmitCollector');
+    });
+  });
+
+  const mockField: StandardFieldValue = {
     key: 'testKey',
     label: 'Test Label',
-    type: 'TestType',
+    type: 'TEXT',
   };
 
-  it('should return a valid FlowCollector with all parameters provided', () => {
-    const idx = 1;
-    const collectorType = 'SubmitCollector';
-    const result = returnActionCollector(mockField, idx, collectorType);
-
-    expect(result).toEqual({
-      category: 'ActionCollector',
-      error: null,
-      type: collectorType,
-      id: `${mockField.key}-${idx}`,
-      name: mockField.key,
-      output: {
-        key: mockField.key,
-        label: mockField.label,
-        type: mockField.type,
+  const socialLoginField: DaVinciField = {
+    key: 'google-login',
+    label: 'Login with Google',
+    type: 'SOCIAL_LOGIN_BUTTON',
+    links: {
+      authenticate: {
+        href: 'https://auth.example.com/google',
       },
+    },
+  };
+
+  describe('returnActionCollector', () => {
+    it('should return a valid ActionCollector with all parameters provided', () => {
+      const result = returnActionCollector(mockField, 1, 'ActionCollector');
+      expect(result).toEqual({
+        category: 'ActionCollector',
+        error: null,
+        type: 'ActionCollector',
+        id: 'testKey-1',
+        name: 'testKey',
+        output: {
+          key: mockField.key,
+          label: mockField.label,
+          type: mockField.type,
+        },
+      });
     });
-  });
 
-  it('should return a valid FlowCollector with all parameters provided', () => {
-    const idx = 1;
-    const collectorType = 'FlowCollector';
-    const result = returnActionCollector(mockField, idx, collectorType);
-
-    expect(result).toEqual({
-      category: 'ActionCollector',
-      error: null,
-      type: collectorType,
-      id: `${mockField.key}-${idx}`,
-      name: mockField.key,
-      output: {
-        key: mockField.key,
-        label: mockField.label,
-        type: mockField.type,
-      },
+    it('should return a valid SubmitCollector', () => {
+      const result = returnActionCollector(mockField, 1, 'SubmitCollector');
+      expect(result).toEqual({
+        category: 'ActionCollector',
+        error: null,
+        type: 'SubmitCollector',
+        id: 'testKey-1',
+        name: 'testKey',
+        output: {
+          key: mockField.key,
+          label: mockField.label,
+          type: mockField.type,
+        },
+      });
     });
-  });
 
-  it('should default to "ActionCollector" type when collectorType is not provided', () => {
-    const idx = 2;
-    const result = returnActionCollector(mockField, idx, 'ActionCollector');
-    expect(result.type).toEqual('ActionCollector');
-  });
+    it('should return a valid FlowCollector', () => {
+      const result = returnActionCollector(mockField, 1, 'FlowCollector');
+      expect(result).toEqual({
+        category: 'ActionCollector',
+        error: null,
+        type: 'FlowCollector',
+        id: 'testKey-1',
+        name: 'testKey',
+        output: {
+          key: mockField.key,
+          label: mockField.label,
+          type: mockField.type,
+        },
+      });
+    });
+
+    it('creates a social login collector with URL', () => {
+      const result = returnActionCollector(socialLoginField, 1, 'SocialLoginCollector');
+      expect(result).toEqual({
+        category: 'ActionCollector',
+        error: null,
+        type: 'SocialLoginCollector',
+        id: 'google-login-1',
+        name: 'google-login',
+        output: {
+          key: 'google-login',
+          label: 'Login with Google',
+          type: 'SOCIAL_LOGIN_BUTTON',
+          url: 'https://auth.example.com/google',
+        },
+      });
+    });
 
-  // Just test runtime issues with field
-  it('should return an error message when field is missing key, label, or type', () => {
-    const field = {};
-    const idx = 3;
-    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-    // @ts-ignore-next-line
-    const result = returnActionCollector(field, idx);
-    expect(result.error).toBe(
-      'Key is not found in the field object. Label is not found in the field object. Type is not found in the field object. ',
-    );
+    it('handles missing authentication URL for social login', () => {
+      const result = returnActionCollector(mockField, 1, 'SocialLoginCollector');
+      expect(result.output.url).toBeNull();
+    });
+
+    it('should return an error message when field is missing key, label, or type', () => {
+      const field = {};
+      const idx = 3;
+      const result = returnActionCollector(field, idx, 'ActionCollector');
+      expect(result.error).toBe(
+        'Key is not found in the field object. Label is not found in the field object. Type is not found in the field object. ',
+      );
+    });
   });
 });
 
-describe('The returnSingleValueCollector function', () => {
+describe('Single Value Collectors', () => {
   const mockField: DaVinciField = {
     key: 'testKey',
     label: 'Test Label',
-    type: 'TestType',
+    type: 'TEXT',
   };
 
-  it('should return a valid SingleValueCollector with all parameters provided', () => {
-    const idx = 1;
-    const collectorType = 'PasswordCollector';
-    const result = returnSingleValueCollector(mockField, idx, collectorType);
-
-    expect(result).toEqual({
-      category: 'SingleValueCollector',
-      error: null,
-      type: collectorType,
-      id: `${mockField.key}-${idx}`,
-      name: mockField.key,
-      input: {
-        key: mockField.key,
-        value: '',
-        type: mockField.type,
-      },
-      output: {
-        key: mockField.key,
-        label: mockField.label,
-        type: mockField.type,
-      },
+  describe('returnSingleValueCollector', () => {
+    it('should return a valid SingleValueCollector with value in output', () => {
+      const result = returnSingleValueCollector(mockField, 1, 'SingleValueCollector');
+      expect(result).toEqual({
+        category: 'SingleValueCollector',
+        error: null,
+        type: 'SingleValueCollector',
+        id: 'testKey-1',
+        name: 'testKey',
+        input: {
+          key: mockField.key,
+          value: '',
+          type: mockField.type,
+        },
+        output: {
+          key: mockField.key,
+          label: mockField.label,
+          type: mockField.type,
+          value: '',
+        },
+      });
     });
-  });
 
-  it('should return a valid SingleValueCollector with all parameters provided', () => {
-    const idx = 1;
-    const collectorType = 'TextCollector';
-    const result = returnSingleValueCollector(mockField, idx, collectorType);
-
-    expect(result).toEqual({
-      category: 'SingleValueCollector',
-      error: null,
-      type: collectorType,
-      id: `${mockField.key}-${idx}`,
-      name: mockField.key,
-      input: {
-        key: mockField.key,
-        value: '',
-        type: mockField.type,
-      },
-      output: {
-        key: mockField.key,
-        label: mockField.label,
-        type: mockField.type,
-        value: '',
-      },
+    it('should return a valid PasswordCollector without value in output', () => {
+      const result = returnSingleValueCollector(mockField, 1, 'PasswordCollector');
+      expect(result).toEqual({
+        category: 'SingleValueCollector',
+        error: null,
+        type: 'PasswordCollector',
+        id: 'testKey-1',
+        name: 'testKey',
+        input: {
+          key: mockField.key,
+          value: '',
+          type: mockField.type,
+        },
+        output: {
+          key: mockField.key,
+          label: mockField.label,
+          type: mockField.type,
+        },
+      });
+      expect(result.output).not.toHaveProperty('value');
     });
-  });
 
-  it('should default to "SingleValueCollector" type when collectorType is not provided', () => {
-    const idx = 2;
-    const result = returnSingleValueCollector(mockField, idx, 'SingleValueCollector');
-    expect(result.type).toEqual('SingleValueCollector');
+    it('should return an error message when field is missing key, label, or type', () => {
+      const field = {};
+      const idx = 3;
+      const result = returnSingleValueCollector(field, idx, 'SingleValueCollector');
+      expect(result.error).toBe(
+        'Key is not found in the field object. Label is not found in the field object. Type is not found in the field object. ',
+      );
+    });
   });
 
-  // Just test runtime issues with field
-  it('should return an error message when field is missing key, label, or type', () => {
-    const field = {};
-    const idx = 3;
-    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-    // @ts-ignore-next-line
-    const result = returnSingleValueCollector(field, idx);
-    expect(result.error).toBe(
-      'Key is not found in the field object. Label is not found in the field object. Type is not found in the field object. ',
-    );
+  describe('Specialized Single Value Collectors', () => {
+    it('creates a password collector', () => {
+      const result = returnPasswordCollector(mockField, 1);
+      expect(result.type).toBe('PasswordCollector');
+      expect(result.output).not.toHaveProperty('value');
+    });
+
+    it('creates a text collector', () => {
+      const result = returnTextCollector(mockField, 1);
+      expect(result.type).toBe('TextCollector');
+      expect(result.output).toHaveProperty('value', '');
+    });
+
+    it('creates a single select collector from radio field type', () => {
+      const field: DaVinciField = {
+        type: 'RADIO',
+        key: 'radio-field',
+        label: 'Radio',
+        required: true,
+        options: [
+          {
+            label: 'radio1',
+            value: 'radio1',
+          },
+          {
+            label: 'radio2',
+            value: 'radio2',
+          },
+        ],
+        inputType: 'SINGLE_SELECT',
+      };
+      const result = returnSingleSelectCollector(field, 1);
+      expect(result.type).toBe('SingleSelectCollector');
+      expect(result.output).toHaveProperty('value', '');
+    });
+
+    it('creates a single select collector from dropdown field type', () => {
+      const field: DaVinciField = {
+        type: 'DROPDOWN',
+        key: 'dropdown-field',
+        label: 'Dropdown',
+        required: true,
+        options: [
+          {
+            label: 'dropdown1',
+            value: 'dropdown1',
+          },
+          {
+            label: 'dropdown2',
+            value: 'dropdown2',
+          },
+          {
+            label: 'dropdown3',
+            value: 'dropdown3',
+          },
+        ],
+        inputType: 'SINGLE_SELECT',
+      };
+      const result = returnSingleSelectCollector(field, 1);
+      expect(result.type).toBe('SingleSelectCollector');
+      expect(result.output).toHaveProperty('value', '');
+    });
+
+    it('creates a multi-select collector from combobox field type', () => {
+      const comboField: DaVinciField = {
+        type: 'COMBOBOX',
+        key: 'combobox-field',
+        label: 'Combobox',
+        required: true,
+        options: [
+          {
+            label: 'combobox1',
+            value: 'combobox1',
+          },
+          {
+            label: 'combobox2',
+            value: 'combobox2',
+          },
+        ],
+        inputType: 'MULTI_SELECT',
+      };
+      const result = returnMultiSelectCollector(comboField, 1);
+      expect(result.type).toBe('MultiSelectCollector');
+      expect(result.output).toHaveProperty('value', []);
+    });
+
+    it('creates an action collector from flow link field type', () => {
+      const result = returnFlowCollector(mockField, 1);
+      expect(result.type).toBe('FlowCollector');
+      expect(result.output).not.toHaveProperty('value');
+    });
   });
 });
diff --git a/packages/davinci-client/src/lib/collector.utils.ts b/packages/davinci-client/src/lib/collector.utils.ts
index 8cdc2418..b05d58c0 100644
--- a/packages/davinci-client/src/lib/collector.utils.ts
+++ b/packages/davinci-client/src/lib/collector.utils.ts
@@ -4,10 +4,18 @@
 import type {
   ActionCollectors,
   ActionCollectorTypes,
-  SingleValueCollectors,
+  InferSingleValueCollectorType,
+  InferMultiValueCollectorType,
   SingleValueCollectorTypes,
+  MultiValueCollectorTypes,
+  InferActionCollectorType,
 } from './collector.types';
-import type { DaVinciField } from './davinci.types';
+import type {
+  DaVinciField,
+  MultiSelect,
+  SingleSelect,
+  StandardFieldValue,
+} from './davinci.types.js';
 
 /**
  * @function returnActionCollector - Creates an ActionCollector object based on the provided field and index.
@@ -17,7 +25,7 @@ import type { DaVinciField } from './davinci.types';
  * @returns {ActionCollector} The constructed ActionCollector object.
  */
 export function returnActionCollector<CollectorType extends ActionCollectorTypes>(
-  field: DaVinciField,
+  field: StandardFieldValue,
   idx: number,
   collectorType: CollectorType,
 ): ActionCollectors {
@@ -45,7 +53,7 @@ export function returnActionCollector<CollectorType extends ActionCollectorTypes
         type: field.type,
         url: field.links?.['authenticate']?.href || null,
       },
-    };
+    } as InferActionCollectorType<CollectorType>;
   } else {
     return {
       category: 'ActionCollector',
@@ -58,7 +66,7 @@ export function returnActionCollector<CollectorType extends ActionCollectorTypes
         label: field.label,
         type: field.type,
       },
-    };
+    } as InferActionCollectorType<CollectorType>;
   }
 }
 
@@ -68,8 +76,7 @@ export function returnActionCollector<CollectorType extends ActionCollectorTypes
  * @param {number} idx - The index of the field in the form
  * @returns {FlowCollector} - The flow collector object
  */
-
-export function returnFlowCollector(field: DaVinciField, idx: number) {
+export function returnFlowCollector(field: StandardFieldValue, idx: number) {
   return returnActionCollector(field, idx, 'FlowCollector');
 }
 
@@ -79,7 +86,7 @@ export function returnFlowCollector(field: DaVinciField, idx: number) {
  * @param {number} idx - The index of the field in the form
  * @returns {SocialLoginCollector} - The social login collector object
  */
-export function returnSocialLoginCollector(field: DaVinciField, idx: number) {
+export function returnSocialLoginCollector(field: StandardFieldValue, idx: number) {
   return returnActionCollector(field, idx, 'SocialLoginCollector');
 }
 
@@ -89,7 +96,7 @@ export function returnSocialLoginCollector(field: DaVinciField, idx: number) {
  * @param {number} idx - The index of the field in the form
  * @returns {ActionCollector} - The submit collector object
  */
-export function returnSubmitCollector(field: DaVinciField, idx: number) {
+export function returnSubmitCollector(field: StandardFieldValue, idx: number) {
   return returnActionCollector(field, idx, 'SubmitCollector');
 }
 
@@ -101,8 +108,9 @@ export function returnSubmitCollector(field: DaVinciField, idx: number) {
  * @returns {SingleValueCollector} The constructed SingleValueCollector object.
  */
 export function returnSingleValueCollector<
+  Field extends DaVinciField,
   CollectorType extends SingleValueCollectorTypes = 'SingleValueCollector',
->(field: DaVinciField, idx: number, collectorType: CollectorType): SingleValueCollectors {
+>(field: Field, idx: number, collectorType: CollectorType) {
   let error = '';
   if (!('key' in field)) {
     error = `${error}Key is not found in the field object. `;
@@ -119,6 +127,32 @@ export function returnSingleValueCollector<
       category: 'SingleValueCollector',
       error: error || null,
       type: collectorType,
+      id: `${field?.key || field.type}-${idx}`,
+      name: field.key,
+      input: {
+        key: field.key,
+        value: '',
+        type: field.type,
+      },
+      output: {
+        key: field.key,
+        label: field.label,
+        type: field.type,
+      },
+    } as InferSingleValueCollectorType<CollectorType>;
+  } else if (collectorType === 'SingleSelectCollector') {
+    /**
+     * Check if options are present in the field object first
+     * If found, return existing error, which should be ''
+     * If not found, add additional message to error string
+     */
+    const err = 'options' in field ? error : `${error}Options are not found in the field object. `;
+    const options = 'options' in field ? field.options : []; // Fallback to ensure type consistency
+
+    return {
+      category: 'SingleValueCollector',
+      error: err || null,
+      type: collectorType,
       id: `${field.key}-${idx}`,
       name: field.key,
       input: {
@@ -130,8 +164,10 @@ export function returnSingleValueCollector<
         key: field.key,
         label: field.label,
         type: field.type,
+        value: '',
+        options: options,
       },
-    };
+    } as InferSingleValueCollectorType<CollectorType>;
   } else {
     return {
       category: 'SingleValueCollector',
@@ -150,7 +186,7 @@ export function returnSingleValueCollector<
         type: field.type,
         value: '',
       },
-    };
+    } as InferSingleValueCollectorType<CollectorType>;
   }
 }
 
@@ -160,7 +196,7 @@ export function returnSingleValueCollector<
  * @param {number} idx - The index to be used in the id of the PasswordCollector.
  * @returns {PasswordCollector} The constructed PasswordCollector object.
  */
-export function returnPasswordCollector(field: DaVinciField, idx: number) {
+export function returnPasswordCollector(field: StandardFieldValue, idx: number) {
   return returnSingleValueCollector(field, idx, 'PasswordCollector');
 }
 
@@ -170,6 +206,71 @@ export function returnPasswordCollector(field: DaVinciField, idx: number) {
  * @param {number} idx - The index to be used in the id of the TextCollector.
  * @returns {TextCollector} The constructed TextCollector object.
  */
-export function returnTextCollector(field: DaVinciField, idx: number) {
+export function returnTextCollector(field: StandardFieldValue, idx: number) {
   return returnSingleValueCollector(field, idx, 'TextCollector');
 }
+/**
+ * @function returnSingleSelectCollector - Creates a SingleCollector object based on the provided field and index.
+ * @param {DaVinciField} field - The field object containing key, label, type, and links.
+ * @param {number} idx - The index to be used in the id of the SingleCollector.
+ * @returns {SingleValueCollector} The constructed SingleCollector object.
+ */
+export function returnSingleSelectCollector(field: SingleSelect, idx: number) {
+  return returnSingleValueCollector(field, idx, 'SingleSelectCollector');
+}
+
+/**
+ * @function returnMultiValueCollector - Creates a MultiValueCollector object based on the provided field, index, and optional collector type.
+ * @param {DaVinciField} field - The field object containing key, label, type, and links.
+ * @param {number} idx - The index to be used in the id of the MultiValueCollector.
+ * @param {MultiValueCollectorTypes} [collectorType] - Optional type of the MultiValueCollector.
+ * @returns {MultiValueCollector} The constructed MultiValueCollector object.
+ */
+export function returnMultiValueCollector<
+  Field extends MultiSelect,
+  CollectorType extends MultiValueCollectorTypes = 'MultiValueCollector',
+>(field: Field, idx: number, collectorType: CollectorType) {
+  let error = '';
+  if (!('key' in field)) {
+    error = `${error}Key is not found in the field object. `;
+  }
+  if (!('label' in field)) {
+    error = `${error}Label is not found in the field object. `;
+  }
+  if (!('type' in field)) {
+    error = `${error}Type is not found in the field object. `;
+  }
+  if (!('options' in field)) {
+    error = `${error}Options are not found in the field object. `;
+  }
+
+  return {
+    category: 'MultiValueCollector',
+    error: error || null,
+    type: collectorType || 'MultiValueCollector',
+    id: `${field.key}-${idx}`,
+    name: field.key,
+    input: {
+      key: field.key,
+      value: [],
+      type: field.type,
+    },
+    output: {
+      key: field.key,
+      label: field.label,
+      type: field.type,
+      value: [],
+      options: field.options || [],
+    },
+  } as InferMultiValueCollectorType<CollectorType>;
+}
+
+/**
+ * @function returnMultiSelectCollector - Creates a DropDownCollector object based on the provided field and index.
+ * @param {DaVinciField} field - The field object containing key, label, type, and links.
+ * @param {number} idx - The index to be used in the id of the DropDownCollector.
+ * @returns {SingleValueCollector} The constructed DropDownCollector object.
+ */
+export function returnMultiSelectCollector(field: MultiSelect, idx: number) {
+  return returnMultiValueCollector(field, idx, 'MultiSelectCollector');
+}
diff --git a/packages/davinci-client/src/lib/config.types.test-d.ts b/packages/davinci-client/src/lib/config.types.test-d.ts
new file mode 100644
index 00000000..dc0528b2
--- /dev/null
+++ b/packages/davinci-client/src/lib/config.types.test-d.ts
@@ -0,0 +1,267 @@
+import { describe, expectTypeOf, it } from 'vitest';
+import type { DaVinciConfig, InternalDaVinciConfig } from './config.types.js';
+import type { AsyncConfigOptions } from '@forgerock/javascript-sdk/src/config/interfaces';
+import type { WellknownResponse } from './wellknown.types.js';
+
+describe('Config Types', () => {
+  describe('DaVinciConfig', () => {
+    it('should extend AsyncConfigOptions', () => {
+      expectTypeOf<DaVinciConfig>().toMatchTypeOf<AsyncConfigOptions>();
+    });
+
+    it('should have optional responseType', () => {
+      const config: DaVinciConfig = {
+        responseType: 'code',
+        serverConfig: {},
+      };
+      expectTypeOf(typeof config['responseType']).toBeString();
+      expectTypeOf<DaVinciConfig>().toHaveProperty('responseType').toBeNullable();
+    });
+
+    it('should allow AsyncConfigOptions properties', () => {
+      const config: DaVinciConfig = {
+        clientId: 'test-client',
+        scope: 'openid profile',
+        serverConfig: {
+          wellknown: 'https://example.com',
+          timeout: 30000,
+        },
+        redirectUri: 'https://app.example.com/callback',
+        responseType: 'code',
+      };
+      expectTypeOf(config).toMatchTypeOf<DaVinciConfig>();
+    });
+  });
+
+  describe('InternalDaVinciConfig', () => {
+    it('should extend DaVinciConfig', () => {
+      expectTypeOf<InternalDaVinciConfig>().toMatchTypeOf<DaVinciConfig>();
+    });
+
+    it('should require wellknownResponse', () => {
+      const config: InternalDaVinciConfig = {
+        wellknownResponse: {
+          issuer: 'https://example.com',
+          authorization_endpoint: 'https://example.com/auth',
+          token_endpoint: 'https://example.com/token',
+          userinfo_endpoint: 'https://example.com/userinfo',
+          jwks_uri: 'https://example.com/jwks',
+          revocation_endpoint: 'https://example.com/register',
+          end_session_endpoint: 'https://example.com/logout',
+          pushed_authorization_request_endpoint: '',
+          check_session_iframe: '',
+          introspection_endpoint: '',
+          device_authorization_endpoint: '',
+          claims_parameter_supported: '',
+          request_parameter_supported: '',
+          request_uri_parameter_supported: '',
+          require_pushed_authorization_requests: '',
+          scopes_supported: [],
+          response_types_supported: [],
+          response_modes_supported: [],
+          grant_types_supported: [],
+          subject_types_supported: [],
+          id_token_signing_alg_values_supported: [],
+          userinfo_signing_alg_values_supported: [],
+          request_object_signing_alg_values_supported: [],
+          token_endpoint_auth_methods_supported: [],
+          token_endpoint_auth_signing_alg_values_supported: [],
+          claim_types_supported: [],
+          claims_supported: [],
+          code_challenge_methods_supported: [],
+        },
+        responseType: 'code',
+        serverConfig: {},
+      };
+      expectTypeOf(config).toMatchTypeOf<InternalDaVinciConfig>();
+      expectTypeOf<InternalDaVinciConfig>().toHaveProperty('wellknownResponse').toBeObject;
+    });
+
+    it('should combine DaVinciConfig and wellknownResponse', () => {
+      const config: InternalDaVinciConfig = {
+        // DaVinciConfig properties
+        clientId: 'test-client',
+        scope: 'openid profile',
+        serverConfig: {
+          wellknown: 'https://example.com',
+          timeout: 30000,
+        },
+        redirectUri: 'https://app.example.com/callback',
+        responseType: 'code',
+        // InternalDaVinciConfig specific property
+        wellknownResponse: {
+          issuer: 'https://example.com',
+          authorization_endpoint: 'https://example.com/auth',
+          token_endpoint: 'https://example.com/token',
+          userinfo_endpoint: 'https://example.com/userinfo',
+          jwks_uri: 'https://example.com/jwks',
+          revocation_endpoint: 'https://example.com/revoke',
+          end_session_endpoint: 'https://example.com/logout',
+          pushed_authorization_request_endpoint: '',
+          check_session_iframe: '',
+          introspection_endpoint: '',
+          device_authorization_endpoint: '',
+          claims_parameter_supported: '',
+          request_parameter_supported: '',
+          request_uri_parameter_supported: '',
+          require_pushed_authorization_requests: '',
+          scopes_supported: [],
+          response_types_supported: [],
+          response_modes_supported: [],
+          grant_types_supported: [],
+          subject_types_supported: [],
+          id_token_signing_alg_values_supported: [],
+          userinfo_signing_alg_values_supported: [],
+          request_object_signing_alg_values_supported: [],
+          token_endpoint_auth_methods_supported: [],
+          token_endpoint_auth_signing_alg_values_supported: [],
+          claim_types_supported: [],
+          claims_supported: [],
+          code_challenge_methods_supported: [],
+        },
+      };
+      expectTypeOf(config).toMatchTypeOf<InternalDaVinciConfig>();
+    });
+  });
+});
+
+describe('WellknownResponse', () => {
+  it('should have all required OIDC properties', () => {
+    const wellknown: WellknownResponse = {
+      issuer: 'https://example.com',
+      authorization_endpoint: 'https://example.com/auth',
+      token_endpoint: 'https://example.com/token',
+      userinfo_endpoint: 'https://example.com/userinfo',
+      jwks_uri: 'https://example.com/jwks',
+      revocation_endpoint: 'https://example.com/revoke',
+      end_session_endpoint: 'https://example.com/logout',
+      pushed_authorization_request_endpoint: '',
+      check_session_iframe: '',
+      introspection_endpoint: '',
+      device_authorization_endpoint: '',
+      claims_parameter_supported: '',
+      request_parameter_supported: '',
+      request_uri_parameter_supported: '',
+      require_pushed_authorization_requests: '',
+      scopes_supported: [],
+      response_types_supported: [],
+      response_modes_supported: [],
+      grant_types_supported: [],
+      subject_types_supported: [],
+      id_token_signing_alg_values_supported: [],
+      userinfo_signing_alg_values_supported: [],
+      request_object_signing_alg_values_supported: [],
+      token_endpoint_auth_methods_supported: [],
+      token_endpoint_auth_signing_alg_values_supported: [],
+      claim_types_supported: [],
+      claims_supported: [],
+      code_challenge_methods_supported: [],
+    };
+
+    expectTypeOf<WellknownResponse>().toHaveProperty('issuer').toBeString();
+    expectTypeOf<WellknownResponse>().toHaveProperty('authorization_endpoint').toBeString();
+    expectTypeOf<WellknownResponse>().toHaveProperty('token_endpoint').toBeString();
+    expectTypeOf<WellknownResponse>().toHaveProperty('userinfo_endpoint').toBeString();
+    expectTypeOf<WellknownResponse>().toHaveProperty('jwks_uri').toBeString();
+    expectTypeOf<WellknownResponse>().toHaveProperty('revocation_endpoint').toBeString();
+    expectTypeOf<WellknownResponse>().toHaveProperty('end_session_endpoint').toBeString();
+
+    expectTypeOf(wellknown).toMatchTypeOf<WellknownResponse>();
+  });
+
+  it('should allow optional OIDC properties', () => {
+    const wellknownWithOptionals: WellknownResponse = {
+      issuer: 'https://example.com',
+      authorization_endpoint: 'https://example.com/auth',
+      token_endpoint: 'https://example.com/token',
+      userinfo_endpoint: 'https://example.com/userinfo',
+      jwks_uri: 'https://example.com/jwks',
+      revocation_endpoint: 'https://example.com/revoke',
+      end_session_endpoint: 'https://example.com/logout',
+      // Optional properties
+      scopes_supported: ['openid', 'profile', 'email'],
+      response_types_supported: ['code', 'token'],
+      grant_types_supported: ['authorization_code', 'refresh_token'],
+      subject_types_supported: ['public'],
+      id_token_signing_alg_values_supported: ['RS256'],
+      token_endpoint_auth_methods_supported: ['client_secret_basic'],
+      pushed_authorization_request_endpoint: '',
+      check_session_iframe: '',
+      introspection_endpoint: '',
+      device_authorization_endpoint: '',
+      claims_parameter_supported: '',
+      request_parameter_supported: '',
+      request_uri_parameter_supported: '',
+      require_pushed_authorization_requests: '',
+      response_modes_supported: [],
+      userinfo_signing_alg_values_supported: [],
+      request_object_signing_alg_values_supported: [],
+      token_endpoint_auth_signing_alg_values_supported: [],
+      claim_types_supported: [],
+      claims_supported: [],
+      code_challenge_methods_supported: [],
+    };
+
+    // Test optional properties are allowed but not required
+    expectTypeOf<WellknownResponse>().toHaveProperty('scopes_supported');
+    expectTypeOf<WellknownResponse>().toHaveProperty('response_types_supported');
+    expectTypeOf<WellknownResponse>().toHaveProperty('grant_types_supported');
+
+    expectTypeOf(wellknownWithOptionals).toMatchTypeOf<WellknownResponse>();
+  });
+
+  it('should validate property types', () => {
+    // Test that array properties must contain strings
+    expectTypeOf<WellknownResponse['scopes_supported']>().toEqualTypeOf<string[]>();
+    expectTypeOf<WellknownResponse['response_types_supported']>().toEqualTypeOf<string[]>();
+    expectTypeOf<WellknownResponse['grant_types_supported']>().toEqualTypeOf<string[]>();
+    expectTypeOf<WellknownResponse['subject_types_supported']>().toEqualTypeOf<string[]>();
+    expectTypeOf<WellknownResponse['id_token_signing_alg_values_supported']>().toEqualTypeOf<
+      string[]
+    >();
+    expectTypeOf<WellknownResponse['token_endpoint_auth_methods_supported']>().toEqualTypeOf<
+      string[]
+    >();
+  });
+
+  it('should enforce URL format for endpoint properties', () => {
+    const wellknown: WellknownResponse = {
+      issuer: 'https://example.com',
+      authorization_endpoint: 'https://example.com/auth',
+      token_endpoint: 'https://example.com/token',
+      userinfo_endpoint: 'https://example.com/userinfo',
+      jwks_uri: 'https://example.com/jwks',
+      revocation_endpoint: 'https://example.com/register',
+      end_session_endpoint: 'https://example.com/logout',
+      pushed_authorization_request_endpoint: '',
+      check_session_iframe: '',
+      introspection_endpoint: '',
+      device_authorization_endpoint: '',
+      claims_parameter_supported: '',
+      request_parameter_supported: '',
+      request_uri_parameter_supported: '',
+      require_pushed_authorization_requests: '',
+      scopes_supported: [],
+      response_types_supported: [],
+      response_modes_supported: [],
+      grant_types_supported: [],
+      subject_types_supported: [],
+      id_token_signing_alg_values_supported: [],
+      userinfo_signing_alg_values_supported: [],
+      request_object_signing_alg_values_supported: [],
+      token_endpoint_auth_methods_supported: [],
+      token_endpoint_auth_signing_alg_values_supported: [],
+      claim_types_supported: [],
+      claims_supported: [],
+      code_challenge_methods_supported: [],
+    };
+
+    // Type assertion to ensure all endpoint properties are strings (URLs)
+    expectTypeOf(wellknown.authorization_endpoint).toBeString();
+    expectTypeOf(wellknown.token_endpoint).toBeString();
+    expectTypeOf(wellknown.userinfo_endpoint).toBeString();
+    expectTypeOf(wellknown.jwks_uri).toBeString();
+    expectTypeOf(wellknown.revocation_endpoint).toBeString();
+    expectTypeOf(wellknown.end_session_endpoint).toBeString();
+  });
+});
diff --git a/packages/davinci-client/src/lib/config.types.ts b/packages/davinci-client/src/lib/config.types.ts
index cd26483b..f7875cb1 100644
--- a/packages/davinci-client/src/lib/config.types.ts
+++ b/packages/davinci-client/src/lib/config.types.ts
@@ -2,7 +2,7 @@
  * Import ConfigOptions type from the JavaScript SDK
  */
 import type { AsyncConfigOptions } from '@forgerock/javascript-sdk/src/config/interfaces';
-import { WellknownResponse } from './wellknown.types';
+import { WellknownResponse } from './wellknown.types.js';
 
 export interface DaVinciConfig extends AsyncConfigOptions {
   responseType?: string;
diff --git a/packages/davinci-client/src/lib/davinci.api.ts b/packages/davinci-client/src/lib/davinci.api.ts
index b021cb8f..472cc467 100644
--- a/packages/davinci-client/src/lib/davinci.api.ts
+++ b/packages/davinci-client/src/lib/davinci.api.ts
@@ -14,7 +14,7 @@ import { handleResponse, transformActionRequest, transformSubmitRequest } from '
  * Import the DaVinci types
  */
 import type { RootStateWithNode } from './client.store.utils.js';
-import type { DaVinciCacheEntry, ThrownQueryError } from './davinci.types';
+import type { DaVinciCacheEntry, ThrownQueryError } from './davinci.types.js';
 import type { ContinueNode } from './node.types.js';
 import type { StartNode } from '../types.js';
 
diff --git a/packages/davinci-client/src/lib/davinci.types.ts b/packages/davinci-client/src/lib/davinci.types.ts
index fd9781e4..1cd1815c 100644
--- a/packages/davinci-client/src/lib/davinci.types.ts
+++ b/packages/davinci-client/src/lib/davinci.types.ts
@@ -46,18 +46,52 @@ export interface Links {
   };
 }
 
-/**
- * Next or Continuation Response DaVinci API
- */
-
-export interface DaVinciField {
-  type: string;
+export type StandardFieldValue = {
+  type:
+    | 'PASSWORD'
+    | 'TEXT'
+    | 'SUBMIT_BUTTON'
+    | 'FLOW_BUTTON'
+    | 'FLOW_LINK'
+    | 'SOCIAL_LOGIN_BUTTON'
+    | 'BUTTON';
   key: string;
   label: string;
 
   // Optional properties
   links?: Links;
-}
+};
+
+export type SingleSelect = {
+  inputType: 'SINGLE_SELECT';
+  key: string;
+  label: string;
+  options: {
+    label: string;
+    value: string | number;
+  }[];
+  required?: boolean;
+  type: 'RADIO' | 'DROPDOWN';
+};
+
+export type MultiSelect = {
+  inputType: 'MULTI_SELECT';
+  key: string;
+  label: string;
+  options: {
+    label: string;
+    value: string | number;
+  }[];
+  required?: boolean;
+  type: 'CHECKBOX' | 'COMBOBOX';
+};
+
+export type DaVinciField = StandardFieldValue | SingleSelect | MultiSelect;
+
+/**
+ * Next or Continuation Response DaVinci API
+ */
+
 export interface DaVinciNextResponse extends DaVinciBaseResponse {
   // Optional properties
   _links?: Links;
diff --git a/packages/davinci-client/src/lib/davinci.utils.ts b/packages/davinci-client/src/lib/davinci.utils.ts
index 93e62971..208a4596 100644
--- a/packages/davinci-client/src/lib/davinci.utils.ts
+++ b/packages/davinci-client/src/lib/davinci.utils.ts
@@ -3,7 +3,7 @@
  */
 import type { Dispatch } from '@reduxjs/toolkit';
 
-import { nodeSlice } from './node.slice';
+import { nodeSlice } from './node.slice.js';
 
 import type {
   DaVinciCacheEntry,
@@ -172,7 +172,6 @@ export function handleResponse(cacheEntry: DaVinciCacheEntry, dispatch: Dispatch
    */
   if (cacheEntry.isSuccess) {
     const requestId = cacheEntry.requestId;
-
     if ('eventName' in cacheEntry.data && cacheEntry.data.eventName === 'continue') {
       const data = cacheEntry.data as DaVinciNextResponse;
       dispatch(nodeSlice.actions.next({ data, requestId, httpStatus: status }));
diff --git a/packages/davinci-client/src/lib/error.types.test-d.ts b/packages/davinci-client/src/lib/error.types.test-d.ts
new file mode 100644
index 00000000..b658107c
--- /dev/null
+++ b/packages/davinci-client/src/lib/error.types.test-d.ts
@@ -0,0 +1,61 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+import { describe, expect, it } from 'vitest';
+import type { GenericError } from './error.types.js';
+
+describe('GenericError type', () => {
+  it('should allow valid error objects', () => {
+    const validErrors: GenericError[] = [
+      {
+        message: 'Something went wrong',
+        type: 'unknown_error',
+      },
+      {
+        code: 404,
+        message: 'Not found',
+        type: 'network_error',
+      },
+      {
+        code: 'ERR_001',
+        message: 'Invalid argument',
+        type: 'argument_error',
+      },
+      {
+        message: 'Internal server error',
+        type: 'internal_error',
+      },
+      {
+        message: 'Invalid state',
+        type: 'state_error',
+      },
+      {
+        message: 'Davinci specific error',
+        type: 'davinci_error',
+      },
+    ];
+
+    // TypeScript will validate these assignments
+    validErrors.forEach((error) => {
+      expect(error.message).toBeDefined();
+      expect(error.type).toBeDefined();
+    });
+  });
+
+  // This test is just for TypeScript compilation validation
+  it('should enforce required properties', () => {
+    // @ts-expect-error - message is required
+    const missingMessage: GenericError = {
+      type: 'unknown_error',
+    };
+
+    // @ts-expect-error - type is required
+    const missingType: GenericError = {
+      message: 'Error message',
+    };
+
+    const invalidType: GenericError = {
+      message: 'Error message',
+      // @ts-expect-error - invalid type error below
+      type: 'invalid_type',
+    };
+  });
+});
diff --git a/packages/davinci-client/src/lib/mock-data/mock-form-fields.data.ts b/packages/davinci-client/src/lib/mock-data/mock-form-fields.data.ts
new file mode 100644
index 00000000..92d32438
--- /dev/null
+++ b/packages/davinci-client/src/lib/mock-data/mock-form-fields.data.ts
@@ -0,0 +1,226 @@
+const obj = {
+  interactionId: '18fa40b7-0eb8-4a5c-803c-d3f3f807ed46',
+  companyId: '02fb4743-189a-4bc7-9d6c-a919edfe6447',
+  connectionId: '8209285e0d2f3fc76bfd23fd10d45e6f',
+  connectorId: 'pingOneFormsConnector',
+  id: '65u7m8cm28',
+  capabilityName: 'customForm',
+  showContinueButton: false,
+  form: {
+    components: {
+      fields: [
+        {
+          type: 'LABEL',
+          content: 'Sign On',
+        },
+        {
+          type: 'LABEL',
+          content: 'Welcome to Ping Identity',
+        },
+        {
+          type: 'ERROR_DISPLAY',
+        },
+        {
+          type: 'TEXT',
+          key: 'user.username',
+          label: 'Username',
+          required: true,
+          validation: {
+            regex: '^[^@]+@[^@]+\\.[^@]+$',
+            errorMessage: 'Must be valid email address',
+          },
+        },
+        {
+          type: 'PASSWORD',
+          key: 'password',
+          label: 'Password',
+          required: true,
+        },
+        {
+          type: 'SUBMIT_BUTTON',
+          label: 'Sign On',
+          key: 'submit',
+        },
+        {
+          type: 'FLOW_LINK',
+          key: 'register',
+          label: 'No account? Register now!',
+        },
+        {
+          type: 'FLOW_LINK',
+          key: 'trouble',
+          label: 'Having trouble signing on?',
+        },
+        {
+          type: 'DROPDOWN',
+          key: 'dropdown-field',
+          label: 'Dropdown',
+          required: true,
+          options: [
+            {
+              label: 'dropdown1',
+              value: 'dropdown1',
+            },
+            {
+              label: 'dropdown2',
+              value: 'dropdown2',
+            },
+            {
+              label: 'dropdown3',
+              value: 'dropdown3',
+            },
+          ],
+          inputType: 'SINGLE_SELECT',
+        },
+        {
+          type: 'COMBOBOX',
+          key: 'combobox-field',
+          label: 'Combobox',
+          required: true,
+          options: [
+            {
+              label: 'combobox1',
+              value: 'combobox1',
+            },
+            {
+              label: 'combobox2',
+              value: 'combobox2',
+            },
+          ],
+          inputType: 'MULTI_SELECT',
+        },
+        {
+          type: 'RADIO',
+          key: 'radio-field',
+          label: 'Radio',
+          required: true,
+          options: [
+            {
+              label: 'radio1',
+              value: 'radio1',
+            },
+            {
+              label: 'radio2',
+              value: 'radio2',
+            },
+          ],
+          inputType: 'SINGLE_SELECT',
+        },
+        {
+          type: 'CHECKBOX',
+          key: 'checkbox-field',
+          label: 'Checkbox',
+          required: true,
+          options: [
+            {
+              label: 'checkbox1',
+              value: 'checkbox1',
+            },
+            {
+              label: 'checkbox2',
+              value: 'checkbox2',
+            },
+          ],
+          inputType: 'MULTI_SELECT',
+        },
+      ],
+    },
+    name: 'session main - signon1',
+    description: 'session main flow - sign on form ',
+    category: 'CUSTOM_FORM',
+  },
+  theme: 'activeTheme',
+  formData: {
+    value: {
+      'user.username': '',
+      password: '',
+      'dropdown-field': '',
+      'combobox-field': '',
+      'radio-field': '',
+      'checkbox-field': '',
+    },
+  },
+  returnUrl: '',
+  enableRisk: false,
+  collectBehavioralData: false,
+  universalDeviceIdentification: false,
+  pingidAgent: false,
+  linkWithP1User: true,
+  population: 'usePopulationId',
+  buttonText: 'Submit',
+  authenticationMethodSource: 'useDefaultMfaPolicy',
+  nodeTitle: 'Sign On',
+  nodeDescription: 'Enter username and password',
+  backgroundColor: '#b7e9deff',
+  envId: '02fb4743-189a-4bc7-9d6c-a919edfe6447',
+  region: 'CA',
+  themeId: 'activeTheme',
+  formId: 'f0cf83ab-f8f4-4f4a-9260-8f7d27061fa7',
+  passwordPolicy: {
+    _links: {
+      environment: {
+        href: 'http://10.76.247.190:4140/directory-api/environments/02fb4743-189a-4bc7-9d6c-a919edfe6447',
+      },
+      self: {
+        href: 'http://10.76.247.190:4140/directory-api/environments/02fb4743-189a-4bc7-9d6c-a919edfe6447/passwordPolicies/39cad7af-3c2f-4672-9c3f-c47e5169e582',
+      },
+    },
+    id: '39cad7af-3c2f-4672-9c3f-c47e5169e582',
+    environment: {
+      id: '02fb4743-189a-4bc7-9d6c-a919edfe6447',
+    },
+    name: 'Standard',
+    description: 'A standard policy that incorporates industry best practices',
+    excludesProfileData: true,
+    notSimilarToCurrent: true,
+    excludesCommonlyUsed: true,
+    maxAgeDays: 182,
+    minAgeDays: 1,
+    maxRepeatedCharacters: 2,
+    minUniqueCharacters: 5,
+    history: {
+      count: 6,
+      retentionDays: 365,
+    },
+    lockout: {
+      failureCount: 5,
+      durationSeconds: 900,
+    },
+    length: {
+      min: 8,
+      max: 255,
+    },
+    minCharacters: {
+      '~!@#$%^&*()-_=+[]{}|;:,.<>/?': 1,
+      '0123456789': 1,
+      ABCDEFGHIJKLMNOPQRSTUVWXYZ: 1,
+      abcdefghijklmnopqrstuvwxyz: 1,
+    },
+    populationCount: 1,
+    createdAt: '2024-01-03T19:50:39.586Z',
+    updatedAt: '2024-01-03T19:50:39.586Z',
+    default: true,
+  },
+  isResponseCompatibleWithMobileAndWebSdks: true,
+  fieldTypes: [
+    'LABEL',
+    'ERROR_DISPLAY',
+    'TEXT',
+    'PASSWORD',
+    'RADIO',
+    'CHECKBOX',
+    'FLOW_LINK',
+    'COMBOBOX',
+    'DROPDOWN',
+    'SUBMIT_BUTTON',
+  ],
+  success: true,
+  interactionToken:
+    '51bfd3ad179f2f76aa01b759fcc11470a2bd4d99a4b45b72ecaba6e3e422c7dde53987bc2887f0fc590ba22ba7ae1216acce7ef4f213e79075dd73383b63c519db25e2d88840efbf4dc9eda93241d26663d9882f3d738bdbdf06702daa89a630d9bed292d76f5deec5cc0c915738d227ccff9ff8062b15a1b25a8dab8b7f7b96',
+  startUiSubFlow: true,
+  _links: {
+    next: {
+      href: 'https://auth.pingone.ca/02fb4743-189a-4bc7-9d6c-a919edfe6447/davinci/connections/8209285e0d2f3fc76bfd23fd10d45e6f/capabilities/customForm',
+    },
+  },
+};
diff --git a/packages/davinci-client/src/lib/node.reducer.test.ts b/packages/davinci-client/src/lib/node.reducer.test.ts
index e1e6a288..75c20446 100644
--- a/packages/davinci-client/src/lib/node.reducer.test.ts
+++ b/packages/davinci-client/src/lib/node.reducer.test.ts
@@ -1,7 +1,7 @@
 import { describe, it, expect } from 'vitest';
 
-import { nodeCollectorReducer } from './node.reducer';
-import { SubmitCollector, TextCollector } from './collector.types';
+import { nodeCollectorReducer } from './node.reducer.js';
+import { SubmitCollector, TextCollector } from './collector.types.js';
 
 describe('The node collector reducer', () => {
   it('should return the initial state', () => {
diff --git a/packages/davinci-client/src/lib/node.reducer.ts b/packages/davinci-client/src/lib/node.reducer.ts
index 750f7a70..3b7ddf42 100644
--- a/packages/davinci-client/src/lib/node.reducer.ts
+++ b/packages/davinci-client/src/lib/node.reducer.ts
@@ -14,11 +14,14 @@ import {
   returnSocialLoginCollector,
   returnSubmitCollector,
   returnTextCollector,
+  returnSingleSelectCollector,
+  returnMultiSelectCollector,
 } from './collector.utils.js';
-
-import type { DaVinciField } from './davinci.types';
+import type { DaVinciField } from './davinci.types.js';
 import {
   ActionCollector,
+  MultiSelectCollector,
+  SingleSelectCollector,
   FlowCollector,
   PasswordCollector,
   SingleValueCollector,
@@ -51,6 +54,8 @@ const initialCollectorValues: (
   | SubmitCollector
   | ActionCollector<'ActionCollector'>
   | SingleValueCollector<'SingleValueCollector'>
+  | SingleSelectCollector
+  | MultiSelectCollector
 )[] = [];
 
 /**
@@ -69,22 +74,29 @@ export const nodeCollectorReducer = createReducer(initialCollectorValues, (build
       const collectors = action.payload.map((field: DaVinciField, idx: number) => {
         // Specific Collectors
         switch (field.type) {
-          case 'SUBMIT_BUTTON':
-            return returnSubmitCollector(field, idx);
+          case 'CHECKBOX':
+          case 'COMBOBOX': // Intentional fall-through
+            return returnMultiSelectCollector(field, idx);
+          case 'DROPDOWN':
+          case 'RADIO': // Intentional fall-through
+            return returnSingleSelectCollector(field, idx);
           case 'FLOW_BUTTON':
+          case 'FLOW_LINK': // Intentional fall-through
             return returnFlowCollector(field, idx);
-          case 'SOCIAL_LOGIN_BUTTON':
-            return returnSocialLoginCollector(field, idx);
           case 'PASSWORD':
             return returnPasswordCollector(field, idx);
           case 'TEXT':
             return returnTextCollector(field, idx);
+          case 'SOCIAL_LOGIN_BUTTON':
+            return returnSocialLoginCollector(field, idx);
+          case 'SUBMIT_BUTTON':
+            return returnSubmitCollector(field, idx);
           default:
           // Default is handled below
         }
 
         // Generic Collectors
-        if (field.type.includes('BUTTON')) {
+        if (field.type.includes('BUTTON') || field.type.includes('LINK')) {
           return returnActionCollector(field, idx, 'ActionCollector');
         }
 
diff --git a/packages/davinci-client/src/lib/node.slice.test.ts b/packages/davinci-client/src/lib/node.slice.test.ts
index ab63d6c2..2046c27d 100644
--- a/packages/davinci-client/src/lib/node.slice.test.ts
+++ b/packages/davinci-client/src/lib/node.slice.test.ts
@@ -1,11 +1,11 @@
 import { describe, it, expect } from 'vitest';
 
-import { nodeSlice } from './node.slice';
-import { next0 } from './mock-data/davinci.next.mock';
-import { nodeNext0 } from './mock-data/node.next.mock';
-import { success0, success1 } from './mock-data/davinci.success.mock';
-import { nodeSuccess0, nodeSuccess1 } from './mock-data/node.success.mock';
-import { error0a, error2b, error3 } from './mock-data/davinci.error.mock';
+import { nodeSlice } from './node.slice.js';
+import { next0 } from './mock-data/davinci.next.mock.js';
+import { nodeNext0 } from './mock-data/node.next.mock.js';
+import { success0, success1 } from './mock-data/davinci.success.mock.js';
+import { nodeSuccess0, nodeSuccess1 } from './mock-data/node.success.mock.js';
+import { error0a, error2b, error3 } from './mock-data/davinci.error.mock.js';
 
 describe('The node slice reducers', () => {
   it('should return the initial state', () => {
diff --git a/packages/davinci-client/src/lib/node.slice.ts b/packages/davinci-client/src/lib/node.slice.ts
index 6dd381d0..fd71d81a 100644
--- a/packages/davinci-client/src/lib/node.slice.ts
+++ b/packages/davinci-client/src/lib/node.slice.ts
@@ -6,20 +6,20 @@ import { createSlice } from '@reduxjs/toolkit';
 /**
  * Import the needed reducers
  */
-import { nodeCollectorReducer, updateCollectorValues } from './node.reducer';
+import { nodeCollectorReducer, updateCollectorValues } from './node.reducer.js';
 
 /**
  * Import the types
  */
 import type { Draft, PayloadAction } from '@reduxjs/toolkit';
-import type { SubmitCollector } from './collector.types';
+import type { SubmitCollector } from './collector.types.js';
 import type {
   DavinciErrorResponse,
   DaVinciFailureResponse,
   DaVinciNextResponse,
   DaVinciSuccessResponse,
-} from './davinci.types';
-import type { ContinueNode, SuccessNode, ErrorNode, StartNode, FailureNode } from './node.types';
+} from './davinci.types.js';
+import type { ContinueNode, SuccessNode, ErrorNode, StartNode, FailureNode } from './node.types.js';
 
 /**
  * The possible statuses for the four types of nodes
diff --git a/packages/davinci-client/src/lib/node.types.test-d.ts b/packages/davinci-client/src/lib/node.types.test-d.ts
new file mode 100644
index 00000000..d3bdd4c4
--- /dev/null
+++ b/packages/davinci-client/src/lib/node.types.test-d.ts
@@ -0,0 +1,238 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+import { describe, expectTypeOf, it } from 'vitest';
+import type {
+  DaVinciError,
+  Collectors,
+  ContinueNode,
+  ErrorNode,
+  FailureNode,
+  StartNode,
+  SuccessNode,
+} from './node.types.js';
+import type { ErrorDetail, Links } from './davinci.types.js';
+import {
+  ActionCollector,
+  FlowCollector,
+  MultiSelectCollector,
+  PasswordCollector,
+  SingleSelectCollector,
+  SingleValueCollector,
+  SocialLoginCollector,
+  SubmitCollector,
+  TextCollector,
+} from './collector.types.js';
+// ErrorDetail and Links are used as part of the DaVinciError and server._links types respectively
+
+describe('Node Types', () => {
+  describe('DaVinciError', () => {
+    it('should have required properties', () => {
+      // @ts-expect-error Variable is used only for type checking
+      const _error: DaVinciError = {
+        message: 'Test error',
+        code: 'TEST_ERROR',
+        status: 'error',
+      };
+      expectTypeOf<DaVinciError>().toHaveProperty('message');
+      expectTypeOf<DaVinciError['message']>().toEqualTypeOf<string>();
+      expectTypeOf<DaVinciError>().toHaveProperty('code');
+      expectTypeOf<DaVinciError['status']>().toEqualTypeOf<'error' | 'failure' | 'unknown'>();
+    });
+
+    it('should allow nullable properties', () => {
+      // _errorWithDetails variable is unused but necessary for type checking
+      const _errorWithDetails: DaVinciError = {
+        message: 'Test error',
+        code: 'TEST_ERROR',
+        status: 'error',
+        details: [{ message: 'Detail message' } as ErrorDetail],
+        internalHttpStatus: 400,
+        type: 'argument_error',
+      };
+
+      expectTypeOf<DaVinciError>().toHaveProperty('details').toBeNullable();
+      expectTypeOf<DaVinciError>().toHaveProperty('internalHttpStatus').toBeNullable();
+    });
+
+    it('should validate ErrorDetail structure', () => {
+      const detail: ErrorDetail = { message: 'Test detail' };
+      expectTypeOf(detail).toMatchTypeOf<ErrorDetail>();
+    });
+
+    it('should validate Links structure', () => {
+      const links: Links = {
+        self: { href: 'https://example.com' },
+        next: { href: 'https://example.com/next' },
+      };
+      expectTypeOf(links).toMatchTypeOf<Links>();
+    });
+  });
+
+  describe('Node Types', () => {
+    it('should validate ContinueNode structure', () => {
+      // _continueNode variable is unused but necessary for type checking
+      const _continueNode: ContinueNode = {
+        cache: { key: 'test-key' },
+        client: {
+          action: 'test-action',
+          collectors: [],
+          status: 'continue',
+        },
+        error: null,
+        httpStatus: 200,
+        server: {
+          status: 'continue',
+          _links: {},
+          id: 'test-id',
+          interactionId: 'test-interaction',
+          interactionToken: 'test-token',
+          href: 'test-href',
+          eventName: 'test-event',
+        },
+        status: 'continue',
+      };
+
+      expectTypeOf<ContinueNode>().toHaveProperty('cache').toBeObject();
+      expectTypeOf<ContinueNode>().toHaveProperty('client').toBeObject();
+      expectTypeOf<ContinueNode>().toHaveProperty('error').toBeNull();
+      expectTypeOf<ContinueNode>().toHaveProperty('status').toEqualTypeOf<'continue'>();
+    });
+
+    it('should validate ErrorNode structure', () => {
+      const errorNode: ErrorNode = {
+        cache: { key: 'test-key' },
+        client: { status: 'error' },
+        error: {
+          message: 'Test error',
+          code: 'TEST_ERROR',
+          status: 'error',
+          type: 'argument_error',
+        },
+        httpStatus: 400,
+        server: {
+          status: 'error',
+          _links: {},
+          eventName: 'error-event',
+          id: 'test-id',
+          interactionId: 'test-interaction',
+          interactionToken: 'test-token',
+        },
+        status: 'error',
+      };
+
+      expectTypeOf<ErrorNode>().toHaveProperty('error').toMatchTypeOf<DaVinciError>();
+      expectTypeOf<ErrorNode>().toHaveProperty('status').toEqualTypeOf<'error'>();
+    });
+
+    it('should validate FailureNode structure', () => {
+      const failureNode: FailureNode = {
+        cache: { key: 'test-key' },
+        client: { status: 'failure' },
+        error: {
+          message: 'Test failure',
+          code: 'TEST_FAILURE',
+          status: 'failure',
+          type: 'argument_error',
+        },
+        httpStatus: 400,
+        server: {
+          status: 'failure',
+          _links: {},
+          eventName: 'failure-event',
+          href: 'test-href',
+          id: 'test-id',
+          interactionId: 'test-interaction',
+          interactionToken: 'test-token',
+        },
+        status: 'failure',
+      };
+
+      expectTypeOf<FailureNode>().toHaveProperty('error').toMatchTypeOf<DaVinciError>();
+      expectTypeOf<FailureNode>().toHaveProperty('status').toEqualTypeOf<'failure'>();
+    });
+
+    it('should validate StartNode structure', () => {
+      const startNode: StartNode = {
+        cache: null,
+        client: { status: 'start' },
+        error: null,
+        server: { status: 'start' },
+        status: 'start',
+      };
+
+      expectTypeOf<StartNode>().toHaveProperty('cache').toBeNull();
+      expectTypeOf<StartNode>().toHaveProperty('error').toBeNull();
+      expectTypeOf<StartNode>().toHaveProperty('status').toEqualTypeOf<'start'>();
+    });
+
+    it('should validate SuccessNode structure', () => {
+      const successNode: SuccessNode = {
+        cache: { key: 'test-key' },
+        client: {
+          status: 'success',
+          authorization: {
+            code: 'auth-code',
+            state: 'auth-state',
+          },
+        },
+        error: null,
+        httpStatus: 200,
+        server: {
+          status: 'success',
+          _links: {},
+          eventName: 'success-event',
+          id: 'test-id',
+          interactionId: 'test-interaction',
+          interactionToken: 'test-token',
+          href: 'test-href',
+          session: 'test-session',
+        },
+        status: 'success',
+      };
+
+      expectTypeOf<SuccessNode>().toHaveProperty('error').toBeNull();
+      expectTypeOf<SuccessNode>().toHaveProperty('status').toEqualTypeOf<'success'>();
+      expectTypeOf<SuccessNode>().toHaveProperty('client');
+    });
+  });
+
+  describe('Collectors Type', () => {
+    it('should validate Collectors union type', () => {
+      expectTypeOf<Collectors>().toMatchTypeOf<
+        | TextCollector
+        | PasswordCollector
+        | FlowCollector
+        | SocialLoginCollector
+        | SubmitCollector
+        | ActionCollector<'ActionCollector'>
+        | SingleValueCollector<'SingleValueCollector'>
+        | MultiSelectCollector
+        | SingleSelectCollector
+      >();
+
+      // Test that each collector type is part of the union
+      const collectors: Collectors[] = [
+        {
+          category: 'SingleValueCollector',
+          type: 'TextCollector',
+          error: null,
+          id: 'test',
+          name: 'Test',
+          input: { key: 'test', value: '', type: 'string' },
+          output: { key: 'test', label: 'Test', type: 'string', value: '' },
+        },
+        {
+          category: 'SingleValueCollector',
+          type: 'PasswordCollector',
+          error: null,
+          id: 'test',
+          name: 'Test',
+          input: { key: 'test', value: '', type: 'string' },
+          output: { key: 'test', label: 'Test', type: 'string' },
+        },
+      ];
+
+      expectTypeOf(collectors).toBeArray();
+      expectTypeOf(collectors[0]).toMatchTypeOf<Collectors>();
+    });
+  });
+});
diff --git a/packages/davinci-client/src/lib/node.types.ts b/packages/davinci-client/src/lib/node.types.ts
index 7fab63e6..46933230 100644
--- a/packages/davinci-client/src/lib/node.types.ts
+++ b/packages/davinci-client/src/lib/node.types.ts
@@ -6,6 +6,8 @@ import type {
   SubmitCollector,
   ActionCollector,
   SingleValueCollector,
+  SingleSelectCollector,
+  MultiSelectCollector,
 } from './collector.types.js';
 import type { ErrorDetail, Links } from './davinci.types.js';
 import { GenericError } from './error.types.js';
@@ -20,10 +22,12 @@ export type Collectors =
   | FlowCollector
   | PasswordCollector
   | TextCollector
+  | SingleSelectCollector
   | SocialLoginCollector
   | SubmitCollector
   | ActionCollector<'ActionCollector'>
-  | SingleValueCollector<'SingleValueCollector'>;
+  | SingleValueCollector<'SingleValueCollector'>
+  | MultiSelectCollector;
 
 export interface ContinueNode {
   cache: {
diff --git a/packages/davinci-client/src/lib/wellknown.api.ts b/packages/davinci-client/src/lib/wellknown.api.ts
index 5a1b62c8..af0c915c 100644
--- a/packages/davinci-client/src/lib/wellknown.api.ts
+++ b/packages/davinci-client/src/lib/wellknown.api.ts
@@ -1,5 +1,5 @@
 import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query';
-import { WellknownResponse } from './wellknown.types';
+import { WellknownResponse } from './wellknown.types.js';
 
 export const wellknownApi = createApi({
   reducerPath: 'wellknown',
diff --git a/packages/davinci-client/src/types.test-d.ts b/packages/davinci-client/src/types.test-d.ts
new file mode 100644
index 00000000..14e90449
--- /dev/null
+++ b/packages/davinci-client/src/types.test-d.ts
@@ -0,0 +1,124 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+import { describe, expectTypeOf, it } from 'vitest';
+import type {
+  NodeStates,
+  StartNode,
+  ContinueNode,
+  ErrorNode,
+  SuccessNode,
+  FailureNode,
+  ActionCollector,
+  SingleValueCollector,
+  FlowCollector,
+  PasswordCollector,
+  TextCollector,
+  SocialLoginCollector,
+  SubmitCollector,
+} from './types.js';
+import type * as Types from './types.js';
+
+describe('Type exports', () => {
+  it('should validate all types are exported', () => {
+    expectTypeOf<typeof Types>().toBeObject();
+    // Force type checking of the entire module
+    type AllExports = typeof Types;
+    expectTypeOf<AllExports>().not.toBeNever();
+  });
+});
+
+describe('Type exports', () => {
+  describe('Node Types', () => {
+    it('should verify NodeStates union includes all node types', () => {
+      expectTypeOf<NodeStates>().toEqualTypeOf<
+        StartNode | ContinueNode | ErrorNode | SuccessNode | FailureNode
+      >();
+    });
+
+    it('should verify StartNode structure', () => {
+      type ExpectedStartNode = {
+        cache: null;
+        client: { status: 'start' };
+        error: null;
+        server: { status: 'start' };
+        status: 'start';
+      };
+      expectTypeOf<StartNode>().toEqualTypeOf<ExpectedStartNode>();
+    });
+
+    it('should verify ContinueNode has required properties', () => {
+      expectTypeOf<ContinueNode>().toHaveProperty('cache');
+      expectTypeOf<ContinueNode>().toHaveProperty('client');
+      expectTypeOf<ContinueNode>().toHaveProperty('status');
+    });
+  });
+
+  describe('Collector Types', () => {
+    describe('SingleValueCollector Types', () => {
+      it('should validate TextCollector structure', () => {
+        expectTypeOf<TextCollector>()
+          .toHaveProperty('category')
+          .toEqualTypeOf<'SingleValueCollector'>();
+        expectTypeOf<TextCollector>().toHaveProperty('type').toEqualTypeOf<'TextCollector'>();
+        expectTypeOf<TextCollector>().toHaveProperty('input').toBeObject();
+        expectTypeOf<TextCollector>().toHaveProperty('output').toBeObject();
+      });
+
+      it('should validate PasswordCollector structure', () => {
+        expectTypeOf<PasswordCollector>()
+          .toHaveProperty('category')
+          .toEqualTypeOf<'SingleValueCollector'>();
+        expectTypeOf<PasswordCollector>()
+          .toHaveProperty('type')
+          .toEqualTypeOf<'PasswordCollector'>();
+        expectTypeOf<PasswordCollector>().toHaveProperty('input').toBeObject();
+        expectTypeOf<PasswordCollector>().toHaveProperty('output').toBeObject();
+      });
+    });
+
+    describe('ActionCollector Types', () => {
+      it('should validate SocialLoginCollector structure', () => {
+        expectTypeOf<SocialLoginCollector>()
+          .toHaveProperty('category')
+          .toEqualTypeOf<'ActionCollector'>();
+        expectTypeOf<SocialLoginCollector>()
+          .toHaveProperty('type')
+          .toEqualTypeOf<'SocialLoginCollector'>();
+        expectTypeOf<SocialLoginCollector>().toHaveProperty('output').toBeObject();
+      });
+
+      it('should validate FlowCollector structure', () => {
+        expectTypeOf<FlowCollector>().toHaveProperty('category').toEqualTypeOf<'ActionCollector'>();
+        expectTypeOf<FlowCollector>().toHaveProperty('type').toEqualTypeOf<'FlowCollector'>();
+        expectTypeOf<FlowCollector>().toHaveProperty('output').toBeObject();
+      });
+
+      it('should validate SubmitCollector structure', () => {
+        expectTypeOf<SubmitCollector>()
+          .toHaveProperty('category')
+          .toEqualTypeOf<'ActionCollector'>();
+        expectTypeOf<SubmitCollector>().toHaveProperty('type').toEqualTypeOf<'SubmitCollector'>();
+        expectTypeOf<SubmitCollector>().toHaveProperty('output').toBeObject();
+      });
+    });
+
+    describe('Type Constraints', () => {
+      it('should enforce valid collector types for SingleValueCollector', () => {
+        // Valid type - should compile
+        type ValidSingleValue = SingleValueCollector<'TextCollector'>;
+        expectTypeOf<ValidSingleValue>().toBeObject();
+
+        // @ts-expect-error - Invalid collector type
+        type InvalidSingleValue = SingleValueCollector<'InvalidType'>;
+      });
+
+      it('should enforce valid collector types for ActionCollector', () => {
+        // Valid type - should compile
+        type ValidAction = ActionCollector<'SubmitCollector'>;
+        expectTypeOf<ValidAction>().toBeObject();
+
+        // @ts-expect-error - Invalid collector type
+        type InvalidAction = ActionCollector<'InvalidType'>;
+      });
+    });
+  });
+});
diff --git a/packages/davinci-client/tsconfig.spec.json b/packages/davinci-client/tsconfig.spec.json
index 0ce2e457..9cac0a9a 100644
--- a/packages/davinci-client/tsconfig.spec.json
+++ b/packages/davinci-client/tsconfig.spec.json
@@ -1,6 +1,8 @@
 {
   "extends": "./tsconfig.json",
   "compilerOptions": {
+    "module": "NodeNext",
+    "target": "ES2022",
     "outDir": "../../dist/out-tsc",
     "types": [
       "vitest/globals",
diff --git a/packages/davinci-client/vite.config.ts b/packages/davinci-client/vite.config.ts
index ee79dbc7..3188b112 100644
--- a/packages/davinci-client/vite.config.ts
+++ b/packages/davinci-client/vite.config.ts
@@ -1,7 +1,7 @@
 import { defineConfig } from 'vite';
 import dts from 'vite-plugin-dts';
 import * as path from 'path';
-import * as pkg from './package.json';
+import pkg from './package.json';
 
 export default defineConfig({
   root: __dirname,
@@ -52,10 +52,40 @@ export default defineConfig({
     },
     globals: true,
     environment: 'jsdom',
-    include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
+    include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}', 'src/**/*.test-d.ts'],
     reporters: ['default'],
     coverage: {
-      reporter: ['text', 'json', 'html'],
+      include: ['src/**/*.{js,ts}'],
+      /**
+       * You have to extend the vite defaults to include the files you want to exclude from coverage.
+       */
+      exclude: [
+        'src/**/*.mock.{js,ts}',
+        'src/**/*.data.{js,ts}',
+        'src/**/*.test.{js,ts}',
+        'coverage/**',
+        'dist/**',
+        '**/node_modules/**',
+        '**/[.]**',
+        'packages/*/test?(s)/**',
+        '**/*.d.ts',
+        '**/virtual:*',
+        '**/__x00__*',
+        '**/\x00*',
+        'cypress/**',
+        'test?(s)/**',
+        'test?(-*).?(c|m)[jt]s?(x)',
+        '**/*{.,-}{test,spec,bench,benchmark}?(-d).?(c|m)[jt]s?(x)',
+        '**/__tests__/**',
+        '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*',
+        '**/vitest.{workspace,projects}.[jt]s?(on)',
+        '**/.{eslint,mocha,prettier}rc.{?(c|m)js,yml}',
+      ],
+      reporter: [
+        ['text', { skipEmpty: true }],
+        ['html', { skipEmpty: true }],
+        ['json', { skipEmpty: true }],
+      ],
       enabled: Boolean(process.env['CI']),
       reportsDirectory: './coverage',
       provider: 'v8',
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9d642e4b..16b9d51a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -288,10 +288,6 @@ importers:
       immer:
         specifier: 'catalog:'
         version: 10.1.1
-    devDependencies:
-      vitest:
-        specifier: ^1.4.0
-        version: 1.5.0(@types/node@22.10.2)(@vitest/ui@1.5.0)(jsdom@22.1.0)(less@4.1.3)(sass@1.75.0)(stylus@0.64.0)(terser@5.33.0)
 
   packages/device-client:
     dependencies:
diff --git a/tools/create-package/src/generators/files/vite.config.ts.template b/tools/create-package/src/generators/files/vite.config.ts.template
index b8354249..7ebcc2a4 100644
--- a/tools/create-package/src/generators/files/vite.config.ts.template
+++ b/tools/create-package/src/generators/files/vite.config.ts.template
@@ -9,7 +9,11 @@ export default defineConfig(() => ({
     watch: !process.env['CI'],
     coverage: {
       enabled: Boolean(process.env['CI']),
-      reporter: ['text', 'json', 'html'],
+      reporter: [
+        ['text', { skipEmpty: true }],
+        ['html', { skipEmpty: true }],
+        ['json', { skipEmpty: true }],
+      ],
       reportsDirectory: './coverage',
       provider: 'v8',
     },
@@ -21,6 +25,9 @@ export default defineConfig(() => ({
       },
     },
     environment: 'jsdom',
-    include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
+    include: [
+    'src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'
+    'src/**/*.test-d.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
+    ],
   },
 }));