diff --git a/.gitignore b/.gitignore index 0c3f3abc9..a95d6581e 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ dump.rdb # connectors /packages/core/connectors + +# console auto generated files +/packages/console/src/consts/jwt-customizer-type-definition.ts diff --git a/packages/console/generate.sh b/packages/console/generate.sh new file mode 100755 index 000000000..d54dcf99a --- /dev/null +++ b/packages/console/generate.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# Clean up +rm -rf scripts-js/ +# build the jwt-customizer-type-definition generate script +pnpm exec tsc -p tsconfig.scripts.gen.json +# clean up the existing generated jwt-customizer-type-definition file +rm -f src/consts/jwt-customizer-type-definition.ts +# run script +node scripts-js/generate-jwt-customizer-type-definition.js +# Clean up +rm -rf scripts-js/ diff --git a/packages/console/package.json b/packages/console/package.json index 6df6957fe..94113d371 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -11,11 +11,13 @@ "dist" ], "scripts": { + "prepack": "pnpm generate", + "generate": "./generate.sh", "precommit": "lint-staged", "start": "parcel src/index.html", "dev": "cross-env PORT=5002 parcel src/index.html --public-url ${CONSOLE_PUBLIC_URL:-/console} --no-cache --hmr-port 6002", "check": "tsc --noEmit", - "build": "pnpm check && rm -rf dist && parcel build src/index.html --no-autoinstall --no-cache --public-url ${CONSOLE_PUBLIC_URL:-/console}", + "build": "pnpm generate && pnpm check && rm -rf dist && parcel build src/index.html --no-autoinstall --no-cache --public-url ${CONSOLE_PUBLIC_URL:-/console}", "lint": "eslint --ext .ts --ext .tsx src", "lint:report": "pnpm lint --format json --output-file report.json", "stylelint": "stylelint \"src/**/*.scss\"", @@ -121,7 +123,8 @@ "ts-node": "^10.9.2", "tslib": "^2.4.1", "typescript": "^5.3.3", - "zod": "^3.22.4" + "zod": "^3.22.4", + "zod-to-ts": "^1.2.0" }, "engines": { "node": "^20.9.0" @@ -141,6 +144,12 @@ }, "eslintConfig": { "extends": "@silverhand/react", + "parserOptions": { + "project": [ + "./tsconfig.json", + "./tsconfig.scripts.gen.json" + ] + }, "rules": { "react/function-component-definition": [ "error", diff --git a/packages/console/scripts/generate-jwt-customizer-type-definition.ts b/packages/console/scripts/generate-jwt-customizer-type-definition.ts new file mode 100644 index 000000000..744b74d46 --- /dev/null +++ b/packages/console/scripts/generate-jwt-customizer-type-definition.ts @@ -0,0 +1,64 @@ +import fs from 'node:fs'; + +import { + jwtCustomizerUserContextGuard, + accessTokenPayloadGuard, + clientCredentialsPayloadGuard, +} from '@logto/schemas'; +import prettier from 'prettier'; +import { type ZodTypeAny } from 'zod'; +import { zodToTs, printNode } from 'zod-to-ts'; + +const filePath = 'src/consts/jwt-customizer-type-definition.ts'; + +const typeIdentifiers = `export enum JwtCustomizerTypeDefinitionKey { + JwtCustomizerUserContext = 'JwtCustomizerUserContext', + AccessTokenPayload = 'AccessTokenPayload', + ClientCredentialsPayload = 'ClientCredentialsPayload', + EnvironmentVariables = 'EnvironmentVariables', +};`; + +const inferTsDefinitionFromZod = (zodSchema: ZodTypeAny, identifier: string): string => { + const { node } = zodToTs(zodSchema, identifier); + const typeDefinition = printNode(node); + + return `type ${identifier} = ${typeDefinition};`; +}; + +// Create the jwt-customizer-type-definition.ts file +const createJwtCustomizerTypeDefinitions = async () => { + const jwtCustomizerUserContextTypeDefinition = inferTsDefinitionFromZod( + jwtCustomizerUserContextGuard, + 'JwtCustomizerUserContext' + ); + + const accessTokenPayloadTypeDefinition = inferTsDefinitionFromZod( + accessTokenPayloadGuard, + 'AccessTokenPayload' + ); + + const clientCredentialsPayloadTypeDefinition = inferTsDefinitionFromZod( + clientCredentialsPayloadGuard, + 'ClientCredentialsPayload' + ); + + const fileContent = `/* This file is auto-generated. Do not modify it manually. */ +${typeIdentifiers} + +export const jwtCustomizerUserContextTypeDefinition = \`${jwtCustomizerUserContextTypeDefinition}\`; + +export const accessTokenPayloadTypeDefinition = \`${accessTokenPayloadTypeDefinition}\`; + +export const clientCredentialsPayloadTypeDefinition = \`${clientCredentialsPayloadTypeDefinition}\`; +`; + + const formattedFileContent = await prettier.format(fileContent, { + parser: 'typescript', + tabWidth: 2, + singleQuote: true, + }); + + fs.writeFileSync(filePath, formattedFileContent); +}; + +void createJwtCustomizerTypeDefinitions(); diff --git a/packages/console/src/pages/JwtClaims/Main.tsx b/packages/console/src/pages/JwtClaims/Main.tsx index d23cf1caf..2fa5e1e8b 100644 --- a/packages/console/src/pages/JwtClaims/Main.tsx +++ b/packages/console/src/pages/JwtClaims/Main.tsx @@ -17,7 +17,11 @@ import ScriptSection from './ScriptSection'; import SettingsSection from './SettingsSection'; import * as styles from './index.module.scss'; import { type JwtClaimsFormType } from './type'; -import { formatResponseDataToFormData, formatFormDataToRequestData, getApiPath } from './utils'; +import { + formatResponseDataToFormData, + formatFormDataToRequestData, + getApiPath, +} from './utils/format'; type Props = { className?: string; @@ -100,7 +104,7 @@ function Main({ onDiscard={reset} onSubmit={onSubmitHandler} /> - + ); } diff --git a/packages/console/src/pages/JwtClaims/MonacoCodeEditor/index.tsx b/packages/console/src/pages/JwtClaims/MonacoCodeEditor/index.tsx index 1d69d9141..892108547 100644 --- a/packages/console/src/pages/JwtClaims/MonacoCodeEditor/index.tsx +++ b/packages/console/src/pages/JwtClaims/MonacoCodeEditor/index.tsx @@ -24,6 +24,7 @@ type Props = { activeModelName?: string; setActiveModel?: (name: string) => void; value?: string; + environmentVariablesDefinition?: string; onChange?: (value: string | undefined) => void; onMountHandler?: (editor: IStandaloneCodeEditor) => void; }; @@ -37,6 +38,7 @@ type Props = { * @param {(name: string) => void} prop.setActiveModel - The callback function to set the active model. Used to switch between tabs. * @param {string} prop.value - The value of the code editor for the current active model. * @param {(value: string | undefined) => void} prop.onChange - The callback function to handle the value change of the code editor. + * @param {string} [prop.environmentVariablesDefinition] - The environment variables type definition for the script section. * * @returns */ @@ -46,6 +48,7 @@ function MonacoCodeEditor({ models, activeModelName, value, + environmentVariablesDefinition, setActiveModel, onChange, onMountHandler, @@ -71,19 +74,28 @@ function MonacoCodeEditor({ // Set the global declarations for the active model // @see {@link https://microsoft.github.io/monaco-editor/typedoc/interfaces/languages.typescript.LanguageServiceDefaults.html#setExtraLibs} - if (activeModel.globalDeclarations) { - monaco.languages.typescript.typescriptDefaults.setExtraLibs([ - { - content: activeModel.globalDeclarations, - filePath: `file:///global.d.ts`, - }, - ]); + if (activeModel.extraLibs) { + monaco.languages.typescript.typescriptDefaults.setExtraLibs(activeModel.extraLibs); } - }, [activeModel, monaco]); + + // Set the environment variables type definition for the active model + if (environmentVariablesDefinition) { + monaco.languages.typescript.typescriptDefaults.addExtraLib( + environmentVariablesDefinition, + 'environmentVariables.d.ts' + ); + } + }, [activeModel, monaco, environmentVariablesDefinition]); const handleEditorWillMount = useCallback((monaco) => { // Register the new logto theme monaco.editor.defineTheme('logto-dark', logtoDarkTheme); + + // Set the typescript compiler options + monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ + allowNonTsExtensions: true, + strictNullChecks: true, + }); }, []); const handleEditorDidMount = useCallback( diff --git a/packages/console/src/pages/JwtClaims/MonacoCodeEditor/type.ts b/packages/console/src/pages/JwtClaims/MonacoCodeEditor/type.ts index 1851f334f..7061080c3 100644 --- a/packages/console/src/pages/JwtClaims/MonacoCodeEditor/type.ts +++ b/packages/console/src/pages/JwtClaims/MonacoCodeEditor/type.ts @@ -4,6 +4,11 @@ export type IStandaloneThemeData = Parameters[1 export type IStandaloneCodeEditor = Parameters[0]; +type ExtraLibrary = { + content: string; + filePath: string; +}; + export type ModelSettings = { /** Used as the unique key for the monaco editor model @see {@link https://github.com/suren-atoyan/monaco-react?tab=readme-ov-file#multi-model-editor} */ name: string; @@ -19,7 +24,7 @@ export type ModelSettings = { * @see {@link https://microsoft.github.io/monaco-editor/typedoc/interfaces/languages.typescript.LanguageServiceDefaults.html#setExtraLibs} * We use this to load the global type declarations for the active model */ - globalDeclarations?: string; + extraLibs?: ExtraLibrary[]; }; export type ModelControl = { diff --git a/packages/console/src/pages/JwtClaims/ScriptSection.tsx b/packages/console/src/pages/JwtClaims/ScriptSection.tsx index 3ff187181..6a4912a60 100644 --- a/packages/console/src/pages/JwtClaims/ScriptSection.tsx +++ b/packages/console/src/pages/JwtClaims/ScriptSection.tsx @@ -1,16 +1,17 @@ /* Code Editor for the custom JWT claims script. */ import { LogtoJwtTokenPath } from '@logto/schemas'; import { useMemo, useContext, useCallback } from 'react'; -import { useFormContext, Controller } from 'react-hook-form'; +import { useFormContext, Controller, useWatch } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import Card from '@/ds-components/Card'; import { CodeEditorLoadingContext } from './CodeEditorLoadingContext'; import MonacoCodeEditor, { type ModelSettings } from './MonacoCodeEditor'; -import { userJwtFile, machineToMachineJwtFile } from './config'; import * as styles from './index.module.scss'; import { type JwtClaimsFormType } from './type'; +import { accessTokenJwtCustomizerModel, clientCredentialsModel } from './utils/config'; +import { buildEnvironmentVariablesTypeDefinition } from './utils/type-definitions'; const titlePhrases = Object.freeze({ [LogtoJwtTokenPath.AccessToken]: 'user_jwt', @@ -21,12 +22,28 @@ function ScriptSection() { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { watch, control } = useFormContext(); + const tokenType = watch('tokenType'); + // Need to use useWatch hook to subscribe the mutation of the environmentVariables field + // Otherwise, the default watch function's return value won't mutate when the environmentVariables field changes + const envVariables = useWatch({ + control, + name: 'environmentVariables', + }); + + const environmentVariablesTypeDefinition = useMemo( + () => buildEnvironmentVariablesTypeDefinition(envVariables), + [envVariables] + ); + const { setIsMonacoLoaded } = useContext(CodeEditorLoadingContext); const activeModel = useMemo( - () => (tokenType === LogtoJwtTokenPath.AccessToken ? userJwtFile : machineToMachineJwtFile), + () => + tokenType === LogtoJwtTokenPath.AccessToken + ? accessTokenJwtCustomizerModel + : clientCredentialsModel, [tokenType] ); @@ -54,6 +71,7 @@ function ScriptSection() { models={[activeModel]} activeModelName={activeModel.name} value={value} + environmentVariablesDefinition={environmentVariablesTypeDefinition} onChange={(newValue) => { // If the value is the same as the default code and the original form script value is undefined, reset the value to undefined as well if (newValue === activeModel.defaultValue && !defaultValues?.script) { diff --git a/packages/console/src/pages/JwtClaims/SettingsSection/InstructionTab.tsx b/packages/console/src/pages/JwtClaims/SettingsSection/InstructionTab.tsx index e477fbce0..33bf332bd 100644 --- a/packages/console/src/pages/JwtClaims/SettingsSection/InstructionTab.tsx +++ b/packages/console/src/pages/JwtClaims/SettingsSection/InstructionTab.tsx @@ -7,13 +7,13 @@ import { useTranslation } from 'react-i18next'; import Table from '@/ds-components/Table'; +import { type JwtClaimsFormType } from '../type'; import { userDataDescription, tokenDataDescription, fetchExternalDataEditorOptions, fetchExternalDataCodeExample, -} from '../config'; -import { type JwtClaimsFormType } from '../type'; +} from '../utils/config'; import EnvironmentVariablesField from './EnvironmentVariablesField'; import GuideCard, { CardType } from './GuideCard'; diff --git a/packages/console/src/pages/JwtClaims/SettingsSection/TestTab.tsx b/packages/console/src/pages/JwtClaims/SettingsSection/TestTab.tsx index e9fc0197b..d91020b82 100644 --- a/packages/console/src/pages/JwtClaims/SettingsSection/TestTab.tsx +++ b/packages/console/src/pages/JwtClaims/SettingsSection/TestTab.tsx @@ -8,12 +8,12 @@ import Button from '@/ds-components/Button'; import Card from '@/ds-components/Card'; import MonacoCodeEditor, { type ModelControl } from '../MonacoCodeEditor/index.js'; +import { type JwtClaimsFormType } from '../type.js'; import { userTokenPayloadTestModel, machineToMachineTokenPayloadTestModel, userTokenContextTestModel, -} from '../config.js'; -import { type JwtClaimsFormType } from '../type.js'; +} from '../utils/config.js'; import TestResult, { type TestResultData } from './TestResult.js'; import * as styles from './index.module.scss'; diff --git a/packages/console/src/pages/JwtClaims/use-jwt-customizer.ts b/packages/console/src/pages/JwtClaims/use-jwt-customizer.ts index b28c95d57..4bd3ab65e 100644 --- a/packages/console/src/pages/JwtClaims/use-jwt-customizer.ts +++ b/packages/console/src/pages/JwtClaims/use-jwt-customizer.ts @@ -11,7 +11,7 @@ import useApi from '@/hooks/use-api'; import useSwrFetcher from '@/hooks/use-swr-fetcher'; import { shouldRetryOnError } from '@/utils/request'; -import { getApiPath } from './utils'; +import { getApiPath } from './utils/format'; function useJwtCustomizer() { const fetchApi = useApi({ hideErrorToast: true }); diff --git a/packages/console/src/pages/JwtClaims/config.tsx b/packages/console/src/pages/JwtClaims/utils/config.tsx similarity index 66% rename from packages/console/src/pages/JwtClaims/config.tsx rename to packages/console/src/pages/JwtClaims/utils/config.tsx index da7d1e697..a4b89ba4a 100644 --- a/packages/console/src/pages/JwtClaims/config.tsx +++ b/packages/console/src/pages/JwtClaims/utils/config.tsx @@ -3,52 +3,40 @@ import { type EditorProps } from '@monaco-editor/react'; import TokenFileIcon from '@/assets/icons/token-file-icon.svg'; import UserFileIcon from '@/assets/icons/user-file-icon.svg'; -import type { ModelSettings } from './MonacoCodeEditor/type.js'; +import type { ModelSettings } from '../MonacoCodeEditor/type.js'; + +import { + JwtCustomizerTypeDefinitionKey, + buildAccessTokenJwtCustomizerContextTsDefinition, + buildClientCredentialsJwtCustomizerContextTsDefinition, +} from './type-definitions.js'; /** * JWT token code editor configuration */ -const userJwtGlobalDeclarations = ` +const accessTokenJwtCustomizerDefinition = ` declare global { export interface CustomJwtClaims extends Record {} - /** The user info associated with the token. - * - * @param {string} id - The user id - * @param {string} [primaryEmail] - The user email - * @param {string} [primaryPhone] - The user phone - * @param {string} [username] - The user username - * @param {string} [name] - The user name - * @param {string} [avatar] - The user avatar - * - */ - export type User = { - id: string; - primaryEmail?: string; - primaryPhone?: string; - username?: string; - name?: string; - avatar?: string; - } - /** Logto internal data that can be used to pass additional information - * @param {User} user - The user info associated with the token. + * @param {${JwtCustomizerTypeDefinitionKey.JwtCustomizerUserContext}} user - The user info associated with the token. */ export type Data = { - user: User; + user: ${JwtCustomizerTypeDefinitionKey.JwtCustomizerUserContext}; } export interface Exports { /** * This function is called to get custom claims for the JWT token. * - * @param {string} token -The JWT token. + * @param {${JwtCustomizerTypeDefinitionKey.AccessTokenPayload}} token -The JWT token. * @param {Data} data - Logto internal data that can be used to pass additional information - * @param {User} data.user - The user info associated with the token. + * @param {${JwtCustomizerTypeDefinitionKey.JwtCustomizerUserContext}} data.user - The user info associated with the token. + * @param {${JwtCustomizerTypeDefinitionKey.EnvironmentVariables}} envVariables - The environment variables. * * @returns The custom claims. */ - getCustomJwtClaims: (token: string, data: Data) => Promise; + getCustomJwtClaims: (token: ${JwtCustomizerTypeDefinitionKey.AccessTokenPayload}, data: Data, envVariables: ${JwtCustomizerTypeDefinitionKey.EnvironmentVariables}) => Promise; } const exports: Exports; @@ -57,7 +45,7 @@ declare global { export { exports as default }; `; -const machineToMachineJwtGlobalDeclarations = ` +const clientCredentialsJwtCustomizerDefinition = ` declare global { export interface CustomJwtClaims extends Record {} @@ -65,11 +53,11 @@ declare global { /** * This function is called to get custom claims for the JWT token. * - * @param {string} token -The JWT token. + * @param {${JwtCustomizerTypeDefinitionKey.ClientCredentialsPayload}} token -The JWT token. * * @returns The custom claims. */ - getCustomJwtClaims: (token: string) => Promise; + getCustomJwtClaims: (token: ${JwtCustomizerTypeDefinitionKey.ClientCredentialsPayload}, envVariables: ${JwtCustomizerTypeDefinitionKey.EnvironmentVariables}) => Promise; } const exports: Exports; @@ -78,12 +66,13 @@ declare global { export { exports as default }; `; -const defaultUserJwtClaimsCode = `/** +const defaultAccessTokenJwtCustomizerCode = `/** * This function is called to get custom claims for the JWT token. * -* @param {string} token -The JWT token. +* @param {${JwtCustomizerTypeDefinitionKey.AccessTokenPayload}} token -The JWT token. * @param {Data} data - Logto internal data that can be used to pass additional information -* @param {User} data.user - The user info associated with the token. +* @param {${JwtCustomizerTypeDefinitionKey.JwtCustomizerUserContext}} data.user - The user info associated with the token. +* @param {${JwtCustomizerTypeDefinitionKey.EnvironmentVariables}} [envVariables] - The environment variables. * * @returns The custom claims. */ @@ -92,10 +81,11 @@ exports.getCustomJwtClaims = async (token, data) => { return {}; }`; -const defaultMachineToMachineJwtClaimsCode = `/** +const defaultClientCredentialsJwtCustomizerCode = `/** * This function is called to get custom claims for the JWT token. * -* @param {string} token -The JWT token. +* @param {${JwtCustomizerTypeDefinitionKey.ClientCredentialsPayload}} token -The JWT token. +* @param {${JwtCustomizerTypeDefinitionKey.EnvironmentVariables}} [envVariables] - The environment variables. * * @returns The custom claims. */ @@ -104,20 +94,38 @@ exports.getCustomJwtClaims = async (token) => { return {}; }`; -export const userJwtFile: ModelSettings = { +export const accessTokenJwtCustomizerModel: ModelSettings = { name: 'user-jwt.ts', title: 'TypeScript', language: 'typescript', - defaultValue: defaultUserJwtClaimsCode, - globalDeclarations: userJwtGlobalDeclarations, + defaultValue: defaultAccessTokenJwtCustomizerCode, + extraLibs: [ + { + content: accessTokenJwtCustomizerDefinition, + filePath: `file:///logto-jwt-customizer.d.ts`, + }, + { + content: buildAccessTokenJwtCustomizerContextTsDefinition(), + filePath: `file:///logto-jwt-customizer-context.d.ts`, + }, + ], }; -export const machineToMachineJwtFile: ModelSettings = { +export const clientCredentialsModel: ModelSettings = { name: 'machine-to-machine-jwt.ts', title: 'TypeScript', language: 'typescript', - defaultValue: defaultMachineToMachineJwtClaimsCode, - globalDeclarations: machineToMachineJwtGlobalDeclarations, + defaultValue: defaultClientCredentialsJwtCustomizerCode, + extraLibs: [ + { + content: clientCredentialsJwtCustomizerDefinition, + filePath: `file:///logto-jwt-customizer.d.ts`, + }, + { + content: buildClientCredentialsJwtCustomizerContextTsDefinition(), + filePath: `file:///logto-jwt-customizer-context.d.ts`, + }, + ], }; /** diff --git a/packages/console/src/pages/JwtClaims/utils.ts b/packages/console/src/pages/JwtClaims/utils/format.ts similarity index 98% rename from packages/console/src/pages/JwtClaims/utils.ts rename to packages/console/src/pages/JwtClaims/utils/format.ts index 1adccd8cd..c158f6258 100644 --- a/packages/console/src/pages/JwtClaims/utils.ts +++ b/packages/console/src/pages/JwtClaims/utils/format.ts @@ -4,7 +4,7 @@ import { type ClientCredentialsJwtCustomizer, } from '@logto/schemas'; -import type { JwtClaimsFormType } from './type'; +import type { JwtClaimsFormType } from '../type'; const formatEnvVariablesResponseToFormData = ( enVariables?: AccessTokenJwtCustomizer['envVars'] diff --git a/packages/console/src/pages/JwtClaims/utils/type-definitions.ts b/packages/console/src/pages/JwtClaims/utils/type-definitions.ts new file mode 100644 index 000000000..d998f3afd --- /dev/null +++ b/packages/console/src/pages/JwtClaims/utils/type-definitions.ts @@ -0,0 +1,34 @@ +import { + JwtCustomizerTypeDefinitionKey, + accessTokenPayloadTypeDefinition, + jwtCustomizerUserContextTypeDefinition, + clientCredentialsPayloadTypeDefinition, +} from '@/consts/jwt-customizer-type-definition'; + +import { type JwtClaimsFormType } from '../type'; + +export { JwtCustomizerTypeDefinitionKey } from '@/consts/jwt-customizer-type-definition'; + +export const buildAccessTokenJwtCustomizerContextTsDefinition = () => { + return `declare ${jwtCustomizerUserContextTypeDefinition} + + declare ${accessTokenPayloadTypeDefinition}`; +}; + +export const buildClientCredentialsJwtCustomizerContextTsDefinition = () => + `declare ${clientCredentialsPayloadTypeDefinition}`; + +export const buildEnvironmentVariablesTypeDefinition = ( + envVariables?: JwtClaimsFormType['environmentVariables'] +) => { + const typeDefinition = envVariables + ? `{ + ${envVariables + .filter(({ key }) => Boolean(key)) + .map(({ key }) => `${key}: string`) + .join(';\n')} + }` + : 'undefined'; + + return `declare type ${JwtCustomizerTypeDefinitionKey.EnvironmentVariables} = ${typeDefinition}`; +}; diff --git a/packages/console/tsconfig.scripts.gen.json b/packages/console/tsconfig.scripts.gen.json new file mode 100644 index 000000000..ac248a2ce --- /dev/null +++ b/packages/console/tsconfig.scripts.gen.json @@ -0,0 +1,7 @@ +{ + "extends": "@silverhand/ts-config/tsconfig.base", + "compilerOptions": { + "outDir": "scripts-js" + }, + "include": ["scripts"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86c857370..c08d806d7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3200,6 +3200,9 @@ importers: zod: specifier: ^3.22.4 version: 3.22.4 + zod-to-ts: + specifier: ^1.2.0 + version: 1.2.0(typescript@5.3.3)(zod@3.22.4) packages/core: dependencies: @@ -21483,6 +21486,16 @@ packages: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} + /zod-to-ts@1.2.0(typescript@5.3.3)(zod@3.22.4): + resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==} + peerDependencies: + typescript: ^4.9.4 || ^5.0.2 + zod: ^3 + dependencies: + typescript: 5.3.3 + zod: 3.22.4 + dev: true + /zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} requiresBuild: true