diff --git a/.changeset/config.json b/.changeset/config.json index 20254db41..68ca41d48 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -8,7 +8,6 @@ ], "commit": false, "fixed": [["@forgerock/*"]], - "privatePackages": false, "linked": [], "access": "public", "baseBranch": "main", diff --git a/.changeset/empty-brooms-sneeze.md b/.changeset/empty-brooms-sneeze.md new file mode 100644 index 000000000..f749a68ef --- /dev/null +++ b/.changeset/empty-brooms-sneeze.md @@ -0,0 +1,8 @@ +--- +'@forgerock/davinci-client': minor +'@forgerock/sdk-utilities': minor +'@forgerock/shared-types': minor +'@forgerock/effects': minor +--- + +added effects, utilities, and shared-types. ported over types and configuration settings from legacy sdk diff --git a/.changeset/lemon-rocks-dream.md b/.changeset/lemon-rocks-dream.md new file mode 100644 index 000000000..a0f820a43 --- /dev/null +++ b/.changeset/lemon-rocks-dream.md @@ -0,0 +1,6 @@ +--- +'@forgerock/davinci-client': minor +'@forgerock/effects': minor +--- + +add effects package diff --git a/.changeset/slick-cougars-smoke.md b/.changeset/slick-cougars-smoke.md new file mode 100644 index 000000000..837fbba7c --- /dev/null +++ b/.changeset/slick-cougars-smoke.md @@ -0,0 +1,5 @@ +--- +'@forgerock/sdk-utilities': minor +--- + +created sdk-utilities package diff --git a/.gitignore b/.gitignore index ff10da1a1..6d1f53aad 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ packages/**/coverage/ node_modules/ tests/**/app/index.js* tests/**/ie11/ie-bundle.js* +**/out-tsc/* .swc .vite diff --git a/CHANGELOG.md b/CHANGELOG.md index 721d07fd1..58010e1bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ # ForgeRock Javascript SDK Changelogs [ForgeRock DaVinci Client package](./packages/davinci-client/CHANGELOG.md) +[ForgeRock SDK Utilities package](./packages/sdk-utilities/CHANGELOG.md) diff --git a/e2e/davinci-app/main.ts b/e2e/davinci-app/main.ts index bd661a17c..434f9e3d7 100644 --- a/e2e/davinci-app/main.ts +++ b/e2e/davinci-app/main.ts @@ -8,7 +8,6 @@ import './style.css'; import { Config, FRUser, TokenManager } from '@forgerock/javascript-sdk'; import { davinci } from '@forgerock/davinci-client'; - import type { DaVinciConfig, RequestMiddleware } from '@forgerock/davinci-client/types'; import textComponent from './components/text.js'; @@ -27,7 +26,7 @@ const searchParams = new URLSearchParams(qs); const config: DaVinciConfig = serverConfigs[searchParams.get('clientId') || '724ec718-c41c-4d51-98b0-84a583f450f9']; -const requestMiddleware: RequestMiddleware[] = [ +const requestMiddleware: RequestMiddleware<'DAVINCI_NEXT' | 'DAVINCI_START'>[] = [ (fetchArgs, action, next) => { if (action.type === 'DAVINCI_START') { fetchArgs.url.searchParams.set('start', 'true'); @@ -55,7 +54,9 @@ const urlParams = new URLSearchParams(window.location.search); if (continueToken) { resumed = await davinciClient.resume({ continueToken }); } else { - await Config.setAsync(config); + // the current davinci-config has a slightly + // different middleware type than the old legacy config + await Config.setAsync(config as any); } function renderComplete() { const clientInfo = davinciClient.getClient(); diff --git a/e2e/davinci-app/package.json b/e2e/davinci-app/package.json index ae88bac20..5911359ea 100644 --- a/e2e/davinci-app/package.json +++ b/e2e/davinci-app/package.json @@ -5,7 +5,7 @@ "type": "module", "private": true, "nx": { - "tags": ["scope:app"] + "tags": ["scope:e2e"] }, "scripts": { "build": "pnpm nx nxBuild", diff --git a/eslint.config.mjs b/eslint.config.mjs index 1d6acd5c1..4e2e60279 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -57,6 +57,7 @@ export default [ { files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], rules: { + 'import/extensions': [2, 'ignorePackages'], '@nx/enforce-module-boundaries': [ 'warn', { @@ -65,14 +66,26 @@ export default [ depConstraints: [ { sourceTag: 'scope:e2e', - onlyDependOnLibsWithTags: ['scope:app'], + onlyDependOnLibsWithTags: ['scope:package'], }, { sourceTag: 'scope:package', - onlyDependOnLibsWithTags: [], + onlyDependOnLibsWithTags: ['scope:utilities', 'scope:effects', 'scope:shared-types'], + }, + { + sourceTag: 'scope:utilities', + onlyDependOnLibsWithTags: ['scope:shared-types'], + }, + { + sourceTag: 'scope:effects', + onlyDependOnLibsWithTags: ['scope:utilities', 'scope:shared-types'], + }, + { + sourceTag: 'scope:config', + onlyDependOnLibsWithTags: ['scope:utilities', 'scope:shared-types'], }, { - sourceTag: 'scope:types', + sourceTag: 'scope:shared-types', onlyDependOnLibsWithTags: [], }, ], @@ -133,7 +146,7 @@ export default [ }, }, { - ignores: ['dist/*', '**/**/tsconfig.spec.vitest-temp.json'], + ignores: ['**/*.md', 'dist/*', '**/**/tsconfig.spec.vitest-temp.json'], }, { ...packageJson, diff --git a/nx.json b/nx.json index f5efa73b0..ca10a2e4d 100644 --- a/nx.json +++ b/nx.json @@ -25,7 +25,8 @@ "!{projectRoot}/test-setup.[jt]s", "noEslintConfig", "noMarkdown", - "workspaceRootIgnores" + "workspaceRootIgnores", + "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)" ], "noMarkdown": ["!{projectRoot}/*.md", "!{projectRoot}/**/*.md"], "noTests": [ @@ -69,7 +70,7 @@ }, "test": { "inputs": ["default", "^default", "noMarkdown", "^noMarkdown"], - "dependsOn": ["^test"], + "dependsOn": ["^test", "^build"], "outputs": ["{projectRoot}/coverage"], "cache": true }, @@ -152,6 +153,20 @@ "typecheckTargetName": "typecheck" }, "include": ["packages/**/**/*", "e2e/**/**/*"] + }, + { + "plugin": "@nx/vite/plugin", + "options": { + "buildTargetName": "vite:build", + "testTargetName": "vite:test", + "serveTargetName": "vite:serve", + "devTargetName": "vite:dev", + "previewTargetName": "vite:preview", + "serveStaticTargetName": "vite:serve-static", + "typecheckTargetName": "vite:typecheck", + "buildDepsTargetName": "vite:build-deps", + "watchDepsTargetName": "vite:watch-deps" + } } ], "parallel": 1, @@ -161,7 +176,6 @@ }, "generators": { "@nx/js:library": { - "publishable": true, "outDir": "{projectRoot}/dist", "bundler": "tsc", "linter": "eslint", diff --git a/package.json b/package.json index 4bfe89568..bcf549230 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,26 @@ { "name": "ping-javascript-sdk", + "version": "0.0.0", "private": true, "description": "Ping JavaScript SDK", - "packageManager": "pnpm@9.15.9+sha512.68046141893c66fad01c079231128e9afb89ef87e2691d69e4d40eee228988295fd4682181bae55b58418c3a253bde65a505ec7c5f9403ece5cc3cd37dcf2531", - "engines": { - "node": "^20 || ^22", - "pnpm": "9.15.9" + "homepage": "https://github.com/ForgeRock/ping-javascript-sdk#readme", + "bugs": { + "url": "https://github.com/ForgeRock/ping-javascript-sdk/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/ForgeRock/ping-javascript-sdk.git" }, + "author": "ForgeRock", "scripts": { "build": "nx affected --target=build", - "clean": "shx rm -rf ./{coverage,dist,docs,node_modules,tmp}/ ./{packages,e2e}/*/{dist,node_modules}/ && git clean -fX -e \"!.env*,nx-cloud.env\"", + "changeset": "changeset", "ci:release": "pnpm publish -r --no-git-checks && changeset tag", "ci:version": "changeset version && pnpm install --no-frozen-lockfile && pnpm format", - "changeset": "changeset", + "circular-dep-check": "madge --circular .", + "clean": "shx rm -rf ./{coverage,dist,docs,node_modules,tmp}/ ./{packages,e2e}/*/{dist,node_modules}/ && git clean -fX -e \"!.env*,nx-cloud.env\"", "commit": "git cz", + "commitlint": "commitlint --edit", "create-package": "nx g @nx/js:library", "docs": "nx affected --target=typedoc", "format": "pnpm nx format:write", @@ -24,9 +31,8 @@ "serve": "nx serve", "test": "CI=true nx affected:test", "test:e2e": "CI=true nx affected:e2e", - "watch": "nx watch-deps", "verdaccio": "nx local-registry", - "commitlint": "commitlint --edit" + "watch": "nx watch-deps" }, "lint-staged": { "*": [ @@ -36,15 +42,11 @@ "git add" ] }, - "repository": { - "type": "git", - "url": "https://github.com/ForgeRock/ping-javascript-sdk.git" - }, - "author": "ForgeRock", - "bugs": { - "url": "https://github.com/ForgeRock/ping-javascript-sdk/issues" + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } }, - "homepage": "https://github.com/ForgeRock/ping-javascript-sdk#readme", "devDependencies": { "@changesets/changelog-github": "^0.5.0", "@changesets/cli": "^2.27.9", @@ -80,7 +82,7 @@ "@types/node": "22.13.16", "@typescript-eslint/typescript-estree": "8.23.0", "@typescript-eslint/utils": "^8.13.0", - "@vitest/coverage-v8": "3.0.4", + "@vitest/coverage-v8": "^3.0.5", "@vitest/ui": "3.0.4", "conventional-changelog-conventionalcommits": "^8.0.0", "cz-conventional-changelog": "^3.3.0", @@ -97,6 +99,7 @@ "jsdom": "26.0.0", "jsonc-eslint-parser": "^2.1.0", "lint-staged": "^15.0.0", + "madge": "8.0.0", "npm-cli-login": "^1.0.0", "nx": "20.5.0", "playwright": "^1.47.2", @@ -119,10 +122,10 @@ "vitest": "3.0.5", "vitest-canvas-mock": "^0.3.3" }, - "config": { - "commitizen": { - "path": "./node_modules/cz-conventional-changelog" - } + "packageManager": "pnpm@9.15.9+sha512.68046141893c66fad01c079231128e9afb89ef87e2691d69e4d40eee228988295fd4682181bae55b58418c3a253bde65a505ec7c5f9403ece5cc3cd37dcf2531", + "engines": { + "node": "^20 || ^22", + "pnpm": "9.15.9" }, "nx": { "includedScripts": [] diff --git a/packages/davinci-client/package.json b/packages/davinci-client/package.json index 798974d2b..262150a7a 100644 --- a/packages/davinci-client/package.json +++ b/packages/davinci-client/package.json @@ -22,7 +22,8 @@ "test:watch": "pnpm nx nxTest --watch" }, "dependencies": { - "@forgerock/javascript-sdk": "4.7.0", + "@forgerock/effects": "workspace:*", + "@forgerock/shared-types": "workspace:*", "@reduxjs/toolkit": "catalog:", "immer": "catalog:" }, diff --git a/packages/davinci-client/src/lib/client.store.ts b/packages/davinci-client/src/lib/client.store.ts index a3d0a7723..d53a3133b 100644 --- a/packages/davinci-client/src/lib/client.store.ts +++ b/packages/davinci-client/src/lib/client.store.ts @@ -13,6 +13,7 @@ import { davinciApi } from './davinci.api.js'; import { configSlice } from './config.slice.js'; import { wellknownApi } from './wellknown.api.js'; +import type { ActionTypes, RequestMiddleware } from '@forgerock/shared-types'; /** * Import the DaVinciRequest types */ @@ -31,7 +32,6 @@ import type { import type { InitFlow, Updater, Validator } from './client.types.js'; import { returnValidator } from './collector.utils.js'; import { authorize } from './davinci.utils.js'; -import type { RequestMiddleware } from './effects/request.effect.types.js'; /** * Create a client function that returns a set of methods @@ -41,12 +41,12 @@ import type { RequestMiddleware } from './effects/request.effect.types.js'; * @param {ConfigurationOptions} options - the configuration options for the client * @returns {Observable} - an observable client for DaVinci flows */ -export async function davinci({ +export async function davinci({ config, requestMiddleware, }: { config: DaVinciConfig; - requestMiddleware?: RequestMiddleware[]; + requestMiddleware?: RequestMiddleware[]; }) { const store = createClientStore({ requestMiddleware }); diff --git a/packages/davinci-client/src/lib/client.store.utils.ts b/packages/davinci-client/src/lib/client.store.utils.ts index 4330b463f..d09cbc576 100644 --- a/packages/davinci-client/src/lib/client.store.utils.ts +++ b/packages/davinci-client/src/lib/client.store.utils.ts @@ -6,18 +6,17 @@ */ import { configureStore } from '@reduxjs/toolkit'; +import type { ActionTypes, RequestMiddleware } from '@forgerock/shared-types'; import { configSlice } from './config.slice.js'; import { nodeSlice } from './node.slice.js'; import { davinciApi } from './davinci.api.js'; import { ErrorNode, ContinueNode, StartNode, SuccessNode } from '../types.js'; import { wellknownApi } from './wellknown.api.js'; -import type { RequestMiddleware } from './effects/request.effect.types.js'; - -export function createClientStore({ +export function createClientStore({ requestMiddleware, }: { - requestMiddleware?: RequestMiddleware[]; + requestMiddleware?: RequestMiddleware[]; }) { return configureStore({ reducer: { diff --git a/packages/davinci-client/src/lib/config.types.test-d.ts b/packages/davinci-client/src/lib/config.types.test-d.ts index b35a04395..4a6db3f23 100644 --- a/packages/davinci-client/src/lib/config.types.test-d.ts +++ b/packages/davinci-client/src/lib/config.types.test-d.ts @@ -6,7 +6,7 @@ */ 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 { AsyncConfigOptions } from '@forgerock/shared-types'; import type { WellknownResponse } from './wellknown.types.js'; describe('Config Types', () => { diff --git a/packages/davinci-client/src/lib/config.types.ts b/packages/davinci-client/src/lib/config.types.ts index 0b4392719..bb0192dea 100644 --- a/packages/davinci-client/src/lib/config.types.ts +++ b/packages/davinci-client/src/lib/config.types.ts @@ -7,7 +7,7 @@ /** * Import ConfigOptions type from the JavaScript SDK */ -import type { AsyncConfigOptions } from '@forgerock/javascript-sdk/src/config/interfaces'; +import type { AsyncConfigOptions } from '@forgerock/shared-types'; import { WellknownResponse } from './wellknown.types.js'; export interface DaVinciConfig extends AsyncConfigOptions { diff --git a/packages/davinci-client/src/lib/davinci.api.ts b/packages/davinci-client/src/lib/davinci.api.ts index 92bb03a3e..38bbdde94 100644 --- a/packages/davinci-client/src/lib/davinci.api.ts +++ b/packages/davinci-client/src/lib/davinci.api.ts @@ -20,7 +20,10 @@ import { /** * Import internal modules */ -import { createAuthorizeUrl } from './authorize.utils.js'; +import { initQuery } from '@forgerock/effects'; +import type { RequestMiddleware } from '@forgerock/shared-types'; + +import { createAuthorizeUrl } from '@forgerock/effects'; import { handleResponse, transformActionRequest, transformSubmitRequest } from './davinci.utils.js'; /** @@ -35,15 +38,14 @@ import type { } from './davinci.types.js'; import type { ContinueNode } from './node.types.js'; import type { StartNode } from '../types.js'; -import { initQuery } from './effects/request.effect.utils.js'; -import { RequestMiddleware } from './effects/request.effect.types.js'; +import { ActionTypes } from '@forgerock/shared-types'; type BaseQueryResponse = Promise< QueryReturnValue >; -interface Extras { - requestMiddleware: RequestMiddleware[]; +interface Extras { + requestMiddleware: RequestMiddleware[]; } /** @@ -250,7 +252,7 @@ export const davinciApi = createApi({ clientId: state?.config?.clientId, login: 'redirect', // TODO: improve this in SDK to be more semantic redirectUri: state?.config?.redirectUri, - responseType: state?.config?.responseType, + responseType: state?.config?.responseType as 'code', scope: state?.config?.scope, }); const url = new URL(authorizeUrl); diff --git a/packages/davinci-client/src/lib/effects/request.effect.types.ts b/packages/davinci-client/src/lib/effects/request.effect.types.ts deleted file mode 100644 index 3c5bb97d3..000000000 --- a/packages/davinci-client/src/lib/effects/request.effect.types.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2025 Ping Identity Corporation. All rights reserved. - * - * This software may be modified and distributed under the terms - * of the MIT license. See the LICENSE file for details. - */ -import { - FetchArgs, - FetchBaseQueryError, - FetchBaseQueryMeta, - QueryReturnValue, -} from '@reduxjs/toolkit/query'; - -import type { ActionTypes } from './request.effect.unions.js'; - -export interface Action { - type: ActionTypes; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - payload: any; -} - -export interface ModifiedFetchArgs extends Omit { - url: URL; - headers?: Headers; -} - -export type RequestMiddleware = ( - req: ModifiedFetchArgs, - action: Action, - next: () => ModifiedFetchArgs, -) => void; - -export interface RequestObj { - url: URL; - init: RequestInit; -} - -export interface QueryApi { - applyMiddleware(middleware: RequestMiddleware[]): QueryApi; - applyQuery( - callback: ( - request: FetchArgs, - ) => Promise>, - ): Promise>; -} diff --git a/packages/davinci-client/src/lib/effects/request.effect.unions.ts b/packages/davinci-client/src/lib/effects/request.effect.unions.ts deleted file mode 100644 index e454a4d7a..000000000 --- a/packages/davinci-client/src/lib/effects/request.effect.unions.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2025 Ping Identity Corporation. All rights reserved. - * - * This software may be modified and distributed under the terms - * of the MIT license. See the LICENSE file for details. - */ -export const actionTypes = { - start: 'DAVINCI_START', - next: 'DAVINCI_NEXT', - flow: 'DAVINCI_FLOW', - success: 'DAVINCI_SUCCESS', - error: 'DAVINCI_ERROR', - failure: 'DAVINCI_FAILURE', - resume: 'DAVINCI_RESUME', -} as const; - -export type ActionTypes = (typeof actionTypes)[keyof typeof actionTypes]; -export type EndpointTypes = keyof typeof actionTypes; diff --git a/packages/davinci-client/src/lib/node.utils.ts b/packages/davinci-client/src/lib/node.utils.ts index cea5f2244..4eee644f1 100644 --- a/packages/davinci-client/src/lib/node.utils.ts +++ b/packages/davinci-client/src/lib/node.utils.ts @@ -4,8 +4,8 @@ * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ -import { DavinciErrorResponse } from './davinci.types'; -import { CollectorErrors } from './node.types'; +import { DavinciErrorResponse } from './davinci.types.js'; +import { CollectorErrors } from './node.types.js'; export function getCollectorErrors(error: DavinciErrorResponse) { const details = error.details; diff --git a/packages/davinci-client/src/types.ts b/packages/davinci-client/src/types.ts index 91175abe0..f24ac708f 100644 --- a/packages/davinci-client/src/types.ts +++ b/packages/davinci-client/src/types.ts @@ -6,11 +6,11 @@ */ import 'immer'; // Side-effect needed only for getting types in workspace +import type { RequestMiddleware } from '@forgerock/shared-types'; import type * as collectors from './lib/collector.types.js'; import type * as config from './lib/config.types.js'; import type * as nodes from './lib/node.types.js'; import type * as client from './lib/client.types.js'; -import type * as effect from './lib/effects/request.effect.types.js'; export type DaVinciConfig = config.DaVinciConfig; @@ -43,5 +43,4 @@ export type ValidatedTextCollector = collectors.ValidatedTextCollector; export type ReadOnlyCollector = collectors.ReadOnlyCollector; export type MultiSelectCollector = collectors.MultiSelectCollector; export type SingleSelectCollector = collectors.SingleSelectCollector; - -export type RequestMiddleware = effect.RequestMiddleware; +export type { RequestMiddleware }; diff --git a/packages/davinci-client/tsconfig.json b/packages/davinci-client/tsconfig.json index eefb01564..146d11cbd 100644 --- a/packages/davinci-client/tsconfig.json +++ b/packages/davinci-client/tsconfig.json @@ -10,6 +10,12 @@ "resolveJsonModule": true }, "references": [ + { + "path": "../shared-types" + }, + { + "path": "../effects" + }, { "path": "./tsconfig.lib.json" }, diff --git a/packages/davinci-client/tsconfig.lib.json b/packages/davinci-client/tsconfig.lib.json index d63f38811..ce9e9e396 100644 --- a/packages/davinci-client/tsconfig.lib.json +++ b/packages/davinci-client/tsconfig.lib.json @@ -1,7 +1,8 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "moduleResolution": "Bundler", + "moduleResolution": "nodenext", + "module": "nodenext", "target": "ES2022", "outDir": "./dist", "resolveJsonModule": true, @@ -28,5 +29,13 @@ "src/**/*.types.test-d.ts", "src/**/*.utils.test-d.ts", "src/lib/mock-data/*" + ], + "references": [ + { + "path": "../shared-types/tsconfig.lib.json" + }, + { + "path": "../effects/tsconfig.lib.json" + } ] } diff --git a/packages/effects/README.md b/packages/effects/README.md new file mode 100644 index 000000000..8dc19b3df --- /dev/null +++ b/packages/effects/README.md @@ -0,0 +1,11 @@ +# effects + +This library was generated with [Nx](https://nx.dev). + +## Building + +Run `nx build effects` to build the library. + +## Running unit tests + +Run `nx test effects` to execute the unit tests via [Vitest](https://vitest.dev/). diff --git a/packages/effects/eslint.config.mjs b/packages/effects/eslint.config.mjs new file mode 100644 index 000000000..9a8d5fa69 --- /dev/null +++ b/packages/effects/eslint.config.mjs @@ -0,0 +1,41 @@ +import baseConfig from '../../eslint.config.mjs'; + +export default [ + ...baseConfig, + { + files: ['**/*.json'], + rules: { + '@nx/dependency-checks': [ + 'error', + { + ignoredFiles: [ + '{projectRoot}/*.test.{js,cjs,mjs,ts}', + '{projectRoot}/eslint.config.{js,cjs,mjs}', + '{projectRoot}/vite.config.ts', + ], + }, + ], + }, + languageOptions: { + parser: await import('jsonc-eslint-parser'), + }, + }, + { + ignores: [ + '**/*.md', + 'LICENSE', + '.babelrc', + '.env*', + '.bin', + 'dist', + '.eslintignore', + 'docs', + 'coverage', + 'vite.config.*.timestamp*', + '*tsconfig.tsbuildinfo*', + '**/**/mock-data/*.d.ts*', + 'out-tsc', + 'node_modules', + ], + }, +]; diff --git a/packages/effects/package.json b/packages/effects/package.json new file mode 100644 index 000000000..289dc3ebd --- /dev/null +++ b/packages/effects/package.json @@ -0,0 +1,55 @@ +{ + "name": "@forgerock/effects", + "version": "0.0.1", + "private": true, + "repository": { + "type": "git", + "url": "git+https://github.com/ForgeRock/ping-javascript-sdk.git", + "directory": "packages/effects" + }, + "sideEffects": false, + "type": "module", + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js", + "default": "./dist/src/index.js" + }, + "./package.json": "./package.json", + "./types": "./dist/src/types.js" + }, + "main": "./dist/src/index.js", + "module": "./dist/src/index.js", + "types": "./dist/src/index.d.ts", + "files": ["dist/*", "!dist/tsconfig.lib.tsbuildinfo"], + "scripts": { + "lint": "pnpm nx nxLint", + "test": "pnpm nx nxTest", + "test:watch": "pnpm nx nxTest --watch" + }, + "dependencies": { + "@forgerock/sdk-utilities": "workspace:*", + "@forgerock/shared-types": "workspace:*", + "@reduxjs/toolkit": "catalog:", + "tslib": "^2.5.0" + }, + "devDependencies": { + "vite": "6.2.5" + }, + "nx": { + "tags": ["scope:effects"], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "packages/effects/dist", + "main": "packages/effects/src/index.ts", + "tsConfig": "packages/effects/tsconfig.lib.json", + "generatePackageJson": false, + "assets": [] + } + } + } + } +} diff --git a/packages/effects/src/index.ts b/packages/effects/src/index.ts new file mode 100644 index 000000000..1fc329e4c --- /dev/null +++ b/packages/effects/src/index.ts @@ -0,0 +1,3 @@ +export * from './lib/request.utils.js'; +export * from './lib/authorize.utils.js'; +export * from './lib/state-pkce.js'; diff --git a/packages/davinci-client/src/lib/effects/architecture-design.md b/packages/effects/src/lib/architecture-design.md similarity index 100% rename from packages/davinci-client/src/lib/effects/architecture-design.md rename to packages/effects/src/lib/architecture-design.md diff --git a/packages/davinci-client/src/lib/authorize.utils.ts b/packages/effects/src/lib/authorize.utils.ts similarity index 58% rename from packages/davinci-client/src/lib/authorize.utils.ts rename to packages/effects/src/lib/authorize.utils.ts index 183eeec16..cb36a3583 100644 --- a/packages/davinci-client/src/lib/authorize.utils.ts +++ b/packages/effects/src/lib/authorize.utils.ts @@ -7,23 +7,10 @@ /** * Import the PKCE and ResponseType utilities from the JavaScript SDK */ -import { PKCE, ResponseType } from '@forgerock/javascript-sdk'; -import { generateAndStoreAuthUrlValues } from '@forgerock/javascript-sdk/src/oauth2-client/state-pkce'; +import { createChallenge } from '@forgerock/sdk-utilities'; +import { GetAuthorizationUrlOptions } from '@forgerock/shared-types'; -/** - * Define the 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 { - clientId: string; - login: 'redirect'; - redirectUri: string; - responseType: string; - scope: string; -} +import { generateAndStoreAuthUrlValues } from './state-pkce.js'; /** * @function createAuthorizeUrl - Create authorization URL for initial call to DaVinci @@ -42,15 +29,13 @@ export async function createAuthorizeUrl( const [authorizeUrlOptions, storeOptions] = generateAndStoreAuthUrlValues({ clientId: options.clientId, - login: options.login, - // this type fails when module resolution is Node16 - // Probably because the javascript-sdk is set to bundler - // so we need to make this correct with .js extensions if possible serverConfig: { baseUrl }, - responseType: ResponseType.Code, + responseType: 'code', + redirectUri: options.redirectUri, + scope: options.scope, }); - const challenge = await PKCE.createChallenge(authorizeUrlOptions.verifier); + const challenge = await createChallenge(authorizeUrlOptions.verifier); const requestParams = new URLSearchParams({ code_challenge: challenge, diff --git a/packages/effects/src/lib/logger.test.ts b/packages/effects/src/lib/logger.test.ts new file mode 100644 index 000000000..013deaec1 --- /dev/null +++ b/packages/effects/src/lib/logger.test.ts @@ -0,0 +1,65 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import logger from './logger.js'; + +describe('logger', () => { + const consoleErrorSpy = vi.spyOn(console, 'error'); + const consoleWarnSpy = vi.spyOn(console, 'warn'); + const consoleInfoSpy = vi.spyOn(console, 'info'); + const consoleDebugSpy = vi.spyOn(console, 'debug'); + + beforeEach(() => { + consoleErrorSpy.mockReset(); + consoleWarnSpy.mockReset(); + consoleInfoSpy.mockReset(); + consoleDebugSpy.mockReset(); + logger.setLevel('info'); // Reset to default level before each test + }); + + it('should log error messages when level is error or higher', () => { + logger.setLevel('error'); + logger.error('test error'); + expect(consoleErrorSpy).toHaveBeenCalledWith('test error'); + logger.warn('test warn'); + expect(consoleWarnSpy).not.toHaveBeenCalled(); + }); + + it('should log warn messages when level is warn or higher', () => { + logger.setLevel('warn'); + logger.warn('test warn'); + expect(consoleWarnSpy).toHaveBeenCalledWith('test warn'); + logger.info('test info'); + expect(consoleInfoSpy).not.toHaveBeenCalled(); + }); + + it('should log info messages when level is info or higher', () => { + logger.setLevel('info'); + logger.info('test info'); + expect(consoleInfoSpy).toHaveBeenCalledWith('test info'); + logger.debug('test debug'); + expect(consoleDebugSpy).not.toHaveBeenCalled(); + }); + + it('should log debug messages when level is debug', () => { + logger.setLevel('debug'); + logger.debug('test debug'); + expect(consoleDebugSpy).toHaveBeenCalledWith('test debug'); + }); + + it('should not log messages when level is none', () => { + logger.setLevel('none'); + logger.error('test error'); + logger.warn('test warn'); + logger.info('test info'); + logger.debug('test debug'); + expect(consoleErrorSpy).not.toHaveBeenCalled(); + expect(consoleWarnSpy).not.toHaveBeenCalled(); + expect(consoleInfoSpy).not.toHaveBeenCalled(); + expect(consoleDebugSpy).not.toHaveBeenCalled(); + }); + + it('should handle multiple arguments correctly', () => { + logger.setLevel('debug'); + logger.debug('test', 123, { key: 'value' }); + expect(consoleDebugSpy).toHaveBeenCalledWith('test', 123, { key: 'value' }); + }); +}); diff --git a/packages/effects/src/lib/logger.ts b/packages/effects/src/lib/logger.ts new file mode 100644 index 000000000..ff822d446 --- /dev/null +++ b/packages/effects/src/lib/logger.ts @@ -0,0 +1,64 @@ +// Define log levels +type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'none'; + +// Define log message type +type LogMessage = string | number | object; + +// Create logger configuration +interface LoggerConfig { + level: LogLevel; +} + +const config: LoggerConfig = { + level: 'info', // Default log level +}; + +// Implement log functions +const logFunctions = { + error: (...args: LogMessage[]) => console.error(...args), + warn: (...args: LogMessage[]) => console.warn(...args), + info: (...args: LogMessage[]) => console.info(...args), + debug: (...args: LogMessage[]) => console.debug(...args), +}; + +// Implement level inclusion +const shouldLog = (level: LogLevel, currentLevel: LogLevel): boolean => { + const levelMap: { [key in LogLevel]: number } = { + error: 0, + warn: 1, + info: 2, + debug: 3, + none: -1, + }; + + return levelMap[level] <= levelMap[currentLevel] && levelMap[currentLevel] !== -1; +}; + +// Compose logger module +const logger = { + setLevel: (level: LogLevel) => { + config.level = level; + }, + error: (...args: LogMessage[]) => { + if (shouldLog('error', config.level)) { + logFunctions.error(...args); + } + }, + warn: (...args: LogMessage[]) => { + if (shouldLog('warn', config.level)) { + logFunctions.warn(...args); + } + }, + info: (...args: LogMessage[]) => { + if (shouldLog('info', config.level)) { + logFunctions.info(...args); + } + }, + debug: (...args: LogMessage[]) => { + if (shouldLog('debug', config.level)) { + logFunctions.debug(...args); + } + }, +}; + +export default logger; diff --git a/packages/davinci-client/src/lib/effects/request.effect.mock.ts b/packages/effects/src/lib/request.mock.ts similarity index 93% rename from packages/davinci-client/src/lib/effects/request.effect.mock.ts rename to packages/effects/src/lib/request.mock.ts index facb58328..814184723 100644 --- a/packages/davinci-client/src/lib/effects/request.effect.mock.ts +++ b/packages/effects/src/lib/request.mock.ts @@ -14,8 +14,12 @@ * of the MIT license. See the LICENSE file for details. */ -import type { Action, ModifiedFetchArgs, RequestMiddleware } from './request.effect.types.js'; -import type { ActionTypes } from './request.effect.unions.js'; +import type { + Action, + ActionTypes, + ModifiedFetchArgs, + RequestMiddleware, +} from '@forgerock/shared-types'; type NextFn = () => ModifiedFetchArgs; @@ -27,7 +31,7 @@ const add = 'ADD' as ActionTypes; const reassignment = 'REASSIGNMENT' as ActionTypes; const mutateAction = 'MUTATE-ACTION' as ActionTypes; -const middleware: RequestMiddleware[] = [ +const middleware: RequestMiddleware[] = [ (req: ModifiedFetchArgs, action: Action, next: NextFn): void => { switch (action.type) { case a: diff --git a/packages/davinci-client/src/lib/effects/request.effect.utils.test.ts b/packages/effects/src/lib/request.utils.test.ts similarity index 88% rename from packages/davinci-client/src/lib/effects/request.effect.utils.test.ts rename to packages/effects/src/lib/request.utils.test.ts index 6763fbc39..c76c1a941 100644 --- a/packages/davinci-client/src/lib/effects/request.effect.utils.test.ts +++ b/packages/effects/src/lib/request.utils.test.ts @@ -4,17 +4,16 @@ * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ -import { initQuery, middlewareWrapper } from './request.effect.utils.js'; -import middleware from './request.effect.mock.js'; -import type { ActionTypes } from './request.effect.unions.js'; import { FetchArgs, FetchBaseQueryError, FetchBaseQueryMeta, QueryReturnValue, } from '@reduxjs/toolkit/query'; -import { ModifiedFetchArgs } from './request.effect.types.js'; -import { Action } from '@reduxjs/toolkit'; +import type { Action, ActionTypes, ModifiedFetchArgs } from '@forgerock/shared-types'; + +import { initQuery, middlewareWrapper } from './request.utils.js'; +import middleware from './request.mock.js'; type BaseQueryResponse = Promise< QueryReturnValue @@ -117,7 +116,11 @@ describe('initQuery function', () => { }; const queryApi = initQuery(fetchArgs, endpoint); - const response = await queryApi.applyQuery(async (fetchArgs) => await mockQuery(fetchArgs)); + const response = await queryApi.applyQuery( + // TODO: this is being required to be passed in + // it probably shouldn't but we can review later + async (fetchArgs: FetchArgs) => await mockQuery(fetchArgs), + ); expect(resultFetchArgs.url.toString()).toBe('https://www.example.com/'); expect(resultFetchArgs.headers).toStrictEqual(new Headers()); @@ -140,7 +143,9 @@ describe('initQuery function', () => { }; const queryApi = initQuery(fetchArgs, endpoint).applyMiddleware(requestMiddleware); - const response = await queryApi.applyQuery(async (fetchArgs) => await mockQuery(fetchArgs)); + const response = await queryApi.applyQuery( + async (fetchArgs: FetchArgs) => await mockQuery(fetchArgs), + ); expect(resultFetchArgs.url.toString()).toBe('https://www.example.com/?searchParam=abc'); expect(resultFetchArgs.headers).toStrictEqual(new Headers({ 'x-new-header': '123' })); @@ -163,7 +168,9 @@ describe('initQuery function', () => { }; const queryApi = initQuery(fetchArgs, endpoint).applyMiddleware(undefined); - const response = await queryApi.applyQuery(async (fetchArgs) => await mockQuery(fetchArgs)); + const response = await queryApi.applyQuery( + async (fetchArgs: FetchArgs) => await mockQuery(fetchArgs), + ); expect(resultFetchArgs.url.toString()).toBe('https://www.example.com/'); expect(resultFetchArgs.headers).toStrictEqual(new Headers()); @@ -173,7 +180,7 @@ describe('initQuery function', () => { it('should initialize query and handle unmatched action type', async () => { let resultFetchArgs = {} as FetchArgs; - const fetchArgs = { url: 'https://www.example.com' }; + const fetchArgs: FetchArgs = { url: 'https://www.example.com' }; const endpoint = 'unknown'; const mockQuery = async (passedFetchArgs: FetchArgs) => { resultFetchArgs = passedFetchArgs; @@ -187,7 +194,9 @@ describe('initQuery function', () => { // @ts-expect-error - Intentionally testing an unknown action type const queryApi = initQuery(fetchArgs, endpoint).applyMiddleware(requestMiddleware); - const response = await queryApi.applyQuery(async (fetchArgs) => await mockQuery(fetchArgs)); + const response = await queryApi.applyQuery( + async (fetchArgs: FetchArgs) => await mockQuery(fetchArgs), + ); expect(resultFetchArgs.url.toString()).toBe('https://www.example.com/'); expect(resultFetchArgs.headers).toStrictEqual(new Headers()); diff --git a/packages/davinci-client/src/lib/effects/request.effect.utils.ts b/packages/effects/src/lib/request.utils.ts similarity index 84% rename from packages/davinci-client/src/lib/effects/request.effect.utils.ts rename to packages/effects/src/lib/request.utils.ts index 191b51644..d52055f65 100644 --- a/packages/davinci-client/src/lib/effects/request.effect.utils.ts +++ b/packages/effects/src/lib/request.utils.ts @@ -10,10 +10,14 @@ import { FetchBaseQueryMeta, QueryReturnValue, } from '@reduxjs/toolkit/query'; -import { actionTypes } from './request.effect.unions.js'; -import type { ActionTypes, EndpointTypes } from './request.effect.unions.js'; -import type { ModifiedFetchArgs, RequestMiddleware } from './request.effect.types.js'; +import { actionTypes } from '@forgerock/shared-types'; +import type { + ActionTypes, + EndpointTypes, + ModifiedFetchArgs, + RequestMiddleware, +} from '@forgerock/shared-types'; /** * @function middlewareWrapper - A "Node" and "Redux" style middleware that is called just before @@ -28,11 +32,11 @@ export function middlewareWrapper( request: ModifiedFetchArgs, // eslint-disable-next-line { type, payload }: { type: ActionTypes; payload?: any }, -): (middleware: RequestMiddleware[] | undefined) => ModifiedFetchArgs { +): (middleware: RequestMiddleware[] | undefined) => ModifiedFetchArgs { // no mutation and no reassignment const actionCopy = Object.freeze({ type, payload }); - return (middleware: RequestMiddleware[] | undefined) => { + return (middleware: RequestMiddleware[] | undefined) => { if (!Array.isArray(middleware)) { return request; } @@ -63,7 +67,9 @@ export function initQuery(fetchArgs: FetchArgs, endpoint: EndpointTypes) { headers: new Headers(fetchArgs.headers as Record), }; const queryApi = { - applyMiddleware(middleware: RequestMiddleware[] | undefined) { + applyMiddleware( + middleware: RequestMiddleware[] | undefined, + ) { // Iterates and executes provided middleware functions // Allow middleware to mutate `request` argument const runMiddleware = middlewareWrapper(modifiedRequest, { type: actionTypes[endpoint] }); diff --git a/packages/effects/src/lib/state-pkce.ts b/packages/effects/src/lib/state-pkce.ts new file mode 100644 index 000000000..6b16507f2 --- /dev/null +++ b/packages/effects/src/lib/state-pkce.ts @@ -0,0 +1,57 @@ +import { createVerifier, createState } from '@forgerock/sdk-utilities'; +import { GetAuthorizationUrlOptions } from '@forgerock/shared-types'; + +function getStorageKey(clientId: string, prefix?: string) { + return `${prefix || 'FR-SDK'}-authflow-${clientId}`; +} + +/** + * 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 } + */ +interface GenerateAndStoreAuthUrlValues extends GetAuthorizationUrlOptions { + login?: 'redirect' | 'embedded'; + clientId: string; + prefix?: string; +} + +export function generateAndStoreAuthUrlValues( + options: GenerateAndStoreAuthUrlValues, +): readonly [GetAuthorizationUrlOptions & { state: string; verifier: string }, () => void] { + const verifier = createVerifier(); + const state = createState(); + const storageKey = getStorageKey(options.clientId, options.prefix); + + const authorizeUrlOptions = { + ...options, + state, + verifier, + }; + + return [ + authorizeUrlOptions, + () => sessionStorage.setItem(storageKey, JSON.stringify(authorizeUrlOptions)), + ] as const; +} + +/** + * @function getStoredAuthUrlValues - Retrieve stored authorization options from sessionStorage + * @param { string } storageKey - Key to retrieve stored values from sessionStorage + * @returns { GetAuthorizationUrlOptions } + */ +export function getStoredAuthUrlValues( + clientId: string, + prefix?: string, +): GetAuthorizationUrlOptions { + const storageKey = getStorageKey(clientId, prefix); + const storedString = sessionStorage.getItem(storageKey); + sessionStorage.removeItem(storageKey); + + try { + return JSON.parse(storedString as string); + } catch { + throw new Error('Stored values for Auth URL could not be parsed'); + } +} diff --git a/packages/effects/src/types.ts b/packages/effects/src/types.ts new file mode 100644 index 000000000..c2f36efb5 --- /dev/null +++ b/packages/effects/src/types.ts @@ -0,0 +1 @@ +export type * from './lib/request.utils.js'; diff --git a/packages/effects/tsconfig.json b/packages/effects/tsconfig.json new file mode 100644 index 000000000..54a8b460e --- /dev/null +++ b/packages/effects/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "../shared-types" + }, + { + "path": "../sdk-utilities" + }, + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "nx": { + "addTypecheckTarget": false + } +} diff --git a/packages/effects/tsconfig.lib.json b/packages/effects/tsconfig.lib.json new file mode 100644 index 000000000..d2a740f9c --- /dev/null +++ b/packages/effects/tsconfig.lib.json @@ -0,0 +1,44 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", + "emitDeclarationOnly": false, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "module": "nodenext", + "moduleResolution": "nodenext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "importHelpers": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "types": [] + }, + "include": ["src/**/*.ts"], + "references": [ + { + "path": "../shared-types/tsconfig.lib.json" + }, + { + "path": "../sdk-utilities/tsconfig.lib.json" + } + ], + "exclude": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.mock.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx" + ] +} diff --git a/packages/effects/tsconfig.spec.json b/packages/effects/tsconfig.spec.json new file mode 100644 index 000000000..96c7e8a17 --- /dev/null +++ b/packages/effects/tsconfig.spec.json @@ -0,0 +1,42 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out-tsc/vitest", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "module": "nodenext", + "moduleResolution": "nodenext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "importHelpers": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.mock.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/packages/effects/typedoc.json b/packages/effects/typedoc.json new file mode 100644 index 000000000..f2ac83841 --- /dev/null +++ b/packages/effects/typedoc.json @@ -0,0 +1,4 @@ +{ + "name": "@forgerock/effects", + "entryPoints": ["src/index.ts", "src/types.ts"] +} diff --git a/packages/effects/vite.config.ts b/packages/effects/vite.config.ts new file mode 100644 index 000000000..38efdbb78 --- /dev/null +++ b/packages/effects/vite.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig(() => ({ + root: __dirname, + cacheDir: '../../node_modules/.vite/packages/effects', + plugins: [], + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + test: { + watch: false, + globals: true, + environment: 'node', + include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + }, + }, +})); diff --git a/packages/sdk-utilities/CHANGELOG.md b/packages/sdk-utilities/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/packages/sdk-utilities/README.md b/packages/sdk-utilities/README.md new file mode 100644 index 000000000..b3c8b5e73 --- /dev/null +++ b/packages/sdk-utilities/README.md @@ -0,0 +1,11 @@ +# sdk-utilities + +This library was generated with [Nx](https://nx.dev). + +## Building + +Run `nx build sdk-utilities` to build the library. + +## Running unit tests + +Run `nx test sdk-utilities` to execute the unit tests via [Vitest](https://vitest.dev/). diff --git a/packages/sdk-utilities/eslint.config.mjs b/packages/sdk-utilities/eslint.config.mjs new file mode 100644 index 000000000..0fc12a756 --- /dev/null +++ b/packages/sdk-utilities/eslint.config.mjs @@ -0,0 +1,56 @@ +import baseConfig from '../../eslint.config.mjs'; + +export default [ + { + ignores: ['**/dist'], + }, + ...baseConfig, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + // Override or add rules here + rules: {}, + }, + { + files: ['**/*.ts', '**/*.tsx'], + // Override or add rules here + rules: {}, + }, + { + files: ['**/*.js', '**/*.jsx'], + // Override or add rules here + rules: {}, + }, + { + files: ['**/*.json'], + rules: { + '@nx/dependency-checks': [ + 'error', + { + ignoredFiles: ['{projectRoot}/vite.config.{js,ts,mjs,mts}'], + }, + ], + }, + languageOptions: { + parser: await import('jsonc-eslint-parser'), + }, + }, + { + ignores: ['README.md'], + }, + { + ignores: [ + '**/*.md', + 'LICENSE', + '.babelrc', + '.env*', + '.bin', + 'dist', + '.eslintignore', + 'docs', + 'coverage', + 'vite.config.*.timestamp*', + '*tsconfig.tsbuildinfo*', + '**/**/mock-data/*.d.ts*', + ], + }, +]; diff --git a/packages/sdk-utilities/package.json b/packages/sdk-utilities/package.json new file mode 100644 index 000000000..fefa87fac --- /dev/null +++ b/packages/sdk-utilities/package.json @@ -0,0 +1,45 @@ +{ + "name": "@forgerock/sdk-utilities", + "version": "0.0.1", + "private": true, + "repository": { + "type": "git", + "url": "git+https://github.com/ForgeRock/ping-javascript-sdk.git", + "directory": "packages/sdk-utilities" + }, + "sideEffects": false, + "type": "module", + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js", + "default": "./dist/src/index.js" + }, + "./package.json": "./package.json", + "./types": "./dist/src/types.js" + }, + "main": "./dist/src/index.js", + "module": "./dist/src/index.js", + "files": ["dist"], + "scripts": { + "lint": "pnpm nx nxLint", + "test": "pnpm nx nxTest", + "test:watch": "pnpm nx nxTest --watch" + }, + "nx": { + "tags": ["scope:utilities"], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "packages/sdk-utilities/dist", + "main": "packages/sdk-utilities/src/index.ts", + "tsConfig": "packages/sdk-utilities/tsconfig.lib.json", + "generatePackageJson": false, + "assets": [] + } + } + } + } +} diff --git a/packages/sdk-utilities/src/index.ts b/packages/sdk-utilities/src/index.ts new file mode 100644 index 000000000..b3000fd07 --- /dev/null +++ b/packages/sdk-utilities/src/index.ts @@ -0,0 +1,11 @@ +/** + * + * Copyright © 2025 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + **/ + +export * from './lib/pkce.utils.js'; +export * from './lib/url.utils.js'; diff --git a/packages/sdk-utilities/src/lib/pkce.utils.test.ts b/packages/sdk-utilities/src/lib/pkce.utils.test.ts new file mode 100644 index 000000000..3b9a60565 --- /dev/null +++ b/packages/sdk-utilities/src/lib/pkce.utils.test.ts @@ -0,0 +1,50 @@ +/** + * + * Copyright © 2025 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + **/ + +/** + * @jest-environment jsdom + */ +import { expect, describe, it } from 'vitest'; +import * as crypto from 'crypto'; +import { TextEncoder } from 'util'; +import { createChallenge, createVerifier } from './pkce.utils.js'; + +declare let window: unknown; + +Object.defineProperty(window, 'crypto', { + value: { + getRandomValues: (array: Buffer): Buffer => crypto.randomFillSync(array), + subtle: { + digest: (alg: string, array: Uint8Array): Buffer => { + if (alg === 'SHA-256') { + return crypto.createHash('sha256').update(array).digest(); + } + throw new Error(`Unsupported algorithm "${alg}"`); + }, + }, + }, +}); + +Object.defineProperty(global, 'TextEncoder', { + value: TextEncoder, +}); + +describe('The PKCE module', () => { + it('creates verifiers and challenges in the correct format', async () => { + const validChars = /[a-z0-9-_]/i; + for (let i = 0; i < 100; i++) { + const verifier = createVerifier(); + expect(verifier).toMatch(validChars); + expect(verifier.length).toBeGreaterThan(89); + + const challenge = await createChallenge(verifier); + expect(challenge).toMatch(validChars); + } + }); +}); diff --git a/packages/sdk-utilities/src/lib/pkce.utils.ts b/packages/sdk-utilities/src/lib/pkce.utils.ts new file mode 100644 index 000000000..4f19b7e58 --- /dev/null +++ b/packages/sdk-utilities/src/lib/pkce.utils.ts @@ -0,0 +1,55 @@ +/** + * + * Copyright © 2025 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + **/ + +/** + * Helper functions for generating verifier, challenge and state strings used for + * Proof Key for Code Exchange (PKCE). + */ + +/** + * Creates a random string. + * + * @param size The number for entropy (default: 32) + */ +export function createRandomString(num = 32) { + const random = crypto.getRandomValues(new Uint8Array(num)); + return btoa(random.join('')).replace(/[^a-zA-Z0-9]+/, ''); +} + +/** + * Creates a random state. + */ +export function createState() { + return createRandomString(16); +} + +/** + * Creates a random verifier. + */ +export function createVerifier() { + return createRandomString(32); +} + +/** + * Creates a SHA-256 hash of the verifier. + * + * @param verifier The verifier to hash + */ +export async function createChallenge(verifier: string) { + // Create a SHA-256 hash of the specified string + const uint8Array = new TextEncoder().encode(verifier); + const arrayBuffer = await crypto.subtle.digest('SHA-256', uint8Array); + const charCodeArray = Array.from(new Uint8Array(arrayBuffer)); + + // Create a base64 encoded, URL-friendly version of the char code array + return btoa(String.fromCharCode(...charCodeArray)) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=/g, ''); +} diff --git a/packages/sdk-utilities/src/lib/url.utils.test.ts b/packages/sdk-utilities/src/lib/url.utils.test.ts new file mode 100644 index 000000000..2c51fb83b --- /dev/null +++ b/packages/sdk-utilities/src/lib/url.utils.test.ts @@ -0,0 +1,81 @@ +/** + * + * Copyright © 2025 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + **/ + +import { getEndpointPath, getRealmUrlPath } from './url.utils.js'; +import { GetEndpointPathParams } from './url.utils.types.js'; + +describe('The URL utility functions', () => { + it('getRealmUrlPath creates the correct paths', () => { + const tests = [ + [undefined, 'realms/root'], + ['', 'realms/root'], + ['root', 'realms/root'], + ['foo', 'realms/root/realms/foo'], + ['root/foo', 'realms/root/realms/foo'], + ['foo/bar', 'realms/root/realms/foo/realms/bar'], + ['foo/Bar', 'realms/root/realms/foo/realms/Bar'], + ['/foo/baz/', 'realms/root/realms/foo/realms/baz'], + [' /foo/baz ', 'realms/root/realms/foo/realms/baz'], + [' foo / baz ', 'realms/root/realms/foo/realms/baz'], + [' / foo / baz / ', 'realms/root/realms/foo/realms/baz'], + ]; + + tests.forEach((x) => { + const urlPath = getRealmUrlPath(x[0]); + expect(urlPath).toBe(x[1]); + }); + }); + + it('getEndpointPath creates the correct paths', () => { + const tests: [GetEndpointPathParams, string][] = [ + [{ endpoint: 'authenticate' }, 'json/realms/root/authenticate'], + [ + { endpoint: 'authenticate', realmPath: 'alpha' }, + 'json/realms/root/realms/alpha/authenticate', + ], + [ + { endpoint: 'authenticate', realmPath: '/alpha' }, + 'json/realms/root/realms/alpha/authenticate', + ], + [{ endpoint: 'authorize', realmPath: '/alpha' }, 'oauth2/realms/root/realms/alpha/authorize'], + [ + { endpoint: 'accessToken', realmPath: '/alpha' }, + 'oauth2/realms/root/realms/alpha/access_token', + ], + [ + { endpoint: 'endSession', realmPath: '/alpha' }, + 'oauth2/realms/root/realms/alpha/connect/endSession', + ], + [{ endpoint: 'userInfo', realmPath: '/alpha' }, 'oauth2/realms/root/realms/alpha/userinfo'], + [{ endpoint: 'revoke', realmPath: '/alpha' }, 'oauth2/realms/root/realms/alpha/token/revoke'], + [{ endpoint: 'sessions', realmPath: '/alpha' }, 'json/realms/root/realms/alpha/sessions/'], + [ + { + endpoint: 'authenticate', + customPaths: { authenticate: 'custom/authenticate' }, + }, + 'custom/authenticate', + ], + [ + { + endpoint: 'authenticate', + realmPath: 'alpha', + customPaths: { authenticate: 'custom/authenticate' }, + }, + 'custom/authenticate', + ], + ]; + + tests.forEach((x) => { + const { endpoint, realmPath, customPaths } = x[0]; + const endpointPath = getEndpointPath({ endpoint, realmPath, customPaths }); + expect(endpointPath).toBe(x[1]); + }); + }); +}); diff --git a/packages/sdk-utilities/src/lib/url.utils.ts b/packages/sdk-utilities/src/lib/url.utils.ts new file mode 100644 index 000000000..67d86c8cc --- /dev/null +++ b/packages/sdk-utilities/src/lib/url.utils.ts @@ -0,0 +1,59 @@ +/** + * + * Copyright © 2025 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + **/ + +import type { GetEndpointPathParams } from './url.utils.types.js'; + +/** **************************************************************** + * @function getRealmUrlPath - Get the realm URL path + * @param {string} realmPath - The realm path + * @returns {string} - The realm URL path + */ +export function getRealmUrlPath(realmPath?: string): string { + // Split the path and scrub segments + const names = (realmPath || '') + .split('/') + .map((x) => x.trim()) + .filter((x) => x !== ''); + + // Ensure 'root' is the first realm + if (names[0] !== 'root') { + names.unshift('root'); + } + + // Concatenate into a URL path + const urlPath = names.map((x) => `realms/${x}`).join('/'); + return urlPath; +} + +/** **************************************************************** + * @function getEndpointPath - Get the endpoint path + * @param {GetEndpointPathParams} - The endpoint, realm path, and custom paths params + * @returns {string} - The endpoint path + */ +export function getEndpointPath({ + endpoint, + realmPath, + customPaths, +}: GetEndpointPathParams): string { + const realmUrlPath = getRealmUrlPath(realmPath); + const defaultPaths = { + authenticate: `json/${realmUrlPath}/authenticate`, + authorize: `oauth2/${realmUrlPath}/authorize`, + accessToken: `oauth2/${realmUrlPath}/access_token`, + endSession: `oauth2/${realmUrlPath}/connect/endSession`, + userInfo: `oauth2/${realmUrlPath}/userinfo`, + revoke: `oauth2/${realmUrlPath}/token/revoke`, + sessions: `json/${realmUrlPath}/sessions/`, + }; + if (customPaths && customPaths[endpoint]) { + return customPaths[endpoint]; + } else { + return defaultPaths[endpoint]; + } +} diff --git a/packages/sdk-utilities/src/lib/url.utils.types.ts b/packages/sdk-utilities/src/lib/url.utils.types.ts new file mode 100644 index 000000000..d889042f7 --- /dev/null +++ b/packages/sdk-utilities/src/lib/url.utils.types.ts @@ -0,0 +1,34 @@ +/** + * + * Copyright © 2025 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + **/ + +export type ConfigurablePaths = keyof CustomPathConfig; + +/** + * Optional configuration for custom paths for actions + */ +export interface CustomPathConfig { + authenticate?: string; + authorize?: string; + accessToken?: string; + endSession?: string; + userInfo?: string; + revoke?: string; + sessions?: string; +} + +/** **************************************************************** + * @param {ConfigurablePaths} endpoint - The endpoint to get the path for + * @param {string} realmPath - The realm path + * @param {CustomPathConfig} customPaths - The custom paths + */ +export interface GetEndpointPathParams { + endpoint: ConfigurablePaths; + realmPath?: string; + customPaths?: CustomPathConfig; +} diff --git a/packages/sdk-utilities/src/types.ts b/packages/sdk-utilities/src/types.ts new file mode 100644 index 000000000..2f6e77a1f --- /dev/null +++ b/packages/sdk-utilities/src/types.ts @@ -0,0 +1,10 @@ +/** + * + * Copyright © 2025 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + **/ + +export * from './lib/url.utils.types.js'; diff --git a/packages/sdk-utilities/tsconfig.json b/packages/sdk-utilities/tsconfig.json new file mode 100644 index 000000000..9d592a77c --- /dev/null +++ b/packages/sdk-utilities/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "nx": { + "addTypecheckTarget": false + } +} diff --git a/packages/sdk-utilities/tsconfig.lib.json b/packages/sdk-utilities/tsconfig.lib.json new file mode 100644 index 000000000..54bf45967 --- /dev/null +++ b/packages/sdk-utilities/tsconfig.lib.json @@ -0,0 +1,33 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "moduleResolution": "nodenext", + "module": "NodeNext", + "target": "ES2022", + "outDir": "./dist", + "resolveJsonModule": true, + "moduleDetection": "force", + "isolatedModules": true, + "strict": true, + "noUncheckedIndexedAccess": false, + "noImplicitOverride": true, + "declaration": true, + "declarationMap": true, + "skipLibCheck": true, + "sourceMap": true, + "lib": ["es2022", "dom", "dom.iterable"] + }, + "include": ["src/**/*.ts", "src/**/*.*.ts"], + "exclude": [ + "src/**/*.*.test-d.ts", + "src/**/*.test-d.ts", + "vite.config.ts", + "src/**/*.spec.ts", + "src/**/*.test.ts", + "src/**/*.*test.ts", + "src/**/*.test-d.ts", + "src/**/*.types.test-d.ts", + "src/**/*.utils.test-d.ts", + "src/lib/mock-data/*" + ] +} diff --git a/packages/sdk-utilities/tsconfig.spec.json b/packages/sdk-utilities/tsconfig.spec.json new file mode 100644 index 000000000..d2b54883e --- /dev/null +++ b/packages/sdk-utilities/tsconfig.spec.json @@ -0,0 +1,41 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc/vitest", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "module": "NodeNext", + "moduleResolution": "nodenext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "importHelpers": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/packages/sdk-utilities/typedoc.json b/packages/sdk-utilities/typedoc.json new file mode 100644 index 000000000..de53937ca --- /dev/null +++ b/packages/sdk-utilities/typedoc.json @@ -0,0 +1,4 @@ +{ + "name": "@forgerock/sdk-utilities", + "entryPoints": ["src/index.ts", "src/types.ts"] +} diff --git a/packages/sdk-utilities/vite.config.ts b/packages/sdk-utilities/vite.config.ts new file mode 100644 index 000000000..ed4a20837 --- /dev/null +++ b/packages/sdk-utilities/vite.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: __dirname, + cacheDir: '../../node_modules/.vite/packages/sdk-utilities', + plugins: [], + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + test: { + watch: false, + globals: true, + environment: 'node', + include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + }, + }, +})); diff --git a/packages/shared-types/README.md b/packages/shared-types/README.md new file mode 100644 index 000000000..b6f0765d1 --- /dev/null +++ b/packages/shared-types/README.md @@ -0,0 +1,11 @@ +# shared-types + +This library was generated with [Nx](https://nx.dev). + +## Building + +Run `nx build shared-types` to build the library. + +## Running unit tests + +Run `nx test shared-types` to execute the unit tests via [Vitest](https://vitest.dev/). diff --git a/packages/shared-types/eslint.config.mjs b/packages/shared-types/eslint.config.mjs new file mode 100644 index 000000000..2dcaf60cb --- /dev/null +++ b/packages/shared-types/eslint.config.mjs @@ -0,0 +1,22 @@ +import baseConfig from '../../eslint.config.mjs'; + +export default [ + ...baseConfig, + { + files: ['**/*.json'], + rules: { + '@nx/dependency-checks': [ + 'error', + { + ignoredFiles: [ + '{projectRoot}/eslint.config.{js,cjs,mjs}', + '{projectRoot}/vite.config.{js,ts,mjs,mts}', + ], + }, + ], + }, + languageOptions: { + parser: await import('jsonc-eslint-parser'), + }, + }, +]; diff --git a/packages/shared-types/package.json b/packages/shared-types/package.json new file mode 100644 index 000000000..5bdc9a7ba --- /dev/null +++ b/packages/shared-types/package.json @@ -0,0 +1,38 @@ +{ + "name": "@forgerock/shared-types", + "version": "0.0.1", + "private": true, + "type": "module", + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js", + "default": "./dist/src/index.js" + }, + "./package.json": "./package.json" + }, + "main": "./dist/src/index.js", + "module": "./dist/src/index.js", + "types": "./dist/src/index.d.ts", + "files": ["dist"], + "dependencies": { + "@reduxjs/toolkit": "catalog:", + "tslib": "^2.3.0" + }, + "nx": { + "tags": ["scope:shared-types"], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "packages/shared-types/dist", + "main": "packages/shared-types/src/index.ts", + "tsConfig": "packages/shared-types/tsconfig.lib.json", + "generatePackageJson": false, + "assets": [] + } + } + } + } +} diff --git a/packages/shared-types/src/index.ts b/packages/shared-types/src/index.ts new file mode 100644 index 000000000..4cede73a1 --- /dev/null +++ b/packages/shared-types/src/index.ts @@ -0,0 +1,5 @@ +export * from './lib/shared-types.js'; +export * from './lib/authorization.types.js'; +export * from './lib/callback.types.js'; +export * from './lib/config.types.js'; +export * from './lib/tokens.types.js'; diff --git a/packages/shared-types/src/lib/authorization.types.ts b/packages/shared-types/src/lib/authorization.types.ts new file mode 100644 index 000000000..0abf8c2d5 --- /dev/null +++ b/packages/shared-types/src/lib/authorization.types.ts @@ -0,0 +1,25 @@ +import type { ConfigOptions } from './config.types.js'; + +/** + * Define the 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 type ResponseType = 'code' | 'token'; +export interface GetAuthorizationUrlOptions extends ConfigOptions { + /** + * These three properties clientid, scope and redirectUri are required + * when using this type, which are not required when defining Config. + */ + clientId: string; + login?: 'redirect' | 'embedded'; + scope: string; + redirectUri: string; + responseType: ResponseType; + state?: string; + verifier?: string; + query?: Record; + prompt?: 'none' | 'login' | 'consent'; +} diff --git a/packages/shared-types/src/lib/callback.types.ts b/packages/shared-types/src/lib/callback.types.ts new file mode 100644 index 000000000..f47861cf5 --- /dev/null +++ b/packages/shared-types/src/lib/callback.types.ts @@ -0,0 +1,43 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const callbackType = { + BooleanAttributeInputCallback: 'BooleanAttributeInputCallback', + ChoiceCallback: 'ChoiceCallback', + ConfirmationCallback: 'ConfirmationCallback', + DeviceProfileCallback: 'DeviceProfileCallback', + HiddenValueCallback: 'HiddenValueCallback', + KbaCreateCallback: 'KbaCreateCallback', + MetadataCallback: 'MetadataCallback', + NameCallback: 'NameCallback', + NumberAttributeInputCallback: 'NumberAttributeInputCallback', + PasswordCallback: 'PasswordCallback', + PingOneProtectEvaluationCallback: 'PingOneProtectEvaluationCallback', + PingOneProtectInitializeCallback: 'PingOneProtectInitializeCallback', + PollingWaitCallback: 'PollingWaitCallback', + ReCaptchaCallback: 'ReCaptchaCallback', + ReCaptchaEnterpriseCallback: 'ReCaptchaEnterpriseCallback', + RedirectCallback: 'RedirectCallback', + SelectIdPCallback: 'SelectIdPCallback', + StringAttributeInputCallback: 'StringAttributeInputCallback', + SuspendedTextOutputCallback: 'SuspendedTextOutputCallback', + TermsAndConditionsCallback: 'TermsAndConditionsCallback', + TextInputCallback: 'TextInputCallback', + TextOutputCallback: 'TextOutputCallback', + ValidatedCreatePasswordCallback: 'ValidatedCreatePasswordCallback', + ValidatedCreateUsernameCallback: 'ValidatedCreateUsernameCallback', +} as const; + +export type CallbackType = (typeof callbackType)[keyof typeof callbackType]; + +export interface NameValue { + name: string; + value: unknown; +} +/** + * Represents the authentication tree API callback schema. + */ +export interface Callback { + _id?: number; + input?: NameValue[]; + output: NameValue[]; + type: CallbackType; +} diff --git a/packages/shared-types/src/lib/config.types.ts b/packages/shared-types/src/lib/config.types.ts new file mode 100644 index 000000000..ef411616f --- /dev/null +++ b/packages/shared-types/src/lib/config.types.ts @@ -0,0 +1,113 @@ +import { Callback } from './callback.types.js'; +import { RequestMiddleware } from './shared-types.js'; +import { Tokens } from './tokens.types.js'; + +/** + * Async ConfigOptions for well-known endpoint usage + */ +export interface AsyncConfigOptions extends Omit { + serverConfig: AsyncServerConfig; +} + +export type ConfigurablePaths = keyof CustomPathConfig; +/** + * Optional configuration for custom paths for actions + */ +export interface CustomPathConfig { + authenticate?: string; + authorize?: string; + accessToken?: string; + endSession?: string; + userInfo?: string; + revoke?: string; + sessions?: string; +} + +/** + * Configuration settings for connecting to a server. + */ +export interface ServerConfig { + baseUrl: string; + paths?: CustomPathConfig; + timeout?: number; +} + +/** + * Configuration settings for async config with well-known + */ +export interface AsyncServerConfig extends Omit { + wellknown?: string; +} + +/** + * API for implementing a custom token store + */ +export interface TokenStoreObject { + get: (clientId: string) => Promise; + set: (clientId: string, token: Tokens) => Promise; + remove: (clientId: string) => Promise; +} + +/** + * Configuration options with a server configuration specified. + */ +export interface ValidConfigOptions extends ConfigOptions { + serverConfig: ServerConfig; + // needs logger? +} + +/** + * Represents configuration overrides used when requesting the next + * step in an authentication tree. + */ +export interface StepOptions extends ConfigOptions { + query?: Record; +} + +export interface WellKnownResponse { + issuer: string; + authorization_endpoint: string; + pushed_authorization_request_endpoint?: string; + token_endpoint: string; + userinfo_endpoint: string; + end_session_endpoint: string; + introspection_endpoint: string; + revocation_endpoint: string; + jwks_uri?: string; + device_authorization_endpoint?: string; + claims_parameter_supported?: boolean; + request_parameter_supported?: boolean; + request_uri_parameter_supported?: boolean; + require_pushed_authorization_requests?: boolean; + scopes_supported?: string[]; + response_types_supported?: string[]; + response_modes_supported?: string[]; + grant_types_supported?: string[]; + subject_types_supported?: string[]; + id_token_signing_alg_values_supported?: string[]; + userinfo_signing_alg_values_supported?: string[]; + request_object_signing_alg_values_supported?: string[]; + token_endpoint_auth_methods_supported?: string[]; + token_endpoint_auth_signing_alg_values_supported?: string[]; + claim_types_supported?: string[]; + claims_supported?: string[]; + code_challenge_methods_supported?: string[]; +} + +type FRCallbackFactory = (callback: Callback) => any; + +export interface ConfigOptions { + callbackFactory?: FRCallbackFactory; + clientId?: string; + middleware?: RequestMiddleware[]; + realmPath?: string; + redirectUri?: string; + scope?: string; + serverConfig?: ServerConfig; + tokenStore?: TokenStoreObject | 'sessionStorage' | 'localStorage'; + tree?: string; + type?: string; + oauthThreshold?: number; + platformHeader?: boolean; + prefix?: string; +} diff --git a/packages/shared-types/src/lib/shared-types.ts b/packages/shared-types/src/lib/shared-types.ts new file mode 100644 index 000000000..6cebbe2e3 --- /dev/null +++ b/packages/shared-types/src/lib/shared-types.ts @@ -0,0 +1,49 @@ +import { + FetchArgs, + FetchBaseQueryError, + FetchBaseQueryMeta, + QueryReturnValue, +} from '@reduxjs/toolkit/query'; + +export type RequestMiddleware = ( + req: ModifiedFetchArgs, + action: Action, + next: () => ModifiedFetchArgs, +) => void; + +export interface QueryApi { + applyMiddleware(middleware: RequestMiddleware[]): QueryApi; + applyQuery( + callback: ( + request: FetchArgs, + ) => Promise>, + ): Promise>; +} + +export const actionTypes = { + start: 'DAVINCI_START', + next: 'DAVINCI_NEXT', + flow: 'DAVINCI_FLOW', + success: 'DAVINCI_SUCCESS', + error: 'DAVINCI_ERROR', + failure: 'DAVINCI_FAILURE', + resume: 'DAVINCI_RESUME', +} as const; + +export type ActionTypes = (typeof actionTypes)[keyof typeof actionTypes]; +export type EndpointTypes = keyof typeof actionTypes; + +export interface Action { + type: Type; + payload: Payload; +} + +export interface ModifiedFetchArgs extends Omit { + url: URL; + headers?: Headers; +} + +export interface RequestObj { + url: URL; + init: RequestInit; +} diff --git a/packages/shared-types/src/lib/tokens.types.ts b/packages/shared-types/src/lib/tokens.types.ts new file mode 100644 index 000000000..4d5bf8ab6 --- /dev/null +++ b/packages/shared-types/src/lib/tokens.types.ts @@ -0,0 +1,6 @@ +export interface Tokens { + accessToken: string; + idToken?: string; + refreshToken?: string; + tokenExpiry?: number; +} diff --git a/packages/shared-types/tsconfig.json b/packages/shared-types/tsconfig.json new file mode 100644 index 000000000..9d592a77c --- /dev/null +++ b/packages/shared-types/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "nx": { + "addTypecheckTarget": false + } +} diff --git a/packages/shared-types/tsconfig.lib.json b/packages/shared-types/tsconfig.lib.json new file mode 100644 index 000000000..1ddaa8a65 --- /dev/null +++ b/packages/shared-types/tsconfig.lib.json @@ -0,0 +1,34 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", + "emitDeclarationOnly": false, + "module": "nodenext", + "moduleResolution": "nodenext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "importHelpers": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "types": [] + }, + "include": ["src/**/*.ts"], + "references": [], + "exclude": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx" + ] +} diff --git a/packages/shared-types/tsconfig.spec.json b/packages/shared-types/tsconfig.spec.json new file mode 100644 index 000000000..1060f1e9a --- /dev/null +++ b/packages/shared-types/tsconfig.spec.json @@ -0,0 +1,41 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out-tsc/vitest", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "module": "nodenext", + "moduleResolution": "nodenext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "importHelpers": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/packages/shared-types/typedoc.json b/packages/shared-types/typedoc.json new file mode 100644 index 000000000..36cfd76eb --- /dev/null +++ b/packages/shared-types/typedoc.json @@ -0,0 +1,4 @@ +{ + "name": "@forgerock/shared-types", + "entryPoints": ["src/index.ts"] +} diff --git a/packages/shared-types/vite.config.ts b/packages/shared-types/vite.config.ts new file mode 100644 index 000000000..1df2cce16 --- /dev/null +++ b/packages/shared-types/vite.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from 'vite'; + +export default defineConfig(() => ({ + root: __dirname, + cacheDir: '../../node_modules/.vite/packages/shared-types', + plugins: [], + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + test: { + watch: false, + globals: true, + environment: 'node', + include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + }, + }, +})); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b26569ff7..193e42a15 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -120,8 +120,8 @@ importers: specifier: ^8.13.0 version: 8.28.0(eslint@9.24.0(jiti@2.4.2))(typescript@5.7.3) '@vitest/coverage-v8': - specifier: 3.0.4 - version: 3.0.4(vitest@3.0.5) + specifier: ^3.0.5 + version: 3.1.1(vitest@3.0.5) '@vitest/ui': specifier: 3.0.4 version: 3.0.4(vitest@3.0.5) @@ -170,6 +170,9 @@ importers: lint-staged: specifier: ^15.0.0 version: 15.5.1 + madge: + specifier: 8.0.0 + version: 8.0.0(typescript@5.7.3) npm-cli-login: specifier: ^1.0.0 version: 1.0.0 @@ -271,13 +274,16 @@ importers: devDependencies: '@effect/vitest': specifier: ^0.19.0 - version: 0.19.10(effect@3.14.3)(vitest@3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4(vitest@3.0.5))(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(terser@5.39.0)(yaml@2.7.1)) + version: 0.19.10(effect@3.14.3)(vitest@3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(terser@5.39.0)(yaml@2.7.1)) packages/davinci-client: dependencies: - '@forgerock/javascript-sdk': - specifier: 4.7.0 - version: 4.7.0 + '@forgerock/effects': + specifier: workspace:* + version: link:../effects + '@forgerock/shared-types': + specifier: workspace:* + version: link:../shared-types '@reduxjs/toolkit': specifier: 'catalog:' version: 2.6.1 @@ -287,7 +293,7 @@ importers: devDependencies: vitest: specifier: ^3.0.4 - version: 3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4(vitest@3.0.5))(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(terser@5.39.0)(yaml@2.7.1) + version: 3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(terser@5.39.0)(yaml@2.7.1) packages/device-client: dependencies: @@ -302,6 +308,36 @@ importers: specifier: ^2.5.1 version: 2.7.3(@types/node@22.13.16)(typescript@5.8.2) + packages/effects: + dependencies: + '@forgerock/sdk-utilities': + specifier: workspace:* + version: link:../sdk-utilities + '@forgerock/shared-types': + specifier: workspace:* + version: link:../shared-types + '@reduxjs/toolkit': + specifier: 'catalog:' + version: 2.6.1 + tslib: + specifier: ^2.5.0 + version: 2.8.1 + devDependencies: + vite: + specifier: 6.2.5 + version: 6.2.5(@types/node@22.13.16)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.1) + + packages/sdk-utilities: {} + + packages/shared-types: + dependencies: + '@reduxjs/toolkit': + specifier: 'catalog:' + version: 2.6.1 + tslib: + specifier: ^2.3.0 + version: 2.8.1 + packages: '@actions/core@1.11.1': @@ -1125,6 +1161,10 @@ packages: resolution: {integrity: sha512-h0NFgh1mJmm1nr4jCwkGHwKneVYKghUyWe6TMNrk0B9zsjAJxpg8C4/+BAcmLgCPa1vj1V8rNUaILl+zYRUWBQ==} engines: {node: '>= 6'} + '@dependents/detective-less@5.0.1': + resolution: {integrity: sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ==} + engines: {node: '>=18'} + '@effect/language-service@0.2.0': resolution: {integrity: sha512-DoK41yKGyQv79o0ca8gxEogMlt+IphXkdCXwgenbQjH1BXKD7tJAr0+VsDhblycQcvQ39f1l9NZN9CBqjM9ALA==} @@ -2308,6 +2348,22 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@ts-graphviz/adapter@2.0.6': + resolution: {integrity: sha512-kJ10lIMSWMJkLkkCG5gt927SnGZcBuG0s0HHswGzcHTgvtUe7yk5/3zTEr0bafzsodsOq5Gi6FhQeV775nC35Q==} + engines: {node: '>=18'} + + '@ts-graphviz/ast@2.0.7': + resolution: {integrity: sha512-e6+2qtNV99UT6DJSoLbHfkzfyqY84aIuoV8Xlb9+hZAjgpum8iVHprGeAMQ4rF6sKUAxrmY8rfF/vgAwoPc3gw==} + engines: {node: '>=18'} + + '@ts-graphviz/common@2.1.5': + resolution: {integrity: sha512-S6/9+T6x8j6cr/gNhp+U2olwo1n0jKj/682QVqsh7yXWV6ednHYqxFw0ZsY3LyzT0N8jaZ6jQY9YD99le3cmvg==} + engines: {node: '>=18'} + + '@ts-graphviz/core@2.0.7': + resolution: {integrity: sha512-w071DSzP94YfN6XiWhOxnLpYT3uqtxJBDYdh6Jdjzt+Ce6DNspJsPQgpC7rbts/B8tEkq0LHoYuIF/O5Jh5rPg==} + engines: {node: '>=18'} + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -2573,11 +2629,11 @@ packages: resolution: {integrity: sha512-efg/bunOUMVXV+MlljJCrpuT+OQRrQS4wJyGL92B3epUGlgZ8DXs+nxN5v59v1a6AocAdSKwHgZS0g9txmBhOg==} engines: {node: '>=18'} - '@vitest/coverage-v8@3.0.4': - resolution: {integrity: sha512-f0twgRCHgbs24Dp8cLWagzcObXMcuKtAwgxjJV/nnysPAJJk1JiKu/W0gIehZLmkljhJXU/E0/dmuQzsA/4jhA==} + '@vitest/coverage-v8@3.1.1': + resolution: {integrity: sha512-MgV6D2dhpD6Hp/uroUoAIvFqA8AuvXEFBC2eepG3WFc1pxTfdk1LEqqkWoWhjz+rytoqrnUUCdf6Lzco3iHkLQ==} peerDependencies: - '@vitest/browser': 3.0.4 - vitest: 3.0.4 + '@vitest/browser': 3.1.1 + vitest: 3.1.1 peerDependenciesMeta: '@vitest/browser': optional: true @@ -2640,6 +2696,12 @@ packages: '@vue/compiler-dom@3.5.13': resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + '@vue/compiler-sfc@3.5.13': + resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} + + '@vue/compiler-ssr@3.5.13': + resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + '@vue/compiler-vue2@2.7.16': resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} @@ -2878,6 +2940,9 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -2886,6 +2951,9 @@ packages: resolution: {integrity: sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==} engines: {node: '>=8'} + app-module-path@2.2.0: + resolution: {integrity: sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ==} + aproba@1.2.0: resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} @@ -2950,6 +3018,10 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + ast-module-types@6.0.1: + resolution: {integrity: sha512-WHw67kLXYbZuHTmcdbIrVArCq5wxo6NEuj3hiYAWr8mwJeC+C2mMCIBIWCiDoCye/OF/xelc+teJ1ERoWmnEIA==} + engines: {node: '>=18'} + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} @@ -3297,6 +3369,10 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + commander@13.1.0: resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} engines: {node: '>=18'} @@ -3308,6 +3384,10 @@ packages: resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} engines: {node: '>= 6'} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + commander@8.3.0: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} @@ -3317,6 +3397,9 @@ packages: engines: {node: '>= 12'} hasBin: true + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} @@ -3548,6 +3631,10 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -3589,6 +3676,11 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dependency-tree@11.1.1: + resolution: {integrity: sha512-pnkCd8VGOq70EVaEQxDC9mZCjCwYj4yG4j8h+PEJswuWp+rdE6p8zbtVvWk+yPwaVimOjlhNi782U9K5KOU9MQ==} + engines: {node: '>=18'} + hasBin: true + deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} @@ -3629,6 +3721,49 @@ packages: engines: {node: '>= 4.0.0'} hasBin: true + detective-amd@6.0.1: + resolution: {integrity: sha512-TtyZ3OhwUoEEIhTFoc1C9IyJIud3y+xYkSRjmvCt65+ycQuc3VcBrPRTMWoO/AnuCyOB8T5gky+xf7Igxtjd3g==} + engines: {node: '>=18'} + hasBin: true + + detective-cjs@6.0.1: + resolution: {integrity: sha512-tLTQsWvd2WMcmn/60T2inEJNhJoi7a//PQ7DwRKEj1yEeiQs4mrONgsUtEJKnZmrGWBBmE0kJ1vqOG/NAxwaJw==} + engines: {node: '>=18'} + + detective-es6@5.0.1: + resolution: {integrity: sha512-XusTPuewnSUdoxRSx8OOI6xIA/uld/wMQwYsouvFN2LAg7HgP06NF1lHRV3x6BZxyL2Kkoih4ewcq8hcbGtwew==} + engines: {node: '>=18'} + + detective-postcss@7.0.1: + resolution: {integrity: sha512-bEOVpHU9picRZux5XnwGsmCN4+8oZo7vSW0O0/Enq/TO5R2pIAP2279NsszpJR7ocnQt4WXU0+nnh/0JuK4KHQ==} + engines: {node: ^14.0.0 || >=16.0.0} + peerDependencies: + postcss: ^8.4.47 + + detective-sass@6.0.1: + resolution: {integrity: sha512-jSGPO8QDy7K7pztUmGC6aiHkexBQT4GIH+mBAL9ZyBmnUIOFbkfZnO8wPRRJFP/QP83irObgsZHCoDHZ173tRw==} + engines: {node: '>=18'} + + detective-scss@5.0.1: + resolution: {integrity: sha512-MAyPYRgS6DCiS6n6AoSBJXLGVOydsr9huwXORUlJ37K3YLyiN0vYHpzs3AdJOgHobBfispokoqrEon9rbmKacg==} + engines: {node: '>=18'} + + detective-stylus@5.0.1: + resolution: {integrity: sha512-Dgn0bUqdGbE3oZJ+WCKf8Dmu7VWLcmRJGc6RCzBgG31DLIyai9WAoEhYRgIHpt/BCRMrnXLbGWGPQuBUrnF0TA==} + engines: {node: '>=18'} + + detective-typescript@14.0.0: + resolution: {integrity: sha512-pgN43/80MmWVSEi5LUuiVvO/0a9ss5V7fwVfrJ4QzAQRd3cwqU1SfWGXJFcNKUqoD5cS+uIovhw5t/0rSeC5Mw==} + engines: {node: '>=18'} + peerDependencies: + typescript: ^5.4.4 + + detective-vue2@2.2.0: + resolution: {integrity: sha512-sVg/t6O2z1zna8a/UIV6xL5KUa2cMTQbdTIIvqNM0NIPswp52fe43Nwmbahzj3ww4D844u/vC2PYfiGLvD3zFA==} + engines: {node: '>=18'} + peerDependencies: + typescript: ^5.4.4 + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3835,6 +3970,11 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + eslint-config-prettier@10.1.2: resolution: {integrity: sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==} hasBin: true @@ -4125,6 +4265,11 @@ packages: resolution: {integrity: sha512-vqIlNogKeyD3yzrm0yhRMQg8hOVwYcYRfjEoODd49iCprMn4HL85gK3HcykQE53EPIpX3HcAbGA5ELQv216dAQ==} engines: {node: '>=16'} + filing-cabinet@5.0.3: + resolution: {integrity: sha512-PlPcMwVWg60NQkhvfoxZs4wEHjhlOO/y7OAm4sKM60o1Z9nttRY4mcdQxp/iZ+kg/Vv6Hw1OAaTbYVM9DA9pYg==} + engines: {node: '>=18'} + hasBin: true + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -4266,6 +4411,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-amd-module-type@6.0.1: + resolution: {integrity: sha512-MtjsmYiCXcYDDrGqtNbeIYdAl85n+5mSv2r3FbzER/YV3ZILw4HNNIw34HuV5pyl0jzs6GFYU1VHVEefhgcNHQ==} + engines: {node: '>=18'} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -4278,6 +4427,9 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-own-enumerable-property-symbols@3.0.2: + resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} + get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} @@ -4383,6 +4535,11 @@ packages: globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + gonzales-pe@4.3.0: + resolution: {integrity: sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==} + engines: {node: '>=0.6.0'} + hasBin: true + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -4727,6 +4884,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-obj@1.0.1: + resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} + engines: {node: '>=0.10.0'} + is-obj@2.0.0: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} @@ -4749,6 +4910,10 @@ packages: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} + is-regexp@1.0.0: + resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==} + engines: {node: '>=0.10.0'} + is-set@2.0.3: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} @@ -4800,6 +4965,13 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-url-superb@4.0.0: + resolution: {integrity: sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==} + engines: {node: '>=10'} + + is-url@1.2.4: + resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} + is-utf8@0.2.1: resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==} @@ -5248,6 +5420,16 @@ packages: lunr@2.3.9: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + madge@8.0.0: + resolution: {integrity: sha512-9sSsi3TBPhmkTCIpVQF0SPiChj1L7Rq9kU2KDG1o6v2XH9cCw086MopjVCD+vuoL5v8S77DTbVopTO8OUiQpIw==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: ^5.4.4 + peerDependenciesMeta: + typescript: + optional: true + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -5395,6 +5577,16 @@ packages: mlly@1.7.4: resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + module-definition@6.0.1: + resolution: {integrity: sha512-FeVc50FTfVVQnolk/WQT8MX+2WVcDnTGiq6Wo+/+lJ2ET1bRVi3HG3YlJUfqagNMc/kUlFSoR96AJkxGpKz13g==} + engines: {node: '>=18'} + hasBin: true + + module-lookup-amd@9.0.4: + resolution: {integrity: sha512-DWJEuLVvjxh5b8wrvJC5wr2a7qo7pOWXIgdCBNazU416kcIyzO4drxvlqKhsHzYwxcC4cWuhoK+MiWCKCGnv7A==} + engines: {node: '>=18'} + hasBin: true + moo-color@1.0.3: resolution: {integrity: sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ==} @@ -5494,6 +5686,10 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-source-walk@7.0.1: + resolution: {integrity: sha512-3VW/8JpPqPvnJvseXowjZcirPisssnBuDikk6JIZ8jQzF7KJQX52iPFX4RYYxLycYH7IbMRSPUOga/esVjy5Yg==} + engines: {node: '>=18'} + normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -5724,6 +5920,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-ms@2.1.0: + resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} + engines: {node: '>=6'} + parse-passwd@1.0.0: resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} engines: {node: '>=0.10.0'} @@ -5863,6 +6063,10 @@ packages: engines: {node: '>=18'} hasBin: true + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + portfinder@1.0.35: resolution: {integrity: sha512-73JaFg4NwYNAufDtS5FsFu/PdM49ahJrO1i44aCRsDWju1z5wuGDaqyFUQWR6aJoK2JPDWlaYYAGFNIGTSUHSw==} engines: {node: '>= 10.12'} @@ -5871,10 +6075,21 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + postcss-values-parser@6.0.2: + resolution: {integrity: sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==} + engines: {node: '>=10'} + peerDependencies: + postcss: ^8.2.9 + postcss@8.5.3: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} + precinct@12.2.0: + resolution: {integrity: sha512-NFBMuwIfaJ4SocE9YXPU/n4AcNSoFMVFjP72nvl3cx69j/ke61/hPOWFREVxLkFhhEGnA8ZuVfTqJBa+PK3b5w==} + engines: {node: '>=18'} + hasBin: true + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -5897,6 +6112,10 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + pretty-ms@7.0.1: + resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} + engines: {node: '>=10'} + proc-log@3.0.0: resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -5972,6 +6191,9 @@ packages: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} + quote-unquote@1.0.0: + resolution: {integrity: sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -5983,6 +6205,10 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} @@ -6062,6 +6288,15 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + requirejs-config-file@4.0.0: + resolution: {integrity: sha512-jnIre8cbWOyvr8a5F2KuqBnY+SDA4NXr/hzEZJG79Mxm2WiFQz2dzhC8ibtPJS7zkmBEl1mxSwp5HhC1W4qpxw==} + engines: {node: '>=10.13.0'} + + requirejs@2.3.7: + resolution: {integrity: sha512-DouTG8T1WanGok6Qjg2SXuCMzszOo0eHeH9hDZ5Y4x8Je+9JB38HdTLT4/VA8OaUhBa0JPVHJ0pyBkM1z+pDsw==} + engines: {node: '>=0.4.0'} + hasBin: true + requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -6071,6 +6306,10 @@ packages: resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + resolve-dependency-path@4.0.1: + resolution: {integrity: sha512-YQftIIC4vzO9UMhO/sCgXukNyiwVRCVaxiWskCBy7Zpqkplm8kTAISZ8O1MoKW1ca6xzgLUBjZTcDgypXvXxiQ==} + engines: {node: '>=18'} + resolve-dir@1.0.1: resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} engines: {node: '>=0.10.0'} @@ -6170,6 +6409,11 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sass-lookup@6.1.0: + resolution: {integrity: sha512-Zx+lVyoWqXZxHuYWlTA17Z5sczJ6braNT2C7rmClw+c4E7r/n911Zwss3h1uHI9reR5AgHZyNHF7c2+VIp5AUA==} + engines: {node: '>=18'} + hasBin: true + saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -6423,6 +6667,9 @@ packages: stream-shift@1.0.3: resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + stream-to-array@2.3.0: + resolution: {integrity: sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==} + streamx@2.22.0: resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} @@ -6471,6 +6718,10 @@ packages: string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-object@3.3.0: + resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==} + engines: {node: '>=4'} + strip-ansi@3.0.1: resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} engines: {node: '>=0.10.0'} @@ -6506,6 +6757,10 @@ packages: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -6514,6 +6769,11 @@ packages: resolution: {integrity: sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw==} engines: {node: '>=16'} + stylus-lookup@6.1.0: + resolution: {integrity: sha512-5QSwgxAzXPMN+yugy61C60PhoANdItfdjSEZR8siFwz7yL9jTmV0UBKDCfn3K8GkGB4g0Y9py7vTCX8rFu4/pQ==} + engines: {node: '>=18'} + hasBin: true + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -6687,6 +6947,10 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-graphviz@2.1.6: + resolution: {integrity: sha512-XyLVuhBVvdJTJr2FJJV2L1pc4MwSjMhcunRVgDE9k4wbb2ee7ORYnPewxMWUav12vxyfUM686MSGsqnVRIInuw==} + engines: {node: '>=18'} + ts-node@10.9.1: resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true @@ -7063,6 +7327,46 @@ packages: yaml: optional: true + vite@6.2.5: + resolution: {integrity: sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vite@6.2.6: resolution: {integrity: sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -7143,6 +7447,10 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + walkdir@0.4.1: + resolution: {integrity: sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==} + engines: {node: '>=6.0.0'} + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} @@ -8494,6 +8802,11 @@ snapshots: tunnel-agent: 0.6.0 uuid: 8.3.2 + '@dependents/detective-less@5.0.1': + dependencies: + gonzales-pe: 4.3.0 + node-source-walk: 7.0.1 + '@effect/language-service@0.2.0': {} '@effect/platform-node-shared@0.8.26(@effect/platform@0.58.27(@effect/schema@0.68.27(effect@3.14.3))(effect@3.14.3))(effect@3.14.3)': @@ -8528,10 +8841,10 @@ snapshots: effect: 3.14.3 fast-check: 3.23.2 - '@effect/vitest@0.19.10(effect@3.14.3)(vitest@3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4(vitest@3.0.5))(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(terser@5.39.0)(yaml@2.7.1))': + '@effect/vitest@0.19.10(effect@3.14.3)(vitest@3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(terser@5.39.0)(yaml@2.7.1))': dependencies: effect: 3.14.3 - vitest: 3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4(vitest@3.0.5))(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(terser@5.39.0)(yaml@2.7.1) + vitest: 3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(terser@5.39.0)(yaml@2.7.1) '@effect/vitest@0.6.12(effect@3.14.3)(vitest@3.0.5)': dependencies: @@ -9786,6 +10099,21 @@ snapshots: '@tokenizer/token@0.3.0': {} + '@ts-graphviz/adapter@2.0.6': + dependencies: + '@ts-graphviz/common': 2.1.5 + + '@ts-graphviz/ast@2.0.7': + dependencies: + '@ts-graphviz/common': 2.1.5 + + '@ts-graphviz/common@2.1.5': {} + + '@ts-graphviz/core@2.0.7': + dependencies: + '@ts-graphviz/ast': 2.0.7 + '@ts-graphviz/common': 2.1.5 + '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -10176,7 +10504,7 @@ snapshots: minimatch: 7.4.6 semver: 7.7.1 - '@vitest/coverage-v8@3.0.4(vitest@3.0.5)': + '@vitest/coverage-v8@3.1.1(vitest@3.0.5)': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -10294,6 +10622,23 @@ snapshots: '@vue/compiler-core': 3.5.13 '@vue/shared': 3.5.13 + '@vue/compiler-sfc@3.5.13': + dependencies: + '@babel/parser': 7.27.0 + '@vue/compiler-core': 3.5.13 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + estree-walker: 2.0.2 + magic-string: 0.30.17 + postcss: 8.5.3 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.13': + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/shared': 3.5.13 + '@vue/compiler-vue2@2.7.16': dependencies: de-indent: 1.0.2 @@ -10583,6 +10928,8 @@ snapshots: ansi-styles@6.2.1: {} + any-promise@1.3.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -10590,6 +10937,8 @@ snapshots: apache-md5@1.1.8: {} + app-module-path@2.2.0: {} + aproba@1.2.0: optional: true @@ -10671,6 +11020,8 @@ snapshots: assertion-error@2.0.1: {} + ast-module-types@6.0.1: {} + async-function@1.0.0: {} async@3.2.4: {} @@ -11050,12 +11401,16 @@ snapshots: dependencies: delayed-stream: 1.0.0 + commander@12.1.0: {} + commander@13.1.0: {} commander@2.20.3: {} commander@6.2.1: {} + commander@7.2.0: {} + commander@8.3.0: {} commitizen@4.3.1(@types/node@22.13.16)(typescript@5.7.3): @@ -11078,6 +11433,8 @@ snapshots: - '@types/node' - typescript + commondir@1.0.1: {} + compare-func@2.0.0: dependencies: array-ify: 1.0.0 @@ -11299,6 +11656,8 @@ snapshots: deep-eql@5.0.2: {} + deep-extend@0.6.0: {} + deep-is@0.1.4: {} deepmerge@4.3.1: {} @@ -11332,6 +11691,15 @@ snapshots: depd@2.0.0: {} + dependency-tree@11.1.1: + dependencies: + commander: 12.1.0 + filing-cabinet: 5.0.3 + precinct: 12.2.0 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + deprecation@2.3.1: {} destroy@1.2.0: {} @@ -11357,6 +11725,62 @@ snapshots: transitivePeerDependencies: - supports-color + detective-amd@6.0.1: + dependencies: + ast-module-types: 6.0.1 + escodegen: 2.1.0 + get-amd-module-type: 6.0.1 + node-source-walk: 7.0.1 + + detective-cjs@6.0.1: + dependencies: + ast-module-types: 6.0.1 + node-source-walk: 7.0.1 + + detective-es6@5.0.1: + dependencies: + node-source-walk: 7.0.1 + + detective-postcss@7.0.1(postcss@8.5.3): + dependencies: + is-url: 1.2.4 + postcss: 8.5.3 + postcss-values-parser: 6.0.2(postcss@8.5.3) + + detective-sass@6.0.1: + dependencies: + gonzales-pe: 4.3.0 + node-source-walk: 7.0.1 + + detective-scss@5.0.1: + dependencies: + gonzales-pe: 4.3.0 + node-source-walk: 7.0.1 + + detective-stylus@5.0.1: {} + + detective-typescript@14.0.0(typescript@5.7.3): + dependencies: + '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3) + ast-module-types: 6.0.1 + node-source-walk: 7.0.1 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + detective-vue2@2.2.0(typescript@5.7.3): + dependencies: + '@dependents/detective-less': 5.0.1 + '@vue/compiler-sfc': 3.5.13 + detective-es6: 5.0.1 + detective-sass: 6.0.1 + detective-scss: 5.0.1 + detective-stylus: 5.0.1 + detective-typescript: 14.0.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + diff-sequences@29.6.3: {} diff@4.0.2: {} @@ -11610,6 +12034,14 @@ snapshots: escape-string-regexp@4.0.0: {} + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + eslint-config-prettier@10.1.2(eslint@9.24.0(jiti@2.4.2)): dependencies: eslint: 9.24.0(jiti@2.4.2) @@ -11974,6 +12406,20 @@ snapshots: dependencies: filename-reserved-regex: 3.0.0 + filing-cabinet@5.0.3: + dependencies: + app-module-path: 2.2.0 + commander: 12.1.0 + enhanced-resolve: 5.18.1 + module-definition: 6.0.1 + module-lookup-amd: 9.0.4 + resolve: 1.22.10 + resolve-dependency-path: 4.0.1 + sass-lookup: 6.1.0 + stylus-lookup: 6.1.0 + tsconfig-paths: 4.2.0 + typescript: 5.7.3 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -12133,6 +12579,11 @@ snapshots: gensync@1.0.0-beta.2: {} + get-amd-module-type@6.0.1: + dependencies: + ast-module-types: 6.0.1 + node-source-walk: 7.0.1 + get-caller-file@2.0.5: {} get-east-asian-width@1.3.0: {} @@ -12150,6 +12601,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-own-enumerable-property-symbols@3.0.2: {} + get-package-type@0.1.0: {} get-proto@1.0.1: @@ -12271,6 +12724,10 @@ snapshots: globrex@0.1.2: {} + gonzales-pe@4.3.0: + dependencies: + minimist: 1.2.8 + gopd@1.2.0: {} got@13.0.0: @@ -12640,6 +13097,8 @@ snapshots: is-number@7.0.0: {} + is-obj@1.0.1: {} + is-obj@2.0.0: {} is-plain-obj@1.1.0: {} @@ -12657,6 +13116,8 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 + is-regexp@1.0.0: {} + is-set@2.0.3: {} is-shared-array-buffer@1.0.4: @@ -12698,6 +13159,10 @@ snapshots: is-unicode-supported@0.1.0: {} + is-url-superb@4.0.0: {} + + is-url@1.2.4: {} + is-utf8@0.2.1: {} is-weakmap@2.0.2: {} @@ -13349,6 +13814,25 @@ snapshots: lunr@2.3.9: {} + madge@8.0.0(typescript@5.7.3): + dependencies: + chalk: 4.1.2 + commander: 7.2.0 + commondir: 1.0.1 + debug: 4.4.0 + dependency-tree: 11.1.1 + ora: 5.4.1 + pluralize: 8.0.0 + pretty-ms: 7.0.1 + rc: 1.2.8 + stream-to-array: 2.3.0 + ts-graphviz: 2.1.6 + walkdir: 0.4.1 + optionalDependencies: + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -13468,6 +13952,18 @@ snapshots: pkg-types: 1.3.1 ufo: 1.5.4 + module-definition@6.0.1: + dependencies: + ast-module-types: 6.0.1 + node-source-walk: 7.0.1 + + module-lookup-amd@9.0.4: + dependencies: + commander: 12.1.0 + glob: 7.2.3 + requirejs: 2.3.7 + requirejs-config-file: 4.0.0 + moo-color@1.0.3: dependencies: color-name: 1.1.4 @@ -13571,6 +14067,10 @@ snapshots: node-releases@2.0.19: {} + node-source-walk@7.0.1: + dependencies: + '@babel/parser': 7.27.0 + normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 @@ -13887,6 +14387,8 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-ms@2.1.0: {} + parse-passwd@1.0.0: {} parse5@7.2.1: @@ -14003,6 +14505,8 @@ snapshots: optionalDependencies: fsevents: 2.3.2 + pluralize@8.0.0: {} + portfinder@1.0.35: dependencies: async: 3.2.6 @@ -14012,12 +14516,39 @@ snapshots: possible-typed-array-names@1.1.0: {} + postcss-values-parser@6.0.2(postcss@8.5.3): + dependencies: + color-name: 1.1.4 + is-url-superb: 4.0.0 + postcss: 8.5.3 + quote-unquote: 1.0.0 + postcss@8.5.3: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 + precinct@12.2.0: + dependencies: + '@dependents/detective-less': 5.0.1 + commander: 12.1.0 + detective-amd: 6.0.1 + detective-cjs: 6.0.1 + detective-es6: 5.0.1 + detective-postcss: 7.0.1(postcss@8.5.3) + detective-sass: 6.0.1 + detective-scss: 5.0.1 + detective-stylus: 5.0.1 + detective-typescript: 14.0.0(typescript@5.7.3) + detective-vue2: 2.2.0(typescript@5.7.3) + module-definition: 6.0.1 + node-source-walk: 7.0.1 + postcss: 8.5.3 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.0: @@ -14034,6 +14565,10 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + pretty-ms@7.0.1: + dependencies: + parse-ms: 2.1.0 + proc-log@3.0.0: {} process-nextick-args@2.0.1: {} @@ -14097,6 +14632,8 @@ snapshots: quick-lru@5.1.1: {} + quote-unquote@1.0.0: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -14110,6 +14647,13 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + react-is@18.3.1: {} read-yaml-file@1.1.0: @@ -14229,12 +14773,21 @@ snapshots: require-from-string@2.0.2: {} + requirejs-config-file@4.0.0: + dependencies: + esprima: 4.0.1 + stringify-object: 3.3.0 + + requirejs@2.3.7: {} + requires-port@1.0.0: {} reselect@5.1.1: {} resolve-alpn@1.2.1: {} + resolve-dependency-path@4.0.1: {} + resolve-dir@1.0.1: dependencies: expand-tilde: 2.0.2 @@ -14352,6 +14905,11 @@ snapshots: safer-buffer@2.1.2: {} + sass-lookup@6.1.0: + dependencies: + commander: 12.1.0 + enhanced-resolve: 5.18.1 + saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -14641,6 +15199,10 @@ snapshots: stream-shift@1.0.3: {} + stream-to-array@2.3.0: + dependencies: + any-promise: 1.3.0 + streamx@2.22.0: dependencies: fast-fifo: 1.3.2 @@ -14713,6 +15275,12 @@ snapshots: dependencies: safe-buffer: 5.2.1 + stringify-object@3.3.0: + dependencies: + get-own-enumerable-property-symbols: 3.0.2 + is-obj: 1.0.1 + is-regexp: 1.0.0 + strip-ansi@3.0.1: dependencies: ansi-regex: 2.1.1 @@ -14741,6 +15309,8 @@ snapshots: strip-final-newline@3.0.0: {} + strip-json-comments@2.0.1: {} + strip-json-comments@3.1.1: {} strtok3@9.1.1: @@ -14748,6 +15318,10 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.4.2 + stylus-lookup@6.1.0: + dependencies: + commander: 12.1.0 + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -14912,6 +15486,13 @@ snapshots: dependencies: typescript: 5.7.3 + ts-graphviz@2.1.6: + dependencies: + '@ts-graphviz/adapter': 2.0.6 + '@ts-graphviz/ast': 2.0.7 + '@ts-graphviz/common': 2.1.5 + '@ts-graphviz/core': 2.0.7 + ts-node@10.9.1(@swc/core@1.11.15(@swc/helpers@0.5.15))(@types/node@22.13.16)(typescript@5.7.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -15324,6 +15905,18 @@ snapshots: terser: 5.39.0 yaml: 2.7.1 + vite@6.2.5(@types/node@22.13.16)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.1): + dependencies: + esbuild: 0.25.2 + postcss: 8.5.3 + rollup: 4.38.0 + optionalDependencies: + '@types/node': 22.13.16 + fsevents: 2.3.3 + jiti: 2.4.2 + terser: 5.39.0 + yaml: 2.7.1 + vite@6.2.6(@types/node@22.13.16)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.1): dependencies: esbuild: 0.25.2 @@ -15341,10 +15934,10 @@ snapshots: jest-canvas-mock: 2.5.2 vitest: 3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.7.3))(terser@5.39.0)(yaml@2.7.1) - vitest@3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4(vitest@3.0.5))(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(terser@5.39.0)(yaml@2.7.1): + vitest@3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.7.3))(terser@5.39.0)(yaml@2.7.1): dependencies: '@vitest/expect': 3.0.5 - '@vitest/mocker': 3.0.5(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(vite@6.2.3(@types/node@22.13.16)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.1)) + '@vitest/mocker': 3.0.5(msw@2.7.3(@types/node@22.13.16)(typescript@5.7.3))(vite@6.2.3(@types/node@22.13.16)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.1)) '@vitest/pretty-format': 3.1.1 '@vitest/runner': 3.0.5 '@vitest/snapshot': 3.0.5 @@ -15381,10 +15974,10 @@ snapshots: - tsx - yaml - vitest@3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.7.3))(terser@5.39.0)(yaml@2.7.1): + vitest@3.0.5(@types/node@22.13.16)(@vitest/ui@3.0.4)(jiti@2.4.2)(jsdom@26.0.0)(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(terser@5.39.0)(yaml@2.7.1): dependencies: '@vitest/expect': 3.0.5 - '@vitest/mocker': 3.0.5(msw@2.7.3(@types/node@22.13.16)(typescript@5.7.3))(vite@6.2.3(@types/node@22.13.16)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.1)) + '@vitest/mocker': 3.0.5(msw@2.7.3(@types/node@22.13.16)(typescript@5.8.2))(vite@6.2.3(@types/node@22.13.16)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.1)) '@vitest/pretty-format': 3.1.1 '@vitest/runner': 3.0.5 '@vitest/snapshot': 3.0.5 @@ -15427,6 +16020,8 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + walkdir@0.4.1: {} + walker@1.0.8: dependencies: makeerror: 1.0.12 diff --git a/tsconfig.base.json b/tsconfig.base.json index 1f316f588..fc5c64323 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -3,6 +3,7 @@ "composite": true, "declaration": true, "declarationMap": true, - "skipLibCheck": true + "skipLibCheck": true, + "baseUrl": "." } } diff --git a/tsconfig.json b/tsconfig.json index 48184413d..190d75dae 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.base.json", "compileOnSave": false, "compilerOptions": {}, - "files": [], // intentionally empty + "files": [], "references": [ { "path": "./packages/device-client" @@ -18,6 +18,15 @@ }, { "path": "./packages/davinci-client" + }, + { + "path": "./packages/sdk-utilities" + }, + { + "path": "./packages/effects" + }, + { + "path": "./packages/shared-types" } ] }