From f1732560a8e180384e1375eb14ee82223328c4b7 Mon Sep 17 00:00:00 2001 From: AJ Ancheta <7781450+ancheetah@users.noreply.github.com> Date: Thu, 5 Feb 2026 10:00:31 -0500 Subject: [PATCH] chore: update readmes, fix types and comments --- .changeset/sour-jobs-count.md | 14 +++++ e2e/davinci-suites/src/fido.test.ts | 4 +- .../davinci-client/src/lib/fido/README.md | 2 + packages/device-client/README.md | 30 +++++----- .../device-client/src/lib/device.store.ts | 20 ++++--- packages/oidc-client/README.md | 6 +- packages/protect/README.md | 16 +++--- packages/sdk-effects/iframe-manager/README.md | 26 ++++----- .../src/lib/iframe-manager.effects.ts | 6 +- packages/sdk-effects/logger/README.md | 51 +++++++++++++++-- .../sdk-request-middleware/README.md | 47 ++++++++++++--- packages/sdk-effects/storage/README.md | 57 ++++++++----------- .../storage/src/lib/storage.effects.test.ts | 2 +- packages/sdk-types/README.md | 20 +++++-- packages/sdk-types/src/lib/authorize.types.ts | 8 +-- packages/sdk-utilities/README.md | 29 +++++++--- 16 files changed, 221 insertions(+), 117 deletions(-) create mode 100644 .changeset/sour-jobs-count.md diff --git a/.changeset/sour-jobs-count.md b/.changeset/sour-jobs-count.md new file mode 100644 index 0000000000..2701148de9 --- /dev/null +++ b/.changeset/sour-jobs-count.md @@ -0,0 +1,14 @@ +--- +'@forgerock/sdk-request-middleware': patch +'@forgerock/iframe-manager': patch +'@forgerock/storage': patch +'@forgerock/sdk-logger': patch +'@forgerock/davinci-client': patch +'@forgerock/device-client': patch +'@forgerock/sdk-utilities': patch +'@forgerock/oidc-client': patch +'@forgerock/sdk-types': patch +'@forgerock/protect': patch +--- + +Update READMES. Fix types and comments. diff --git a/e2e/davinci-suites/src/fido.test.ts b/e2e/davinci-suites/src/fido.test.ts index 3252e9a165..e1a38cb486 100644 --- a/e2e/davinci-suites/src/fido.test.ts +++ b/e2e/davinci-suites/src/fido.test.ts @@ -87,9 +87,7 @@ test.describe('FIDO/WebAuthn Tests', () => { await expect(page.getByText('FIDO2 Test Form')).toBeVisible(); }); - // Note: This test is currently not working due to a DaVinci issue where the authentication options - // are not included in the response. - test.skip('Register and authenticate with usernameless', async ({ page }) => { + test('Register and authenticate with usernameless', async ({ page }) => { const { navigate } = asyncEvents(page); await navigate( diff --git a/packages/davinci-client/src/lib/fido/README.md b/packages/davinci-client/src/lib/fido/README.md index bb1e1cd1b8..b2d7fdb6e3 100644 --- a/packages/davinci-client/src/lib/fido/README.md +++ b/packages/davinci-client/src/lib/fido/README.md @@ -4,6 +4,8 @@ The `fido` API provides an interface for registering and authenticating with the WebAuthn API and transforming data to and from DaVinci. These methods transform options from DaVinci into WebAuthn compatible options, then call `navigator.credentials.create` or `navigator.credentials.get`, and finally transform the output of the WebAuthn API into a valid payload to send back to DaVinci. +**Note**: To use this module, browser support is required for `navigator.credentials.create` and `navigator.credentials.get` + ## Installation and Initialization The `fido` module is exported as a member of the `@forgerock/davinci-client` package and is intended to be used alongside the `davinciClient` to progress through a flow. To install the necessary dependencies, run: diff --git a/packages/device-client/README.md b/packages/device-client/README.md index 3630ad21c8..211b13dd39 100644 --- a/packages/device-client/README.md +++ b/packages/device-client/README.md @@ -8,7 +8,6 @@ The `deviceClient` API provides a structured interface for managing various type 2. [Installation](#installation) 3. [Configuration](#configuration) 4. [API Methods](#api-methods) - - [OATH Management](#oath-management) - [PUSH Management](#push-management) - [WebAuthn Management](#webauthn-management) @@ -36,8 +35,7 @@ npm install @forgerock/device-client --save To configure the `deviceClient`, you need to provide a `ConfigOptions` object that includes the base URL for the server and the realm path. ```typescript -import { deviceClient } from '@forgerock/device-client'; -import { type ConfigOptions } from '@forgerock/javascript-sdk'; +import { deviceClient, type ConfigOptions } from '@forgerock/device-client'; const config: ConfigOptions = { serverConfig: { @@ -59,59 +57,59 @@ const apiClient = deviceClient(config); #### Methods -- **get(query: RetrieveOathQuery): Promise** +- **get(query: RetrieveOathQuery): Promise** - Retrieves Oath devices based on the specified query. -- **delete(query: RetrieveOathQuery & { device: OathDevice }): Promise\** +- **delete(query: RetrieveOathQuery & { device: OathDevice }): Promise** - Deletes an Oath device based on the provided query and device information. ### PUSH Management #### Methods -- **get(query: PushDeviceQuery): Promise** +- **get(query: PushDeviceQuery): Promise** - Retrieves Push devices based on the specified query. -- **delete(query: DeleteDeviceQuery): Promise\** +- **delete(query: DeleteDeviceQuery): Promise** - Deletes a Push device based on the provided query. ### WebAuthn Management #### Methods -- **get(query: WebAuthnQuery): Promise** +- **get(query: WebAuthnQuery): Promise** - Retrieves WebAuthn devices based on the specified query. -- **update(query: WebAuthnQuery & { device: WebAuthnDevice }): Promise\** +- **update(query: WebAuthnQuery & { device: WebAuthnDevice }): Promise** - Updates the name of a WebAuthn device based on the provided query and body. -- **delete(query: WebAuthnQuery & { device: WebAuthnDevice | UpdatedWebAuthnDevice }): Promise\** +- **delete(query: WebAuthnQuery & { device: WebAuthnDevice | UpdatedWebAuthnDevice }): Promise** - Deletes a WebAuthn device based on the provided query and body. ### Bound Devices Management #### Methods -- **get(query: GetBoundDevicesQuery): Promise\** +- **get(query: GetBoundDevicesQuery): Promise** - Retrieves bound devices based on the specified query. -- **update(query: BoundDeviceQuery): Promise\** +- **update(query: BoundDeviceQuery): Promise** - Updates the name of a bound device based on the provided query. -- **delete(query: BoundDeviceQuery): Promise\** +- **delete(query: BoundDeviceQuery): Promise** - Deletes a bound device based on the provided query. ### Device Profiling Management #### Methods -- **get(query: GetProfileDevices): Promise\** +- **get(query: GetProfileDevices): Promise** - Retrieves device profiles based on the specified query. -- **update(query: ProfileDevicesQuery): Promise\** +- **update(query: ProfileDevicesQuery): Promise** - Updates the name of a device profile based on the provided query. -- **delete(query: ProfileDevicesQuery): Promise\** +- **delete(query: ProfileDevicesQuery): Promise** - Deletes a device profile based on the provided query. ## Example Usage diff --git a/packages/device-client/src/lib/device.store.ts b/packages/device-client/src/lib/device.store.ts index 66804dbf9d..8b73e626ca 100644 --- a/packages/device-client/src/lib/device.store.ts +++ b/packages/device-client/src/lib/device.store.ts @@ -7,11 +7,15 @@ import { type ConfigOptions } from '@forgerock/javascript-sdk'; import { configureStore } from '@reduxjs/toolkit'; import { deviceService } from './services/index.js'; -import { OathDevice, RetrieveOathQuery } from './types/oath.types.js'; -import { DeleteDeviceQuery, PushDevice, PushDeviceQuery } from './types/push-device.types.js'; -import { UpdatedWebAuthnDevice, WebAuthnDevice, WebAuthnQuery } from './types/webauthn.types.js'; -import { BoundDeviceQuery, Device, GetBoundDevicesQuery } from './types/bound-device.types.js'; -import { +import type { OathDevice, RetrieveOathQuery } from './types/oath.types.js'; +import type { DeleteDeviceQuery, PushDevice, PushDeviceQuery } from './types/push-device.types.js'; +import type { + UpdatedWebAuthnDevice, + WebAuthnDevice, + WebAuthnQuery, +} from './types/webauthn.types.js'; +import type { BoundDeviceQuery, Device, GetBoundDevicesQuery } from './types/bound-device.types.js'; +import type { GetProfileDevices, ProfileDevice, ProfileDevicesQuery, @@ -290,7 +294,7 @@ export const deviceClient = (config: ConfigOptions) => { * Get profile devices * * @async - * @function update + * @function get * @param {GetProfileDevices} query - The query used to get profile devices * @returns {Promise} - A promise that resolves to the response data or an error object if the response is not valid. */ @@ -336,8 +340,8 @@ export const deviceClient = (config: ConfigOptions) => { * Get profile devices * * @async - * @function update - * @param {ProfileDevicesQuery} query - The query used to update a profile device + * @function delete + * @param {ProfileDevicesQuery} query - The query used to delete a profile device * @returns {Promise} - A promise that resolves to null or an error object if the response is not valid. */ delete: async function (query: ProfileDevicesQuery): Promise { diff --git a/packages/oidc-client/README.md b/packages/oidc-client/README.md index 3d4676369d..a959f5bb16 100644 --- a/packages/oidc-client/README.md +++ b/packages/oidc-client/README.md @@ -1,6 +1,8 @@ -# oidc-client +# OIDC Client -A generic OpenID Connect (OIDC) client library for JavaScript and TypeScript, designed to work with any OIDC-compliant identity provider. +A generic OpenID Connect (OIDC) client library for JavaScript and TypeScript, designed to work with PingOne platforms. + +The oidc module follows the [OIDC](https://openid.net/specs/openid-connect-core-1_0.html) specification and provides a simple and easy-to-use API to interact with the OIDC server. It allows you to authenticate, retrieve the access token, revoke the token, and sign out from the OIDC server. ```js // Initialize OIDC Client diff --git a/packages/protect/README.md b/packages/protect/README.md index 6ee583cb2c..181febef5c 100644 --- a/packages/protect/README.md +++ b/packages/protect/README.md @@ -14,7 +14,7 @@ resumeBehavioralData(); ## Quickstart with a PingOne AIC or PingAM Authentication Journey -The Ping Protect module is intended to be used along with the ForgeRock JavaScript SDK to provide the Protect feature. +The Ping Protect module is intended to be used along with the Journey client to provide the Protect feature. ### Requirements @@ -22,7 +22,7 @@ The Ping Protect module is intended to be used along with the ForgeRock JavaScri 2. PingOne tenant with Protect enabled 3. A Ping Protect Service configured in AIC or AM 4. A journey/tree with the appropriate Protect Nodes -5. A client application with the `@forgerock/javascript-sdk` and `@forgerock/protect` modules installed +5. A client application with the `@forgerock/journey-client` and `@forgerock/protect` modules installed ### Integrate into a Client Application @@ -31,11 +31,11 @@ The Ping Protect module is intended to be used along with the ForgeRock JavaScri Install both modules and their latest versions: ```sh -npm install @forgerock/javascript-sdk @forgerock/protect +npm install @forgerock/journey-client @forgerock/protect ``` ```sh -pnpm install @forgerock/javascript-sdk @forgerock/protect +pnpm install @forgerock/journey-client @forgerock/protect ``` #### Initialization (Recommended) @@ -70,10 +70,10 @@ if (step.getCallbacksOfType('PingOneProtectInitializeCallback')) { #### Data collection -You then call the `FRAuth.next` method after initialization to move the user forward in the journey. +You then call the `next` method after initialization to move the user forward in the journey. ```js -FRAuth.next(step); +journeyClient.next(step); ``` At some point in the journey, and as late as possible in order to collect as much data as you can, you will come across the `PingOneProtectEvaluationCallback`. This is when you call the `getData` method to package what's been collected for the server to evaluate. @@ -92,12 +92,12 @@ Now that we have the data, set it on the callback in order to send it to the ser ```js callback.setData(data); -FRAuth.next(step); +journeyClient.next(step); ``` ### Error Handling -The Protect API methods will return an error object if they fail. When you encounter an error during initialization or evaluation, set the error message on the callback using the `setClientError` method. Setting the message on the callback is how it gets sent to the server on the `FRAuth.next` method call. +The Protect API methods will return an error object if they fail. When you encounter an error during initialization or evaluation, set the error message on the callback using the `setClientError` method. Setting the message on the callback is how it gets sent to the server on the `next` method call. ```js if (step.getCallbacksOfType('PingOneProtectInitializeCallback')) { diff --git a/packages/sdk-effects/iframe-manager/README.md b/packages/sdk-effects/iframe-manager/README.md index 31e28168f7..b32e60d0e2 100644 --- a/packages/sdk-effects/iframe-manager/README.md +++ b/packages/sdk-effects/iframe-manager/README.md @@ -1,4 +1,4 @@ -# IFrame Manager (`@pingidentity/sdk-effects/iframe-manager`) +# IFrame Manager (`@forgerock/iframe-manager`) ## Overview @@ -19,10 +19,8 @@ This utility fundamentally relies on the browser's **Same-Origin Policy**. The f ## Installation -This effect is typically part of a larger SDK. Assume it's imported or available within your project structure like so (adjust path as necessary): - ```typescript -import iFrameManager from './path/to/iframe-manager.effects'; // Adjust path as needed +import iFrameManager from '@forgerock/iframe-manager'; const iframeMgr = iFrameManager(); ``` @@ -40,18 +38,15 @@ This is the main factory function that initializes the effect. This method creates a hidden iframe, initiates navigation, and waits for a redirect back to the application's origin containing specific query parameters. - **`options`**: `GetParamsFromIFrameOptions` - An object containing configuration for the iframe request. - - **`url: string`**: The initial URL to load within the hidden iframe. This URL is expected to eventually redirect back to the application's origin. - **`timeout: number`**: The maximum time in milliseconds to wait for the entire operation to complete successfully (i.e., for a redirect containing success or error parameters). If the timeout is reached before completion, the promise rejects. - * **`successParams: string[]`**: An array of query parameter _keys_. If the final redirect URL (on the same origin) contains **at least one** of these keys in its query string, the promise will **resolve**. - * **`errorParams: string[]`**: An array of query parameter _keys_. If the final redirect URL (on the same origin) contains **any** of these keys in its query string, the promise will **reject**. Error parameters are checked _before_ success parameters. + * **`errorParams: string[]`**: An array of query parameter _keys_. If the final redirect URL (on the same origin) contains **any** of these keys in its query string, the promise will **resolve** with all parsed parameters (including the error parameters). The caller must check the returned parameters for error keys. Error parameters are checked _before_ success parameters. - _Note:_ Both `successParams` and `errorParams` must be provided and contain at least one key. - **Returns**: `Promise` - - **On Success**: Resolves with `ResolvedParams`, an object containing _all_ query parameters parsed from the final redirect URL's query string. This occurs when the iframe redirects back to the same origin and its URL contains at least one key listed in `successParams` (and no keys listed in `errorParams`). - - **On Failure**: Rejects with: + - **On Failure**: Resolves with: - `ResolvedParams`: An object containing _all_ parsed query parameters if the final redirect URL contains any key listed in `errorParams`. - An object `{ type: 'internal_error', message: 'iframe timed out' }` if the specified `timeout` is reached before a success or error condition is met. - An object `{ type: 'internal_error', message: 'unexpected failure' }` if there's an error accessing the iframe's content window (most likely due to a cross-origin redirect that wasn't expected or handled). @@ -63,7 +58,7 @@ This method creates a hidden iframe, initiates navigation, and waits for a redir ## Usage Example ```typescript -import iFrameManager from './path/to/iframe-manager.effects'; // Adjust path +import iFrameManager from '@forgerock/iframe-manager'; const iframeMgr = iFrameManager(); @@ -77,10 +72,15 @@ async function performSilentLogin(authUrl: string) { try { console.log('Attempting silent login via iframe...'); - // The promise resolves/rejects when the iframe redirects back to *this* app's origin - // with appropriate query parameters. + // The promise resolves with all parsed params regardless of success/error. const resultParams = await iframeMgr.getParamsByRedirect(options); + // Check if the server returned an error + if (resultParams.error || resultParams.error_description) { + console.error('Silent login failed. Server returned error:', resultParams); + return; + } + // Success case: 'code', 'id_token', or 'session_state' was present console.log('Silent login successful. Received params:', resultParams); // Process the received parameters (e.g., exchange code for token) @@ -117,4 +117,4 @@ performSilentLogin(authorizationUrl); 1. **Timeout:** Choose a reasonable `timeout` value. If the external service is slow or the redirect chain is long, the operation might time out prematurely. Conversely, too long a timeout might delay feedback to the user if something goes wrong. 1. **Intermediate Redirects:** The code handles intermediate redirects (pages loaded within the iframe that don't contain success or error parameters) by simply waiting for the next `load` event. The process only completes upon detecting success/error parameters or timing out. 1. **Cleanup:** The utility ensures the iframe element is removed from the DOM and the timeout timer is cleared upon completion (resolve, reject, or timeout) to prevent memory leaks. -1. **Error Parameter Precedence:** Error parameters (`errorParams`) are checked before success parameters (`successParams`). If a redirect URL contains both an error parameter and a success parameter, the promise will be **rejected**. +1. **Error Parameter Precedence:** Error parameters (`errorParams`) are checked before success parameters (`successParams`). If a redirect URL contains both an error parameter and a success parameter, the promise will **resolve** with all parameters, and the caller must check for the error parameter keys to determine it's an error state. diff --git a/packages/sdk-effects/iframe-manager/src/lib/iframe-manager.effects.ts b/packages/sdk-effects/iframe-manager/src/lib/iframe-manager.effects.ts index 2fee278e3a..031f085c30 100644 --- a/packages/sdk-effects/iframe-manager/src/lib/iframe-manager.effects.ts +++ b/packages/sdk-effects/iframe-manager/src/lib/iframe-manager.effects.ts @@ -58,8 +58,8 @@ export function iFrameManager() { * Accessing contentWindow.location of a cross-origin iframe will fail. * * @param options - The options for the iframe request (URL, timeout, success/error params). - * @returns A Promise that resolves with the parsed query parameters on success, - * or rejects on error, timeout, or if unable to access iframe content. + * @returns A Promise that resolves with the parsed query parameters on success or + * when error params are present; rejects on timeout or if unable to access iframe content. */ return { getParamsByRedirect: (options: GetParamsFromIFrameOptions): Promise => { @@ -116,7 +116,7 @@ export function iFrameManager() { // 1. Check for Error Parameters if (hasErrorParams(searchParams, errorParams)) { cleanup(); - resolve(parsedParams); // Reject with all parsed params for context + resolve(parsedParams); // Resolve with all parsed params for context return; } diff --git a/packages/sdk-effects/logger/README.md b/packages/sdk-effects/logger/README.md index b5a9faca89..d47ce3e1f6 100644 --- a/packages/sdk-effects/logger/README.md +++ b/packages/sdk-effects/logger/README.md @@ -7,18 +7,19 @@ A flexible and configurable logging utility for the Ping Identity JavaScript SDK - Multiple log levels (`error`, `warn`, `info`, `debug`, `none`) - Ability to change log level at runtime - Support for multiple arguments in log messages +- Custom logger integration (bring your own logger implementation) - TypeScript support with proper type definitions ## Installation ```bash -npm install @ping-identity/effects-logger +npm install @forgerock/sdk-logger ``` ## Usage ```typescript -import { logger } from '@ping-identity/effects-logger'; +import { logger } from '@forgerock/sdk-logger'; // Initialize the logger with a specific log level const log = logger({ level: 'info' }); @@ -38,6 +39,28 @@ log.changeLevel('none'); // Disable all logs log.error('This error will not be logged'); ``` +### Using a Custom Logger + +You can provide your own logger implementation (e.g., Sentry, LogRocket, or another service): + +```typescript +import { logger } from '@forgerock/sdk-logger'; + +const customLogger = { + error: (...args) => /* custom logging */, + warn: (...args) => /* custom logging */, + info: (...args) => /* custom logging */, + debug: (...args) => /* custom logging */, +}; + +// Initialize the logger with custom implementation +const log = logger({ level: 'info', custom: customLogger }); + +// Use the logger +log.error('Critical error:', new Error('Something failed')); +log.info('User logged in successfully'); +``` + ## Log Levels The logger supports the following log levels (in order of severity): @@ -52,13 +75,14 @@ When a log level is set, only messages of that level or higher severity will be ## API Reference -### `logger({ level })` +### `logger({ level, custom? })` Initializes a new logger instance. **Parameters:** - `level`: The initial log level (`'error'`, `'warn'`, `'info'`, `'debug'`, or `'none'`) +- `custom` (optional): A `CustomLogger` object to use instead of the default console implementation **Returns:** A logger instance with the following methods: @@ -68,10 +92,27 @@ Initializes a new logger instance. - `debug(...args)`: Log a debug message - `changeLevel(level)`: Change the current log level +### `CustomLogger` Interface + +Defines the interface for custom logger implementations: + +```typescript +interface CustomLogger { + error: (...args: LogMessage[]) => void; + warn: (...args: LogMessage[]) => void; + info: (...args: LogMessage[]) => void; + debug: (...args: LogMessage[]) => void; +} + +type LogMessage = string | number | object; +``` + +When a custom logger is provided, all log calls will be delegated to your implementation. If no custom logger is provided, the logger falls back to the browser's native `console` methods. + ## Building -Run `nx build logger` to build the library. +Run `nx build sdk-logger` to build the library. ## Running unit tests -Run `nx test @forgerock/sdk-logger` to execute the unit tests via [Vitest](https://vitest.dev/). +Run `nx test sdk-logger` to execute the unit tests via [Vitest](https://vitest.dev/). diff --git a/packages/sdk-effects/sdk-request-middleware/README.md b/packages/sdk-effects/sdk-request-middleware/README.md index b148c3f607..c41b2b4188 100644 --- a/packages/sdk-effects/sdk-request-middleware/README.md +++ b/packages/sdk-effects/sdk-request-middleware/README.md @@ -50,11 +50,12 @@ const requestMiddleware = [ const fetchArgs = { url: 'https://api.example.com/resource' }; // Initialize a query and apply middleware -const response = await initQuery(fetchArgs, 'start') +const response = await initQuery(fetchArgs, 'authorize') .applyMiddleware(requestMiddleware) - .applyQuery(async (args) => { + .applyQuery(async (request) => { // Your fetch implementation here - return fetch(args.url, args); + const response = await fetch(request.url, request); + return { data: await response.json() }; }); ``` @@ -85,7 +86,7 @@ const authMiddleware = [ ]; // Use the middleware with specific action type -const response = await initQuery(fetchArgs, 'login') +const response = await initQuery(fetchArgs, 'start') .applyMiddleware(authMiddleware) .applyQuery(queryCallback); ``` @@ -121,21 +122,51 @@ Executes the request with the provided callback function. **Parameters:** -- `callback`: A function that takes the modified request and returns a Promise with the API response +- `callback`: An async function that takes the modified `FetchArgs` (with `url` as a string) and returns a Promise that resolves to a `QueryReturnValue` **Returns:** -A Promise with the result of the callback function +A Promise that resolves to a `QueryReturnValue` -### RequestMiddleware Type +### RequestMiddleware Types ```typescript -type RequestMiddleware = ( +type RequestMiddleware = ( req: ModifiedFetchArgs, action: Action, next: () => ModifiedFetchArgs, ) => void; ``` +The `endpoint` parameter for `initQuery` accepts an action type which maps to the type of request you want to intercept. + +```typescript +const actionTypes = { + // Journey + begin: 'JOURNEY_START', + continue: 'JOURNEY_NEXT', + terminate: 'JOURNEY_TERMINATE', + + // DaVinci + start: 'DAVINCI_START', + next: 'DAVINCI_NEXT', + flow: 'DAVINCI_FLOW', + success: 'DAVINCI_SUCCESS', + error: 'DAVINCI_ERROR', + failure: 'DAVINCI_FAILURE', + resume: 'DAVINCI_RESUME', + + // OIDC + authorize: 'AUTHORIZE', + tokenExchange: 'TOKEN_EXCHANGE', + revoke: 'REVOKE', + userInfo: 'USER_INFO', + endSession: 'END_SESSION', +} as const; + +type ActionTypes = (typeof actionTypes)[keyof typeof actionTypes]; +type EndpointTypes = keyof typeof actionTypes; +``` + ## Building Run `nx build sdk-request-middleware` to build the library. diff --git a/packages/sdk-effects/storage/README.md b/packages/sdk-effects/storage/README.md index 6d782964f0..b28addbf62 100644 --- a/packages/sdk-effects/storage/README.md +++ b/packages/sdk-effects/storage/README.md @@ -1,13 +1,13 @@ # ForgeRock SDK Effects - Storage -This package provides a storage effect for managing token storage within the ForgeRock JavaScript SDK ecosystem. +This package provides a storage effect for managing token storage within the Ping JavaScript SDK ecosystem. ## Installation ```bash -npm install @forgerock/sdk-effects-storage +npm install @forgerock/storage # or -yarn add @forgerock/sdk-effects-storage +yarn add @forgerock/storage ``` ## Usage @@ -15,18 +15,15 @@ yarn add @forgerock/sdk-effects-storage The `storage` effect facilitates getting, setting, and removing items from browser storage (`localStorage` or `sessionStorage`) or a custom token store implementation. ```typescript -import { storage } from '@forgerock/sdk-effects-storage'; -import { TokenStoreObject } from '@forgerock/sdk-types'; +import { createStorage, type CustomStorageConfig } from '@forgerock/storage'; // Example using localStorage -const storageEffect = storage({ - tokenStore: 'localStorage', - prefix: 'fr-auth', - clientId: 'my-client-id', +const storageApi = createStorage({ + type: 'localStorage', + name: 'MyStorage', + prefix: 'myPrefix', }); -const storageApi = storageEffect(); - async function manageTokens() { // Set a token await storageApi.set('someTokenValue'); @@ -44,39 +41,35 @@ async function manageTokens() { } // Example using a custom token store -const myCustomStore: TokenStoreObject = { - get: async (key) => { - /* ... custom logic ... */ return null; +const myCustomStore: CustomStorageObject = { + get: async (key: string): Promise => { + /* ... custom logic ... */ }, - set: async (key, value) => { + set: async (key: string, valueToSet: string): Promise => { /* ... custom logic ... */ }, - remove: async (key) => { + remove: async (key: string): Promise => { /* ... custom logic ... */ }, }; -const customStorageEffect = storage( - { - tokenStore: 'localStorage', // This is ignored when customTokenStore is provided - prefix: 'fr-auth', - clientId: 'my-client-id', - }, - myCustomStore, -); +const customStorageApi = createStorage({ + type: 'custom', + name: 'MyCustomStorage', + prefix: 'myPrefix', + custom: myCustomStore, +}); -const customStorageApi = customStorageEffect(); // Use customStorageApi.get(), .set(), .remove() as above ``` ## Configuration -The `storage` function accepts a configuration object with the following properties: - -- `tokenStore`: Specifies the storage mechanism. Can be `'localStorage'`, `'sessionStorage'`, or a custom object conforming to the `TokenStoreObject` interface. -- `prefix`: A string prefix used in generating the storage key. -- `clientId`: The client ID, also used in generating the storage key. +The `createStorage` function accepts a configuration object with the following properties: -An optional second argument allows providing a `customTokenStore` object directly, which overrides the `tokenStore` configuration property if provided. +- `type`: Specifies the storage mechanism. Can be `'localStorage'`, `'sessionStorage'`, or `'custom'`. +- `name`: A string used to generate the storage key. +- `prefix`: An optional string prefix used in generating the storage key. +- `custom`: Required when the `type` is set to `'custom'`. Allows providing a custom storage object directly, which overrides the functionality of the `get`, `set`, and `remove` methods. -The storage key is generated as \`\` `${prefix}-${clientId}` +The storage key is generated as `${prefix}-${name}` diff --git a/packages/sdk-effects/storage/src/lib/storage.effects.test.ts b/packages/sdk-effects/storage/src/lib/storage.effects.test.ts index 25cc7b7645..2d4357a83e 100644 --- a/packages/sdk-effects/storage/src/lib/storage.effects.test.ts +++ b/packages/sdk-effects/storage/src/lib/storage.effects.test.ts @@ -113,7 +113,7 @@ const mockCustomStore: CustomStorageObject = { describe('storage Effect', () => { const storageName = 'MyStorage'; - const baseConfig: Omit = { + const baseConfig: StorageConfig = { type: 'localStorage', name: storageName, prefix: 'testPrefix', diff --git a/packages/sdk-types/README.md b/packages/sdk-types/README.md index 224be8ae17..c5bab3613b 100644 --- a/packages/sdk-types/README.md +++ b/packages/sdk-types/README.md @@ -85,6 +85,18 @@ export interface Tokens { Types for request middleware implementations. +### Authorization Types + +Types for OIDC/OAuth2 authorization workflows. + +### Error Types + +A GenericError type used throughout the Ping Javascript SDK ecosystem. + +### Policy Types + +Password and user attribute validation policy types returned by the server during user registration or password management flows. + ## Usage Import types directly from the package: @@ -110,16 +122,16 @@ const handleCallback = (callback: Callback) => { This package follows the development practices of the overall ForgeRock/Ping Identity JavaScript SDK monorepo. -### Testing +### Building ```bash -pnpm test +nx build sdk-types ``` -### Building +### Testing ```bash -pnpm build +nx test sdk-types ``` ## License diff --git a/packages/sdk-types/src/lib/authorize.types.ts b/packages/sdk-types/src/lib/authorize.types.ts index 523958c36b..f4815d2e73 100644 --- a/packages/sdk-types/src/lib/authorize.types.ts +++ b/packages/sdk-types/src/lib/authorize.types.ts @@ -9,13 +9,12 @@ import type { LegacyConfigOptions } from './legacy-config.types.js'; export type ResponseType = 'code' | 'token'; /** - * Define the options for the authorization URL + * Options for the authorization URL * @param clientId The client ID of the application * @param redirectUri The redirect URI of the application * @param responseType The response type of the authorization request * @param scope The scope of the authorization request */ - export interface GetAuthorizationUrlOptions extends LegacyConfigOptions { /** * These four properties clientid, scope, responseType and redirectUri are required @@ -34,13 +33,10 @@ export interface GetAuthorizationUrlOptions extends LegacyConfigOptions { successParams?: string[]; errorParams?: string[]; } + /** * Generate and store PKCE values for later use - * @param { string } storageKey - Key to store authorization options in sessionStorage - * @param {GenerateAndStoreAuthUrlValues} options - Options for generating PKCE values - * @returns { state: string, verifier: string, GetAuthorizationUrlOptions } */ - export interface GenerateAndStoreAuthUrlValues extends GetAuthorizationUrlOptions { login?: 'redirect' | 'embedded'; clientId: string; diff --git a/packages/sdk-utilities/README.md b/packages/sdk-utilities/README.md index bd3268c193..aae41177a3 100644 --- a/packages/sdk-utilities/README.md +++ b/packages/sdk-utilities/README.md @@ -60,20 +60,33 @@ const verifier = createVerifier(); const challenge = await createChallenge(verifier); ``` -## Development +### Error Utilities -### Testing +Utilities for working with error objects: -To run tests: +- `isGenericError`: TypeScript type guard to check if a value is a `GenericError` -```bash -pnpm test +```typescript +import { isGenericError } from '@forgerock/sdk-utilities'; + +const result = await someOperation(); + +if (isGenericError(result)) { + console.error(`Error (${result.type}): ${result.error}`); + console.error(`Message: ${result.message}`); +} else { + console.log('Operation successful:', result); +} ``` -To run tests in watch mode: +## Development + +### Testing + +To run tests: ```bash -pnpm test:watch +nx test sdk-utilities ``` ### Linting @@ -81,7 +94,7 @@ pnpm test:watch To lint the codebase: ```bash -pnpm lint +nx lint sdk-utilities ``` ## License