0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-24 22:41:28 -05:00

fix(connector): refactor ConnectorInstance as class (#1541)

This commit is contained in:
Darcy Ye 2022-07-14 15:56:57 +08:00 committed by GitHub
parent 9bdd80ebcc
commit 6b9ad580ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 271 additions and 61 deletions

View file

@ -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<AlipayNativeConfig> {
export default class AlipayNativeConnector implements SocialConnectorInstance<AlipayNativeConfig> {
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;

View file

@ -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<AlipayConfig> {
export default class AlipayConnector implements SocialConnectorInstance<AlipayConfig> {
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;

View file

@ -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<AliyunDmConfig> {
export default class AliyunDmConnector implements EmailConnectorInstance<AliyunDmConfig> {
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 {

View file

@ -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<AliyunSmsConfig> {
export default class AliyunSmsConnector implements SmsConnectorInstance<AliyunSmsConfig> {
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 {

View file

@ -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<AppleConfig> {
export default class AppleConnector implements SocialConnectorInstance<AppleConfig> {
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) {}

View file

@ -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<FacebookConfig> {
export default class FacebookConnector implements SocialConnectorInstance<FacebookConfig> {
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) {}

View file

@ -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<GithubConfig> {
export default class GithubConnector implements SocialConnectorInstance<GithubConfig> {
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) {}

View file

@ -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<GoogleConfig> {
export default class GoogleConnector implements SocialConnectorInstance<GoogleConfig> {
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) {}

View file

@ -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<SendGridMailConfig> {
export default class SendGridMailConnector implements EmailConnectorInstance<SendGridMailConfig> {
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 {

View file

@ -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<SmtpConfig> {
export default class SmtpConnector implements EmailConnectorInstance<SmtpConfig> {
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) {}

View file

@ -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<TwilioSmsConfig> {
export default class TwilioSmsConnector implements SmsConnectorInstance<TwilioSmsConfig> {
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) {}

View file

@ -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<typeof arbitraryObjectGuard>;
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<T = unknown> extends BaseConnector<T> {
sendTestMessage?: SmsSendTestMessageFunction;
}
export interface SmsConnectorInstance<T = unknown> extends SmsConnector<T> {
connector: Connector;
}
export interface EmailConnector<T = unknown> extends BaseConnector<T> {
sendMessage: EmailSendMessageFunction;
sendTestMessage?: EmailSendTestMessageFunction;
}
export interface EmailConnectorInstance<T = unknown> extends EmailConnector<T> {
connector: Connector;
}
export interface SocialConnector<T = unknown> extends BaseConnector<T> {
getAuthorizationUri: GetAuthorizationUri;
getUserInfo: GetUserInfo;
}
export interface SocialConnectorInstance<T = unknown> extends SocialConnector<T> {
connector: Connector;
}
export type ConnectorInstance =
| SmsConnectorInstance
| EmailConnectorInstance
| SocialConnectorInstance;
export type ValidateConfig<T = unknown> = (config: unknown) => asserts config is T;
export type GetAuthorizationUri = (payload: {

View file

@ -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<WechatNativeConfig> {
export default class WechatNativeConnector implements SocialConnectorInstance<WechatNativeConfig> {
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) {}

View file

@ -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<WechatConfig> {
export default class WechatConnector implements SocialConnectorInstance<WechatConfig> {
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) {}

View file

@ -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<ConnectorInstance[]> => {
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;
});
};

View file

@ -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({

View file

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

View file

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

View file

@ -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';

View file

@ -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';

View file

@ -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';