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