diff --git a/packages/connector-alipay-native/src/index.ts b/packages/connector-alipay-native/src/index.ts index baaadbd33..ebb5bc5c4 100644 --- a/packages/connector-alipay-native/src/index.ts +++ b/packages/connector-alipay-native/src/index.ts @@ -11,9 +11,10 @@ import { ConnectorError, ConnectorErrorCodes, ConnectorMetadata, + Connector, GetAuthorizationUri, GetUserInfo, - SocialConnector, + SocialConnectorInstance, GetConnectorConfig, } from '@logto/connector-types'; import { assert } from '@silverhand/essentials'; @@ -43,8 +44,21 @@ import { signingParameters } from './utils'; export type { AlipayNativeConfig } from './types'; -export default class AlipayNativeConnector implements SocialConnector { +export default class AlipayNativeConnector implements SocialConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } private readonly signingParameters = signingParameters; diff --git a/packages/connector-alipay/src/index.ts b/packages/connector-alipay/src/index.ts index a6c09e27e..cc9f966e6 100644 --- a/packages/connector-alipay/src/index.ts +++ b/packages/connector-alipay/src/index.ts @@ -9,9 +9,10 @@ import { ConnectorError, ConnectorErrorCodes, ConnectorMetadata, + Connector, GetAuthorizationUri, GetUserInfo, - SocialConnector, + SocialConnectorInstance, GetConnectorConfig, } from '@logto/connector-types'; import { assert } from '@silverhand/essentials'; @@ -43,8 +44,21 @@ import { signingParameters } from './utils'; export type { AlipayConfig } from './types'; -export default class AlipayConnector implements SocialConnector { +export default class AlipayConnector implements SocialConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } private readonly signingParameters = signingParameters; diff --git a/packages/connector-aliyun-dm/src/index.ts b/packages/connector-aliyun-dm/src/index.ts index 1fe5308c1..5bf10b50a 100644 --- a/packages/connector-aliyun-dm/src/index.ts +++ b/packages/connector-aliyun-dm/src/index.ts @@ -2,9 +2,10 @@ import { ConnectorError, ConnectorErrorCodes, ConnectorMetadata, + Connector, EmailSendMessageFunction, EmailSendTestMessageFunction, - EmailConnector, + EmailConnectorInstance, GetConnectorConfig, EmailMessageTypes, } from '@logto/connector-types'; @@ -20,8 +21,22 @@ import { sendMailErrorResponseGuard, } from './types'; -export default class AliyunDmConnector implements EmailConnector { +export default class AliyunDmConnector implements EmailConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } + constructor(public readonly getConfig: GetConnectorConfig) {} public validateConfig(config: unknown): asserts config is AliyunDmConfig { diff --git a/packages/connector-aliyun-sms/src/index.ts b/packages/connector-aliyun-sms/src/index.ts index 127037376..2556da88e 100644 --- a/packages/connector-aliyun-sms/src/index.ts +++ b/packages/connector-aliyun-sms/src/index.ts @@ -2,9 +2,10 @@ import { ConnectorError, ConnectorErrorCodes, ConnectorMetadata, + Connector, SmsSendMessageFunction, SmsSendTestMessageFunction, - SmsConnector, + SmsConnectorInstance, GetConnectorConfig, SmsMessageTypes, } from '@logto/connector-types'; @@ -15,8 +16,22 @@ import { defaultMetadata } from './constant'; import { sendSms } from './single-send-text'; import { aliyunSmsConfigGuard, AliyunSmsConfig, sendSmsResponseGuard } from './types'; -export default class AliyunSmsConnector implements SmsConnector { +export default class AliyunSmsConnector implements SmsConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } + constructor(public readonly getConfig: GetConnectorConfig) {} public validateConfig(config: unknown): asserts config is AliyunSmsConfig { diff --git a/packages/connector-apple/src/index.ts b/packages/connector-apple/src/index.ts index 7a33c565c..569d0197f 100644 --- a/packages/connector-apple/src/index.ts +++ b/packages/connector-apple/src/index.ts @@ -4,7 +4,8 @@ import { GetUserInfo, ConnectorError, ConnectorErrorCodes, - SocialConnector, + Connector, + SocialConnectorInstance, GetConnectorConfig, } from '@logto/connector-types'; import { createRemoteJWKSet, jwtVerify } from 'jose'; @@ -13,8 +14,21 @@ import { scope, defaultMetadata, jwksUri, issuer, authorizationEndpoint } from ' import { appleConfigGuard, AppleConfig, dataGuard } from './types'; // TO-DO: support nonce validation -export default class AppleConnector implements SocialConnector { +export default class AppleConnector implements SocialConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } constructor(public readonly getConfig: GetConnectorConfig) {} diff --git a/packages/connector-facebook/src/index.ts b/packages/connector-facebook/src/index.ts index fcd16b8e4..05eb70516 100644 --- a/packages/connector-facebook/src/index.ts +++ b/packages/connector-facebook/src/index.ts @@ -7,9 +7,10 @@ import { ConnectorError, ConnectorErrorCodes, ConnectorMetadata, + Connector, GetAuthorizationUri, GetUserInfo, - SocialConnector, + SocialConnectorInstance, GetConnectorConfig, codeWithRedirectDataGuard, } from '@logto/connector-types'; @@ -32,8 +33,21 @@ import { userInfoResponseGuard, } from './types'; -export default class FacebookConnector implements SocialConnector { +export default class FacebookConnector implements SocialConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } constructor(public readonly getConfig: GetConnectorConfig) {} diff --git a/packages/connector-github/src/index.ts b/packages/connector-github/src/index.ts index 6cb14a36b..6c04ea7d5 100644 --- a/packages/connector-github/src/index.ts +++ b/packages/connector-github/src/index.ts @@ -4,7 +4,8 @@ import { GetUserInfo, ConnectorError, ConnectorErrorCodes, - SocialConnector, + Connector, + SocialConnectorInstance, GetConnectorConfig, codeDataGuard, } from '@logto/connector-types'; @@ -28,8 +29,21 @@ import { userInfoResponseGuard, } from './types'; -export default class GithubConnector implements SocialConnector { +export default class GithubConnector implements SocialConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } constructor(public readonly getConfig: GetConnectorConfig) {} diff --git a/packages/connector-google/src/index.ts b/packages/connector-google/src/index.ts index 817569fe6..8533f8b8a 100644 --- a/packages/connector-google/src/index.ts +++ b/packages/connector-google/src/index.ts @@ -8,7 +8,8 @@ import { GetAuthorizationUri, GetUserInfo, ConnectorMetadata, - SocialConnector, + Connector, + SocialConnectorInstance, GetConnectorConfig, codeWithRedirectDataGuard, } from '@logto/connector-types'; @@ -30,8 +31,21 @@ import { userInfoResponseGuard, } from './types'; -export default class GoogleConnector implements SocialConnector { +export default class GoogleConnector implements SocialConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } constructor(public readonly getConfig: GetConnectorConfig) {} diff --git a/packages/connector-sendgrid-mail/src/index.ts b/packages/connector-sendgrid-mail/src/index.ts index d6e32740b..416066040 100644 --- a/packages/connector-sendgrid-mail/src/index.ts +++ b/packages/connector-sendgrid-mail/src/index.ts @@ -2,9 +2,10 @@ import { ConnectorError, ConnectorErrorCodes, ConnectorMetadata, + Connector, EmailSendMessageFunction, EmailSendTestMessageFunction, - EmailConnector, + EmailConnectorInstance, GetConnectorConfig, EmailMessageTypes, } from '@logto/connector-types'; @@ -21,8 +22,22 @@ import { PublicParameters, } from './types'; -export default class SendGridMailConnector implements EmailConnector { +export default class SendGridMailConnector implements EmailConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } + constructor(public readonly getConfig: GetConnectorConfig) {} public validateConfig(config: unknown): asserts config is SendGridMailConfig { diff --git a/packages/connector-smtp/src/index.ts b/packages/connector-smtp/src/index.ts index f1b15fe51..b4923dd78 100644 --- a/packages/connector-smtp/src/index.ts +++ b/packages/connector-smtp/src/index.ts @@ -2,9 +2,10 @@ import { ConnectorError, ConnectorErrorCodes, ConnectorMetadata, + Connector, EmailSendMessageFunction, EmailSendTestMessageFunction, - EmailConnector, + EmailConnectorInstance, GetConnectorConfig, EmailMessageTypes, } from '@logto/connector-types'; @@ -15,8 +16,21 @@ import SMTPTransport from 'nodemailer/lib/smtp-transport'; import { defaultMetadata } from './constant'; import { ContextType, smtpConfigGuard, SmtpConfig } from './types'; -export default class SmtpConnector implements EmailConnector { +export default class SmtpConnector implements EmailConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } constructor(public readonly getConfig: GetConnectorConfig) {} diff --git a/packages/connector-twilio-sms/src/index.ts b/packages/connector-twilio-sms/src/index.ts index 26ccf1100..d24c8c5cf 100644 --- a/packages/connector-twilio-sms/src/index.ts +++ b/packages/connector-twilio-sms/src/index.ts @@ -2,9 +2,10 @@ import { ConnectorError, ConnectorErrorCodes, ConnectorMetadata, + Connector, SmsSendMessageFunction, SmsSendTestMessageFunction, - SmsConnector, + SmsConnectorInstance, GetConnectorConfig, SmsMessageTypes, } from '@logto/connector-types'; @@ -14,8 +15,21 @@ import got, { HTTPError } from 'got'; import { defaultMetadata, endpoint } from './constant'; import { twilioSmsConfigGuard, TwilioSmsConfig, PublicParameters } from './types'; -export default class TwilioSmsConnector implements SmsConnector { +export default class TwilioSmsConnector implements SmsConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } constructor(public readonly getConfig: GetConnectorConfig) {} diff --git a/packages/connector-types/src/index.ts b/packages/connector-types/src/index.ts index 3a5a8e1fd..00ebf1869 100644 --- a/packages/connector-types/src/index.ts +++ b/packages/connector-types/src/index.ts @@ -2,6 +2,22 @@ import { Language } from '@logto/phrases'; import { Nullable } from '@silverhand/essentials'; import { z } from 'zod'; +/** + * Connector is auto-generated in @logto/schemas according to sql file. + * As @logto/schemas depends on this repo (@logto/connector-types), we manually define Connector type again as a temporary solution. + */ + +export const arbitraryObjectGuard = z.union([z.object({}).catchall(z.unknown()), z.object({})]); + +export type ArbitraryObject = z.infer; + +export type Connector = { + id: string; + enabled: boolean; + config: ArbitraryObject; + createdAt: number; +}; + export enum ConnectorType { Email = 'Email', SMS = 'SMS', @@ -104,16 +120,33 @@ export interface SmsConnector extends BaseConnector { sendTestMessage?: SmsSendTestMessageFunction; } +export interface SmsConnectorInstance extends SmsConnector { + connector: Connector; +} + export interface EmailConnector extends BaseConnector { sendMessage: EmailSendMessageFunction; sendTestMessage?: EmailSendTestMessageFunction; } +export interface EmailConnectorInstance extends EmailConnector { + connector: Connector; +} + export interface SocialConnector extends BaseConnector { getAuthorizationUri: GetAuthorizationUri; getUserInfo: GetUserInfo; } +export interface SocialConnectorInstance extends SocialConnector { + connector: Connector; +} + +export type ConnectorInstance = + | SmsConnectorInstance + | EmailConnectorInstance + | SocialConnectorInstance; + export type ValidateConfig = (config: unknown) => asserts config is T; export type GetAuthorizationUri = (payload: { diff --git a/packages/connector-wechat-native/src/index.ts b/packages/connector-wechat-native/src/index.ts index bf50213f8..d306cfbb7 100644 --- a/packages/connector-wechat-native/src/index.ts +++ b/packages/connector-wechat-native/src/index.ts @@ -9,7 +9,8 @@ import { GetUserInfo, ConnectorError, ConnectorErrorCodes, - SocialConnector, + Connector, + SocialConnectorInstance, GetConnectorConfig, codeDataGuard, } from '@logto/connector-types'; @@ -34,8 +35,21 @@ import { WechatNativeConfig, } from './types'; -export default class WechatNativeConnector implements SocialConnector { +export default class WechatNativeConnector implements SocialConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } constructor(public readonly getConfig: GetConnectorConfig) {} diff --git a/packages/connector-wechat/src/index.ts b/packages/connector-wechat/src/index.ts index 63b597c48..7a0b1b946 100644 --- a/packages/connector-wechat/src/index.ts +++ b/packages/connector-wechat/src/index.ts @@ -9,7 +9,8 @@ import { GetUserInfo, ConnectorError, ConnectorErrorCodes, - SocialConnector, + Connector, + SocialConnectorInstance, GetConnectorConfig, codeDataGuard, } from '@logto/connector-types'; @@ -35,8 +36,21 @@ import { WechatConfig, } from './types'; -export default class WechatConnector implements SocialConnector { +export default class WechatConnector implements SocialConnectorInstance { public metadata: ConnectorMetadata = defaultMetadata; + private _connector?: Connector; + + public get connector() { + if (!this._connector) { + throw new ConnectorError(ConnectorErrorCodes.General); + } + + return this._connector; + } + + public set connector(input: Connector) { + this._connector = input; + } constructor(public readonly getConfig: GetConnectorConfig) {} diff --git a/packages/core/src/connectors/index.ts b/packages/core/src/connectors/index.ts index 3ebfbd1b8..11d7cf4ab 100644 --- a/packages/core/src/connectors/index.ts +++ b/packages/core/src/connectors/index.ts @@ -1,17 +1,18 @@ import { existsSync, readFileSync } from 'fs'; import path from 'path'; +import { ConnectorInstance, SocialConnectorInstance } from '@logto/connector-types'; import resolvePackagePath from 'resolve-package-path'; import RequestError from '@/errors/RequestError'; import { findAllConnectors, insertConnector } from '@/queries/connector'; import { connectorPackages } from './consts'; -import { ConnectorInstance, ConnectorType, IConnector, SocialConnectorInstance } from './types'; +import { ConnectorType } from './types'; import { getConnectorConfig } from './utilities'; // eslint-disable-next-line @silverhand/fp/no-let -let cachedConnectors: IConnector[] | undefined; +let cachedConnectors: ConnectorInstance[] | undefined; const loadConnectors = async () => { if (cachedConnectors) { @@ -23,8 +24,8 @@ const loadConnectors = async () => { connectorPackages.map(async (packageName) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const { default: Builder } = await import(packageName); - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - const instance = new Builder(getConnectorConfig) as IConnector; + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment + const instance: ConnectorInstance = new Builder(getConnectorConfig); // eslint-disable-next-line unicorn/prefer-module const packagePath = resolvePackagePath(packageName, __dirname); @@ -95,7 +96,10 @@ export const getConnectorInstances = async (): Promise => { throw new RequestError({ code: 'entity.not_found', id, status: 404 }); } - return { connector, ...element }; + // eslint-disable-next-line @silverhand/fp/no-mutation + element.connector = connector; + + return element; }); }; diff --git a/packages/core/src/connectors/types.ts b/packages/core/src/connectors/types.ts index a164ae49e..5d18a1270 100644 --- a/packages/core/src/connectors/types.ts +++ b/packages/core/src/connectors/types.ts @@ -1,23 +1,9 @@ -import { SmsConnector, EmailConnector, SocialConnector } from '@logto/connector-types'; -import { Connector, PasscodeType } from '@logto/schemas'; +import { PasscodeType } from '@logto/schemas'; import { z } from 'zod'; export { ConnectorType } from '@logto/schemas'; export type { ConnectorMetadata } from '@logto/schemas'; -// The name `Connector` is used for database, use `ConnectorInstance` to avoid confusing. -export type IConnector = SmsConnector | EmailConnector | SocialConnector; -export type ConnectorInstance = - | SmsConnectorInstance - | EmailConnectorInstance - | SocialConnectorInstance; - -export type SmsConnectorInstance = SmsConnector & { connector: Connector }; - -export type EmailConnectorInstance = EmailConnector & { connector: Connector }; - -export type SocialConnectorInstance = SocialConnector & { connector: Connector }; - export type TemplateType = PasscodeType | 'Test'; export const socialUserInfoGuard = z.object({ diff --git a/packages/core/src/lib/passcode.ts b/packages/core/src/lib/passcode.ts index 0970fc5d5..4f6d168b9 100644 --- a/packages/core/src/lib/passcode.ts +++ b/packages/core/src/lib/passcode.ts @@ -1,8 +1,9 @@ +import { EmailConnectorInstance, SmsConnectorInstance } from '@logto/connector-types'; import { Passcode, PasscodeType } from '@logto/schemas'; import { customAlphabet, nanoid } from 'nanoid'; import { getConnectorInstances } from '@/connectors'; -import { ConnectorType, EmailConnectorInstance, SmsConnectorInstance } from '@/connectors/types'; +import { ConnectorType } from '@/connectors/types'; import RequestError from '@/errors/RequestError'; import { consumePasscode, diff --git a/packages/core/src/lib/sign-in-experience.test.ts b/packages/core/src/lib/sign-in-experience.test.ts index 9fd1ba573..b1a64b8ca 100644 --- a/packages/core/src/lib/sign-in-experience.test.ts +++ b/packages/core/src/lib/sign-in-experience.test.ts @@ -1,3 +1,4 @@ +import { ConnectorInstance } from '@logto/connector-types'; import { BrandingStyle, SignInMethodState, ConnectorType } from '@logto/schemas'; import { @@ -7,7 +8,6 @@ import { mockBranding, mockSignInMethods, } from '@/__mocks__'; -import { ConnectorInstance } from '@/connectors/types'; import RequestError from '@/errors/RequestError'; import { isEnabled, diff --git a/packages/core/src/lib/sign-in-experience.ts b/packages/core/src/lib/sign-in-experience.ts index 1631ab7ca..b3af68020 100644 --- a/packages/core/src/lib/sign-in-experience.ts +++ b/packages/core/src/lib/sign-in-experience.ts @@ -1,3 +1,4 @@ +import { ConnectorInstance } from '@logto/connector-types'; import { Branding, BrandingStyle, @@ -7,7 +8,7 @@ import { } from '@logto/schemas'; import { Optional } from '@silverhand/essentials'; -import { ConnectorInstance, ConnectorType } from '@/connectors/types'; +import { ConnectorType } from '@/connectors/types'; import RequestError from '@/errors/RequestError'; import assertThat from '@/utils/assert-that'; diff --git a/packages/core/src/routes/connector.test.ts b/packages/core/src/routes/connector.test.ts index 2d4830fac..2cf95fbca 100644 --- a/packages/core/src/routes/connector.test.ts +++ b/packages/core/src/routes/connector.test.ts @@ -1,12 +1,12 @@ -import { ValidateConfig } from '@logto/connector-types'; +import { + ValidateConfig, + EmailConnectorInstance, + SmsConnectorInstance, +} from '@logto/connector-types'; import { Connector, ConnectorType } from '@logto/schemas'; import { mockConnectorInstanceList, mockMetadata, mockConnector } from '@/__mocks__'; -import { - ConnectorMetadata, - EmailConnectorInstance, - SmsConnectorInstance, -} from '@/connectors/types'; +import { ConnectorMetadata } from '@/connectors/types'; import RequestError from '@/errors/RequestError'; import assertThat from '@/utils/assert-that'; import { createRequester } from '@/utils/test-utils'; diff --git a/packages/core/src/routes/connector.ts b/packages/core/src/routes/connector.ts index a1e0c9159..f96dfc456 100644 --- a/packages/core/src/routes/connector.ts +++ b/packages/core/src/routes/connector.ts @@ -1,14 +1,14 @@ -import { ValidateConfig } from '@logto/connector-types'; +import { + ValidateConfig, + ConnectorInstance, + EmailConnectorInstance, + SmsConnectorInstance, +} from '@logto/connector-types'; import { arbitraryObjectGuard, ConnectorDto, Connectors, ConnectorType } from '@logto/schemas'; import { emailRegEx, phoneRegEx } from '@logto/shared'; import { object, string } from 'zod'; import { getConnectorInstances, getConnectorInstanceById } from '@/connectors'; -import { - ConnectorInstance, - EmailConnectorInstance, - SmsConnectorInstance, -} from '@/connectors/types'; import RequestError from '@/errors/RequestError'; import koaGuard from '@/middleware/koa-guard'; import { updateConnector } from '@/queries/connector';