0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

refactor(console): refactor the code editor type definition (#5516)

* refactor(console): refactor the code editor type definition

refactor the code editor type definition

* refactor(console): extract type definition gen process

extract the type definition gen step to the build time. As typescript is not available at run time.

* fix(console): add generate to console build script

add generate to console build script

* fix(console): add prettier format

add prettier format
This commit is contained in:
simeng-li 2024-03-19 12:50:07 +08:00 committed by GitHub
parent 23bc5cdc8e
commit 08acdf73e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 251 additions and 62 deletions

3
.gitignore vendored
View file

@ -35,3 +35,6 @@ dump.rdb
# connectors # connectors
/packages/core/connectors /packages/core/connectors
# console auto generated files
/packages/console/src/consts/jwt-customizer-type-definition.ts

12
packages/console/generate.sh Executable file
View file

@ -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/

View file

@ -11,11 +11,13 @@
"dist" "dist"
], ],
"scripts": { "scripts": {
"prepack": "pnpm generate",
"generate": "./generate.sh",
"precommit": "lint-staged", "precommit": "lint-staged",
"start": "parcel src/index.html", "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", "dev": "cross-env PORT=5002 parcel src/index.html --public-url ${CONSOLE_PUBLIC_URL:-/console} --no-cache --hmr-port 6002",
"check": "tsc --noEmit", "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": "eslint --ext .ts --ext .tsx src",
"lint:report": "pnpm lint --format json --output-file report.json", "lint:report": "pnpm lint --format json --output-file report.json",
"stylelint": "stylelint \"src/**/*.scss\"", "stylelint": "stylelint \"src/**/*.scss\"",
@ -121,7 +123,8 @@
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tslib": "^2.4.1", "tslib": "^2.4.1",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"zod": "^3.22.4" "zod": "^3.22.4",
"zod-to-ts": "^1.2.0"
}, },
"engines": { "engines": {
"node": "^20.9.0" "node": "^20.9.0"
@ -141,6 +144,12 @@
}, },
"eslintConfig": { "eslintConfig": {
"extends": "@silverhand/react", "extends": "@silverhand/react",
"parserOptions": {
"project": [
"./tsconfig.json",
"./tsconfig.scripts.gen.json"
]
},
"rules": { "rules": {
"react/function-component-definition": [ "react/function-component-definition": [
"error", "error",

View file

@ -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();

View file

@ -17,7 +17,11 @@ import ScriptSection from './ScriptSection';
import SettingsSection from './SettingsSection'; import SettingsSection from './SettingsSection';
import * as styles from './index.module.scss'; import * as styles from './index.module.scss';
import { type JwtClaimsFormType } from './type'; import { type JwtClaimsFormType } from './type';
import { formatResponseDataToFormData, formatFormDataToRequestData, getApiPath } from './utils'; import {
formatResponseDataToFormData,
formatFormDataToRequestData,
getApiPath,
} from './utils/format';
type Props = { type Props = {
className?: string; className?: string;
@ -100,7 +104,7 @@ function Main({
onDiscard={reset} onDiscard={reset}
onSubmit={onSubmitHandler} onSubmit={onSubmitHandler}
/> />
<UnsavedChangesAlertModal hasUnsavedChanges={isDirty && !isSubmitting} /> <UnsavedChangesAlertModal hasUnsavedChanges={isDirty && !isSubmitting} onConfirm={reset} />
</> </>
); );
} }

View file

@ -24,6 +24,7 @@ type Props = {
activeModelName?: string; activeModelName?: string;
setActiveModel?: (name: string) => void; setActiveModel?: (name: string) => void;
value?: string; value?: string;
environmentVariablesDefinition?: string;
onChange?: (value: string | undefined) => void; onChange?: (value: string | undefined) => void;
onMountHandler?: (editor: IStandaloneCodeEditor) => 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 {(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 {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 {(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 * @returns
*/ */
@ -46,6 +48,7 @@ function MonacoCodeEditor({
models, models,
activeModelName, activeModelName,
value, value,
environmentVariablesDefinition,
setActiveModel, setActiveModel,
onChange, onChange,
onMountHandler, onMountHandler,
@ -71,19 +74,28 @@ function MonacoCodeEditor({
// Set the global declarations for the active model // Set the global declarations for the active model
// @see {@link https://microsoft.github.io/monaco-editor/typedoc/interfaces/languages.typescript.LanguageServiceDefaults.html#setExtraLibs} // @see {@link https://microsoft.github.io/monaco-editor/typedoc/interfaces/languages.typescript.LanguageServiceDefaults.html#setExtraLibs}
if (activeModel.globalDeclarations) { if (activeModel.extraLibs) {
monaco.languages.typescript.typescriptDefaults.setExtraLibs([ monaco.languages.typescript.typescriptDefaults.setExtraLibs(activeModel.extraLibs);
{
content: activeModel.globalDeclarations,
filePath: `file:///global.d.ts`,
},
]);
} }
}, [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<BeforeMount>((monaco) => { const handleEditorWillMount = useCallback<BeforeMount>((monaco) => {
// Register the new logto theme // Register the new logto theme
monaco.editor.defineTheme('logto-dark', logtoDarkTheme); monaco.editor.defineTheme('logto-dark', logtoDarkTheme);
// Set the typescript compiler options
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
allowNonTsExtensions: true,
strictNullChecks: true,
});
}, []); }, []);
const handleEditorDidMount = useCallback<OnMount>( const handleEditorDidMount = useCallback<OnMount>(

View file

@ -4,6 +4,11 @@ export type IStandaloneThemeData = Parameters<Monaco['editor']['defineTheme']>[1
export type IStandaloneCodeEditor = Parameters<OnMount>[0]; export type IStandaloneCodeEditor = Parameters<OnMount>[0];
type ExtraLibrary = {
content: string;
filePath: string;
};
export type ModelSettings = { 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} */ /** 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; name: string;
@ -19,7 +24,7 @@ export type ModelSettings = {
* @see {@link https://microsoft.github.io/monaco-editor/typedoc/interfaces/languages.typescript.LanguageServiceDefaults.html#setExtraLibs} * @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 * We use this to load the global type declarations for the active model
*/ */
globalDeclarations?: string; extraLibs?: ExtraLibrary[];
}; };
export type ModelControl = { export type ModelControl = {

View file

@ -1,16 +1,17 @@
/* Code Editor for the custom JWT claims script. */ /* Code Editor for the custom JWT claims script. */
import { LogtoJwtTokenPath } from '@logto/schemas'; import { LogtoJwtTokenPath } from '@logto/schemas';
import { useMemo, useContext, useCallback } from 'react'; 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 { useTranslation } from 'react-i18next';
import Card from '@/ds-components/Card'; import Card from '@/ds-components/Card';
import { CodeEditorLoadingContext } from './CodeEditorLoadingContext'; import { CodeEditorLoadingContext } from './CodeEditorLoadingContext';
import MonacoCodeEditor, { type ModelSettings } from './MonacoCodeEditor'; import MonacoCodeEditor, { type ModelSettings } from './MonacoCodeEditor';
import { userJwtFile, machineToMachineJwtFile } from './config';
import * as styles from './index.module.scss'; import * as styles from './index.module.scss';
import { type JwtClaimsFormType } from './type'; import { type JwtClaimsFormType } from './type';
import { accessTokenJwtCustomizerModel, clientCredentialsModel } from './utils/config';
import { buildEnvironmentVariablesTypeDefinition } from './utils/type-definitions';
const titlePhrases = Object.freeze({ const titlePhrases = Object.freeze({
[LogtoJwtTokenPath.AccessToken]: 'user_jwt', [LogtoJwtTokenPath.AccessToken]: 'user_jwt',
@ -21,12 +22,28 @@ function ScriptSection() {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { watch, control } = useFormContext<JwtClaimsFormType>(); const { watch, control } = useFormContext<JwtClaimsFormType>();
const tokenType = watch('tokenType'); 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 { setIsMonacoLoaded } = useContext(CodeEditorLoadingContext);
const activeModel = useMemo<ModelSettings>( const activeModel = useMemo<ModelSettings>(
() => (tokenType === LogtoJwtTokenPath.AccessToken ? userJwtFile : machineToMachineJwtFile), () =>
tokenType === LogtoJwtTokenPath.AccessToken
? accessTokenJwtCustomizerModel
: clientCredentialsModel,
[tokenType] [tokenType]
); );
@ -54,6 +71,7 @@ function ScriptSection() {
models={[activeModel]} models={[activeModel]}
activeModelName={activeModel.name} activeModelName={activeModel.name}
value={value} value={value}
environmentVariablesDefinition={environmentVariablesTypeDefinition}
onChange={(newValue) => { 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 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) { if (newValue === activeModel.defaultValue && !defaultValues?.script) {

View file

@ -7,13 +7,13 @@ import { useTranslation } from 'react-i18next';
import Table from '@/ds-components/Table'; import Table from '@/ds-components/Table';
import { type JwtClaimsFormType } from '../type';
import { import {
userDataDescription, userDataDescription,
tokenDataDescription, tokenDataDescription,
fetchExternalDataEditorOptions, fetchExternalDataEditorOptions,
fetchExternalDataCodeExample, fetchExternalDataCodeExample,
} from '../config'; } from '../utils/config';
import { type JwtClaimsFormType } from '../type';
import EnvironmentVariablesField from './EnvironmentVariablesField'; import EnvironmentVariablesField from './EnvironmentVariablesField';
import GuideCard, { CardType } from './GuideCard'; import GuideCard, { CardType } from './GuideCard';

View file

@ -8,12 +8,12 @@ import Button from '@/ds-components/Button';
import Card from '@/ds-components/Card'; import Card from '@/ds-components/Card';
import MonacoCodeEditor, { type ModelControl } from '../MonacoCodeEditor/index.js'; import MonacoCodeEditor, { type ModelControl } from '../MonacoCodeEditor/index.js';
import { type JwtClaimsFormType } from '../type.js';
import { import {
userTokenPayloadTestModel, userTokenPayloadTestModel,
machineToMachineTokenPayloadTestModel, machineToMachineTokenPayloadTestModel,
userTokenContextTestModel, userTokenContextTestModel,
} from '../config.js'; } from '../utils/config.js';
import { type JwtClaimsFormType } from '../type.js';
import TestResult, { type TestResultData } from './TestResult.js'; import TestResult, { type TestResultData } from './TestResult.js';
import * as styles from './index.module.scss'; import * as styles from './index.module.scss';

View file

@ -11,7 +11,7 @@ import useApi from '@/hooks/use-api';
import useSwrFetcher from '@/hooks/use-swr-fetcher'; import useSwrFetcher from '@/hooks/use-swr-fetcher';
import { shouldRetryOnError } from '@/utils/request'; import { shouldRetryOnError } from '@/utils/request';
import { getApiPath } from './utils'; import { getApiPath } from './utils/format';
function useJwtCustomizer() { function useJwtCustomizer() {
const fetchApi = useApi({ hideErrorToast: true }); const fetchApi = useApi({ hideErrorToast: true });

View file

@ -3,52 +3,40 @@ import { type EditorProps } from '@monaco-editor/react';
import TokenFileIcon from '@/assets/icons/token-file-icon.svg'; import TokenFileIcon from '@/assets/icons/token-file-icon.svg';
import UserFileIcon from '@/assets/icons/user-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 * JWT token code editor configuration
*/ */
const userJwtGlobalDeclarations = ` const accessTokenJwtCustomizerDefinition = `
declare global { declare global {
export interface CustomJwtClaims extends Record<string, any> {} export interface CustomJwtClaims extends Record<string, any> {}
/** 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 /** 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 = { export type Data = {
user: User; user: ${JwtCustomizerTypeDefinitionKey.JwtCustomizerUserContext};
} }
export interface Exports { export interface Exports {
/** /**
* This function is called to get custom claims for the JWT token. * 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 {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. * @returns The custom claims.
*/ */
getCustomJwtClaims: (token: string, data: Data) => Promise<CustomJwtClaims>; getCustomJwtClaims: (token: ${JwtCustomizerTypeDefinitionKey.AccessTokenPayload}, data: Data, envVariables: ${JwtCustomizerTypeDefinitionKey.EnvironmentVariables}) => Promise<CustomJwtClaims>;
} }
const exports: Exports; const exports: Exports;
@ -57,7 +45,7 @@ declare global {
export { exports as default }; export { exports as default };
`; `;
const machineToMachineJwtGlobalDeclarations = ` const clientCredentialsJwtCustomizerDefinition = `
declare global { declare global {
export interface CustomJwtClaims extends Record<string, any> {} export interface CustomJwtClaims extends Record<string, any> {}
@ -65,11 +53,11 @@ declare global {
/** /**
* This function is called to get custom claims for the JWT token. * 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. * @returns The custom claims.
*/ */
getCustomJwtClaims: (token: string) => Promise<CustomJwtClaims>; getCustomJwtClaims: (token: ${JwtCustomizerTypeDefinitionKey.ClientCredentialsPayload}, envVariables: ${JwtCustomizerTypeDefinitionKey.EnvironmentVariables}) => Promise<CustomJwtClaims>;
} }
const exports: Exports; const exports: Exports;
@ -78,12 +66,13 @@ declare global {
export { exports as default }; export { exports as default };
`; `;
const defaultUserJwtClaimsCode = `/** const defaultAccessTokenJwtCustomizerCode = `/**
* This function is called to get custom claims for the JWT token. * 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 {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. * @returns The custom claims.
*/ */
@ -92,10 +81,11 @@ exports.getCustomJwtClaims = async (token, data) => {
return {}; return {};
}`; }`;
const defaultMachineToMachineJwtClaimsCode = `/** const defaultClientCredentialsJwtCustomizerCode = `/**
* This function is called to get custom claims for the JWT token. * 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. * @returns The custom claims.
*/ */
@ -104,20 +94,38 @@ exports.getCustomJwtClaims = async (token) => {
return {}; return {};
}`; }`;
export const userJwtFile: ModelSettings = { export const accessTokenJwtCustomizerModel: ModelSettings = {
name: 'user-jwt.ts', name: 'user-jwt.ts',
title: 'TypeScript', title: 'TypeScript',
language: 'typescript', language: 'typescript',
defaultValue: defaultUserJwtClaimsCode, defaultValue: defaultAccessTokenJwtCustomizerCode,
globalDeclarations: userJwtGlobalDeclarations, 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', name: 'machine-to-machine-jwt.ts',
title: 'TypeScript', title: 'TypeScript',
language: 'typescript', language: 'typescript',
defaultValue: defaultMachineToMachineJwtClaimsCode, defaultValue: defaultClientCredentialsJwtCustomizerCode,
globalDeclarations: machineToMachineJwtGlobalDeclarations, extraLibs: [
{
content: clientCredentialsJwtCustomizerDefinition,
filePath: `file:///logto-jwt-customizer.d.ts`,
},
{
content: buildClientCredentialsJwtCustomizerContextTsDefinition(),
filePath: `file:///logto-jwt-customizer-context.d.ts`,
},
],
}; };
/** /**

View file

@ -4,7 +4,7 @@ import {
type ClientCredentialsJwtCustomizer, type ClientCredentialsJwtCustomizer,
} from '@logto/schemas'; } from '@logto/schemas';
import type { JwtClaimsFormType } from './type'; import type { JwtClaimsFormType } from '../type';
const formatEnvVariablesResponseToFormData = ( const formatEnvVariablesResponseToFormData = (
enVariables?: AccessTokenJwtCustomizer['envVars'] enVariables?: AccessTokenJwtCustomizer['envVars']

View file

@ -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}`;
};

View file

@ -0,0 +1,7 @@
{
"extends": "@silverhand/ts-config/tsconfig.base",
"compilerOptions": {
"outDir": "scripts-js"
},
"include": ["scripts"]
}

View file

@ -3200,6 +3200,9 @@ importers:
zod: zod:
specifier: ^3.22.4 specifier: ^3.22.4
version: 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: packages/core:
dependencies: dependencies:
@ -21483,6 +21486,16 @@ packages:
resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
engines: {node: '>=12.20'} 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: /zod@3.22.4:
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
requiresBuild: true requiresBuild: true