0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-30 20:33:54 -05:00

refactor(connector): fix app boot

This commit is contained in:
Darcy Ye 2022-08-18 15:56:46 +08:00
parent 05ae6e532e
commit b076ba4bc9
No known key found for this signature in database
GPG key ID: B46F4C07EDEFC610
24 changed files with 177 additions and 75 deletions

View file

@ -14,6 +14,8 @@ import { assert } from '@silverhand/essentials';
import { defaultMetadata } from './constant'; import { defaultMetadata } from './constant';
import { mockMailConfigGuard, MockMailConfig } from './types'; import { mockMailConfigGuard, MockMailConfig } from './types';
export { defaultMetadata } from './constant';
export default class MockMailConnector extends EmailConnector<MockMailConfig> { export default class MockMailConnector extends EmailConnector<MockMailConfig> {
constructor(getConnectorConfig: GetConnectorConfig) { constructor(getConnectorConfig: GetConnectorConfig) {
super(getConnectorConfig); super(getConnectorConfig);

View file

@ -14,6 +14,8 @@ import { assert } from '@silverhand/essentials';
import { defaultMetadata } from './constant'; import { defaultMetadata } from './constant';
import { mockSmsConfigGuard, MockSmsConfig } from './types'; import { mockSmsConfigGuard, MockSmsConfig } from './types';
export { defaultMetadata } from './constant';
export default class MockSmsConnector extends SmsConnector<MockSmsConfig> { export default class MockSmsConnector extends SmsConnector<MockSmsConfig> {
constructor(getConnectorConfig: GetConnectorConfig) { constructor(getConnectorConfig: GetConnectorConfig) {
super(getConnectorConfig); super(getConnectorConfig);

View file

@ -14,6 +14,8 @@ import { z } from 'zod';
import { defaultMetadata } from './constant'; import { defaultMetadata } from './constant';
import { mockSocialConfigGuard, MockSocialConfig } from './types'; import { mockSocialConfigGuard, MockSocialConfig } from './types';
export { defaultMetadata } from './constant';
export default class MockSocialConnector extends SocialConnector<MockSocialConfig> { export default class MockSocialConnector extends SocialConnector<MockSocialConfig> {
constructor(getConnectorConfig: GetConnectorConfig) { constructor(getConnectorConfig: GetConnectorConfig) {
super(getConnectorConfig); super(getConnectorConfig);

View file

@ -19,6 +19,8 @@ import {
PublicParameters, PublicParameters,
} from './types'; } from './types';
export { defaultMetadata } from './constant';
export default class SendGridMailConnector extends EmailConnector<SendGridMailConfig> { export default class SendGridMailConnector extends EmailConnector<SendGridMailConfig> {
constructor(getConnectorConfig: GetConnectorConfig) { constructor(getConnectorConfig: GetConnectorConfig) {
super(getConnectorConfig); super(getConnectorConfig);

View file

@ -13,6 +13,8 @@ import SMTPTransport from 'nodemailer/lib/smtp-transport';
import { defaultMetadata } from './constant'; import { defaultMetadata } from './constant';
import { ContextType, smtpConfigGuard, SmtpConfig } from './types'; import { ContextType, smtpConfigGuard, SmtpConfig } from './types';
export { defaultMetadata } from './constant';
export default class SmtpConnector extends EmailConnector<SmtpConfig> { export default class SmtpConnector extends EmailConnector<SmtpConfig> {
constructor(getConnectorConfig: GetConnectorConfig) { constructor(getConnectorConfig: GetConnectorConfig) {
super(getConnectorConfig); super(getConnectorConfig);

View file

@ -12,6 +12,8 @@ import got, { HTTPError } from 'got';
import { defaultMetadata, endpoint } from './constant'; import { defaultMetadata, endpoint } from './constant';
import { twilioSmsConfigGuard, TwilioSmsConfig, PublicParameters } from './types'; import { twilioSmsConfigGuard, TwilioSmsConfig, PublicParameters } from './types';
export { defaultMetadata } from './constant';
export default class TwilioSmsConnector extends SmsConnector<TwilioSmsConfig> { export default class TwilioSmsConnector extends SmsConnector<TwilioSmsConfig> {
constructor(getConnectorConfig: GetConnectorConfig) { constructor(getConnectorConfig: GetConnectorConfig) {
super(getConnectorConfig); super(getConnectorConfig);

View file

@ -36,6 +36,8 @@ import {
AuthResponse, AuthResponse,
} from './types'; } from './types';
export { defaultMetadata } from './constant';
export default class WechatNativeConnector extends SocialConnector<WechatNativeConfig> { export default class WechatNativeConnector extends SocialConnector<WechatNativeConfig> {
constructor(getConnectorConfig: GetConnectorConfig) { constructor(getConnectorConfig: GetConnectorConfig) {
super(getConnectorConfig); super(getConnectorConfig);

View file

@ -37,6 +37,8 @@ import {
AuthResponse, AuthResponse,
} from './types'; } from './types';
export { defaultMetadata } from './constant';
export default class WechatConnector extends SocialConnector<WechatConfig> { export default class WechatConnector extends SocialConnector<WechatConfig> {
constructor(getConnectorConfig: GetConnectorConfig) { constructor(getConnectorConfig: GetConnectorConfig) {
super(getConnectorConfig); super(getConnectorConfig);

View file

@ -28,10 +28,10 @@
"@logto/connector-facebook": "^1.0.0-beta.5", "@logto/connector-facebook": "^1.0.0-beta.5",
"@logto/connector-github": "^1.0.0-beta.5", "@logto/connector-github": "^1.0.0-beta.5",
"@logto/connector-google": "^1.0.0-beta.5", "@logto/connector-google": "^1.0.0-beta.5",
"@logto/connector-schemas": "^1.0.0-beta.5",
"@logto/connector-sendgrid-email": "^1.0.0-beta.5", "@logto/connector-sendgrid-email": "^1.0.0-beta.5",
"@logto/connector-smtp": "^1.0.0-beta.5", "@logto/connector-smtp": "^1.0.0-beta.5",
"@logto/connector-twilio-sms": "^1.0.0-beta.5", "@logto/connector-twilio-sms": "^1.0.0-beta.5",
"@logto/connector-types": "^1.0.0-beta.5",
"@logto/connector-wechat-native": "^1.0.0-beta.5", "@logto/connector-wechat-native": "^1.0.0-beta.5",
"@logto/connector-wechat-web": "^1.0.0-beta.5", "@logto/connector-wechat-web": "^1.0.0-beta.5",
"@logto/phrases": "^1.0.0-beta.5", "@logto/phrases": "^1.0.0-beta.5",

View file

@ -1,4 +1,4 @@
import { ConnectorPlatform } from '@logto/connector-types'; import { ConnectorPlatform } from '@logto/connector-schemas';
import { Connector, ConnectorMetadata, ConnectorType } from '@logto/schemas'; import { Connector, ConnectorMetadata, ConnectorType } from '@logto/schemas';
export const mockMetadata: ConnectorMetadata = { export const mockMetadata: ConnectorMetadata = {

View file

@ -1,4 +1,4 @@
import { ConnectorPlatform } from '@logto/connector-types'; import { ConnectorPlatform } from '@logto/connector-schemas';
import { Connector } from '@logto/schemas'; import { Connector } from '@logto/schemas';
import { import {

View file

@ -1,7 +1,8 @@
import { existsSync, readFileSync } from 'fs'; import { existsSync, readFileSync } from 'fs';
import path from 'path'; import path from 'path';
import { ConnectorInstance, SocialConnectorInstance } from '@logto/connector-types'; import { GetConnectorConfig } from '@logto/connector-schemas';
import { Connector } from '@logto/schemas/lib/db-entries';
import resolvePackagePath from 'resolve-package-path'; import resolvePackagePath from 'resolve-package-path';
import envSet from '@/env-set'; import envSet from '@/env-set';
@ -9,17 +10,30 @@ import RequestError from '@/errors/RequestError';
import { findAllConnectors, insertConnector } from '@/queries/connector'; import { findAllConnectors, insertConnector } from '@/queries/connector';
import { defaultConnectorPackages } from './consts'; import { defaultConnectorPackages } from './consts';
import { ConnectorType } from './types'; import { ConnectorInstance, SocialConnectorInstance, ConnectorType } from './types';
import { getConnectorConfig } from './utilities'; import { getConnectorConfig } from './utilities';
// eslint-disable-next-line @silverhand/fp/no-let // eslint-disable-next-line @silverhand/fp/no-let
let cachedConnectors: ConnectorInstance[] | undefined; let cachedConnectorInstances: ConnectorInstance[] | undefined;
const loadConnectors = async () => { export const getConnectorInstances = async (): Promise<ConnectorInstance[]> => {
if (cachedConnectors) { const connectors = await findAllConnectors();
return cachedConnectors; const connectorMap = new Map(connectors.map((connector) => [connector.id, connector]));
if (cachedConnectorInstances) {
return cachedConnectorInstances.map((connectorInstance) => {
const { id } = connectorInstance.metadata;
const connector = connectorMap.get(id);
if (!connector) {
throw new RequestError({ code: 'entity.not_found', id, status: 404 });
}
// eslint-disable-next-line @silverhand/fp/no-mutation
connectorInstance.connector = connector;
return connectorInstance;
});
} }
const { const {
values: { additionalConnectorPackages }, values: { additionalConnectorPackages },
} = envSet; } = envSet;
@ -27,12 +41,30 @@ const loadConnectors = async () => {
const connectorPackages = [...defaultConnectorPackages, ...additionalConnectorPackages]; const connectorPackages = [...defaultConnectorPackages, ...additionalConnectorPackages];
// eslint-disable-next-line @silverhand/fp/no-mutation // eslint-disable-next-line @silverhand/fp/no-mutation
cachedConnectors = await Promise.all( cachedConnectorInstances = await Promise.all(
connectorPackages.map(async (packageName) => { connectorPackages.map(async (packageName) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const { default: Builder } = await import(packageName); const { default: Builder, defaultMetadata: metadata } = await import(packageName);
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment class InstanceBuilder extends Builder {
const instance: ConnectorInstance = new Builder(getConnectorConfig); public connector: Connector;
constructor(getConnectorConfig: GetConnectorConfig, connector: Connector) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
super(getConnectorConfig);
this.connector = connector;
}
}
const connector = connectorMap.get(metadata.id);
if (!connector) {
throw new RequestError({ code: 'entity.not_found', id: metadata.id, status: 404 });
}
// eslint-disable-next-line no-restricted-syntax
const instance: ConnectorInstance = new InstanceBuilder(
getConnectorConfig,
connector
) as ConnectorInstance;
// eslint-disable-next-line unicorn/prefer-module // eslint-disable-next-line unicorn/prefer-module
const packagePath = resolvePackagePath(packageName, __dirname); const packagePath = resolvePackagePath(packageName, __dirname);
@ -86,29 +118,29 @@ const loadConnectors = async () => {
}) })
); );
return cachedConnectors; return cachedConnectorInstances;
}; };
export const getConnectorInstances = async (): Promise<ConnectorInstance[]> => { // Export const getConnectorInstances = async (): Promise<ConnectorInstance[]> => {
const connectors = await findAllConnectors(); // const connectors = await findAllConnectors();
const connectorMap = new Map(connectors.map((connector) => [connector.id, connector])); // const connectorMap = new Map(connectors.map((connector) => [connector.id, connector]));
const allConnectors = await loadConnectors(); // const allConnectors = await loadConnectors();
return allConnectors.map((element) => { // return allConnectors.map((element) => {
const { id } = element.metadata; // const { id } = element.metadata;
const connector = connectorMap.get(id); // const connector = connectorMap.get(id);
if (!connector) { // if (!connector) {
throw new RequestError({ code: 'entity.not_found', id, status: 404 }); // throw new RequestError({ code: 'entity.not_found', id, status: 404 });
} // }
// eslint-disable-next-line @silverhand/fp/no-mutation // // eslint-disable-next-line @silverhand/fp/no-mutation
element.connector = connector; // element.connector = connector;
return element; // return element;
}); // });
}; // };
export const getConnectorInstanceById = async (id: string): Promise<ConnectorInstance> => { export const getConnectorInstanceById = async (id: string): Promise<ConnectorInstance> => {
const connectorInstances = await getConnectorInstances(); const connectorInstances = await getConnectorInstances();
@ -150,8 +182,8 @@ export const getSocialConnectorInstanceById = async (
export const initConnectors = async () => { export const initConnectors = async () => {
const connectors = await findAllConnectors(); const connectors = await findAllConnectors();
const existingConnectors = new Map(connectors.map((connector) => [connector.id, connector])); const existingConnectors = new Map(connectors.map((connector) => [connector.id, connector]));
const allConnectors = await loadConnectors(); const allConnectorInstances = await getConnectorInstances();
const newConnectors = allConnectors.filter(({ metadata: { id } }) => { const newConnectors = allConnectorInstances.filter(({ metadata: { id } }) => {
const connector = existingConnectors.get(id); const connector = existingConnectors.get(id);
if (!connector) { if (!connector) {

View file

@ -1,8 +1,17 @@
import { PasscodeType } from '@logto/schemas'; import {
BaseConnector,
SmsConnector,
EmailConnector,
SocialConnector,
ConnectorType,
ConnectorError,
ConnectorErrorCodes,
} from '@logto/connector-schemas';
import { Connector, PasscodeType } from '@logto/schemas';
import { z } from 'zod'; import { z } from 'zod';
export { ConnectorType } from '@logto/schemas'; export { ConnectorType } from '@logto/connector-schemas';
export type { ConnectorMetadata } from '@logto/schemas'; export type { ConnectorMetadata } from '@logto/connector-schemas';
export type TemplateType = PasscodeType | 'Test'; export type TemplateType = PasscodeType | 'Test';
@ -15,3 +24,43 @@ export const socialUserInfoGuard = z.object({
}); });
export type SocialUserInfo = z.infer<typeof socialUserInfoGuard>; export type SocialUserInfo = z.infer<typeof socialUserInfoGuard>;
export class SmsConnectorInstance<T = unknown> extends SmsConnector<T> {
public connector!: Connector;
}
export class EmailConnectorInstance<T = unknown> extends EmailConnector<T> {
public connector!: Connector;
}
export class SocialConnectorInstance<T = unknown> extends SocialConnector<T> {
public connector!: Connector;
}
export class ConnectorInstance<T = unknown> extends BaseConnector<T> {
public connector!: Connector;
}
export const isSmsConnectorInstance = (
instance: unknown
): asserts instance is SmsConnectorInstance => {
if (!(instance instanceof ConnectorInstance && instance.metadata.type === ConnectorType.SMS)) {
throw new ConnectorError(ConnectorErrorCodes.General);
}
};
export const isEmailConnectorInstance = (
instance: unknown
): asserts instance is EmailConnectorInstance => {
if (!(instance instanceof ConnectorInstance && instance.metadata.type === ConnectorType.Email)) {
throw new ConnectorError(ConnectorErrorCodes.General);
}
};
export const isSocialConnectorInstance = (
instance: unknown
): asserts instance is SocialConnectorInstance => {
if (!(instance instanceof ConnectorInstance && instance.metadata.type === ConnectorType.Social)) {
throw new ConnectorError(ConnectorErrorCodes.General);
}
};

View file

@ -1,8 +1,8 @@
import { ConnectorType } from '@logto/connector-types'; import { ConnectorMetadata, ConnectorType, ValidateConfig } from '@logto/connector-schemas';
import { Passcode, PasscodeType } from '@logto/schemas'; import { Connector, Passcode, PasscodeType } from '@logto/schemas';
import { mockConnector, mockMetadata } from '@/__mocks__'; import { mockConnector, mockMetadata } from '@/__mocks__';
import { getConnectorInstances } from '@/connectors'; // Import { getConnectorInstances } from '@/connectors';
import RequestError from '@/errors/RequestError'; import RequestError from '@/errors/RequestError';
import { import {
consumePasscode, consumePasscode,
@ -22,8 +22,22 @@ import {
verifyPasscode, verifyPasscode,
} from './passcode'; } from './passcode';
type ConnectorInstance = {
connector: Connector;
metadata: ConnectorMetadata;
validateConfig?: ValidateConfig<unknown>;
sendMessage?: unknown;
};
const getConnectorInstancesPlaceHolder = jest.fn() as jest.MockedFunction<
() => Promise<ConnectorInstance[]>
>;
jest.mock('@/queries/passcode'); jest.mock('@/queries/passcode');
jest.mock('@/connectors'); jest.mock('@/connectors', () => ({
...jest.requireActual('@/queries/connector'),
getConnectorInstances: async () => getConnectorInstancesPlaceHolder(),
}));
const mockedFindUnconsumedPasscodesByJtiAndType = const mockedFindUnconsumedPasscodesByJtiAndType =
findUnconsumedPasscodesByJtiAndType as jest.MockedFunction< findUnconsumedPasscodesByJtiAndType as jest.MockedFunction<
@ -37,9 +51,9 @@ const mockedDeletePasscodesByIds = deletePasscodesByIds as jest.MockedFunction<
typeof deletePasscodesByIds typeof deletePasscodesByIds
>; >;
const mockedInsertPasscode = insertPasscode as jest.MockedFunction<typeof insertPasscode>; const mockedInsertPasscode = insertPasscode as jest.MockedFunction<typeof insertPasscode>;
const mockedGetConnectorInstances = getConnectorInstances as jest.MockedFunction< // Const mockedGetConnectorInstances = getConnectorInstances as jest.MockedFunction<
typeof getConnectorInstances // typeof getConnectorInstances
>; // >;
const mockedConsumePasscode = consumePasscode as jest.MockedFunction<typeof consumePasscode>; const mockedConsumePasscode = consumePasscode as jest.MockedFunction<typeof consumePasscode>;
const mockedIncreasePasscodeTryCount = increasePasscodeTryCount as jest.MockedFunction< const mockedIncreasePasscodeTryCount = increasePasscodeTryCount as jest.MockedFunction<
typeof increasePasscodeTryCount typeof increasePasscodeTryCount
@ -126,8 +140,7 @@ describe('sendPasscode', () => {
it('should throw error when email or sms connector can not be found', async () => { it('should throw error when email or sms connector can not be found', async () => {
const sendMessage = jest.fn(); const sendMessage = jest.fn();
const validateConfig = jest.fn(); const validateConfig = jest.fn();
const getConfig = jest.fn(); getConnectorInstancesPlaceHolder.mockResolvedValueOnce([
mockedGetConnectorInstances.mockResolvedValueOnce([
{ {
connector: { connector: {
...mockConnector, ...mockConnector,
@ -140,7 +153,6 @@ describe('sendPasscode', () => {
}, },
sendMessage, sendMessage,
validateConfig, validateConfig,
getConfig,
}, },
]); ]);
const passcode: Passcode = { const passcode: Passcode = {
@ -165,8 +177,7 @@ describe('sendPasscode', () => {
it('should call sendPasscode with params matching', async () => { it('should call sendPasscode with params matching', async () => {
const sendMessage = jest.fn(); const sendMessage = jest.fn();
const validateConfig = jest.fn(); const validateConfig = jest.fn();
const getConfig = jest.fn(); getConnectorInstancesPlaceHolder.mockResolvedValueOnce([
mockedGetConnectorInstances.mockResolvedValueOnce([
{ {
connector: { connector: {
...mockConnector, ...mockConnector,
@ -179,7 +190,6 @@ describe('sendPasscode', () => {
}, },
sendMessage, sendMessage,
validateConfig, validateConfig,
getConfig,
}, },
{ {
connector: { connector: {
@ -193,7 +203,6 @@ describe('sendPasscode', () => {
}, },
sendMessage, sendMessage,
validateConfig, validateConfig,
getConfig,
}, },
]); ]);
const passcode: Passcode = { const passcode: Passcode = {

View file

@ -1,9 +1,8 @@
import { EmailConnectorInstance, SmsConnectorInstance } from '@logto/connector-types';
import { Passcode, PasscodeType } from '@logto/schemas'; import { Passcode, PasscodeType } from '@logto/schemas';
import { customAlphabet, nanoid } from 'nanoid'; import { customAlphabet, nanoid } from 'nanoid';
import { getConnectorInstances } from '@/connectors'; import { getConnectorInstances } from '@/connectors';
import { ConnectorType } from '@/connectors/types'; import { ConnectorType, EmailConnectorInstance, SmsConnectorInstance } from '@/connectors/types';
import RequestError from '@/errors/RequestError'; import RequestError from '@/errors/RequestError';
import { import {
consumePasscode, consumePasscode,

View file

@ -1,4 +1,3 @@
import { ConnectorInstance } from '@logto/connector-types';
import { BrandingStyle, SignInMethodState, ConnectorType } from '@logto/schemas'; import { BrandingStyle, SignInMethodState, ConnectorType } from '@logto/schemas';
import { import {
@ -8,6 +7,7 @@ import {
mockBranding, mockBranding,
mockSignInMethods, mockSignInMethods,
} from '@/__mocks__'; } from '@/__mocks__';
import { ConnectorInstance } from '@/connectors/types';
import RequestError from '@/errors/RequestError'; import RequestError from '@/errors/RequestError';
import { import {
isEnabled, isEnabled,

View file

@ -1,4 +1,3 @@
import { ConnectorInstance } from '@logto/connector-types';
import { import {
Branding, Branding,
BrandingStyle, BrandingStyle,
@ -8,7 +7,7 @@ import {
} from '@logto/schemas'; } from '@logto/schemas';
import { Optional } from '@silverhand/essentials'; import { Optional } from '@silverhand/essentials';
import { ConnectorType } from '@/connectors/types'; import { ConnectorInstance, ConnectorType } from '@/connectors/types';
import RequestError from '@/errors/RequestError'; import RequestError from '@/errors/RequestError';
import assertThat from '@/utils/assert-that'; import assertThat from '@/utils/assert-that';

View file

@ -1,4 +1,4 @@
import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-types'; import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-schemas';
import RequestError from '@/errors/RequestError'; import RequestError from '@/errors/RequestError';
import { createContextWithRouteParameters } from '@/utils/test-utils'; import { createContextWithRouteParameters } from '@/utils/test-utils';

View file

@ -1,4 +1,4 @@
import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-types'; import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-schemas';
import { conditional } from '@silverhand/essentials'; import { conditional } from '@silverhand/essentials';
import { Middleware } from 'koa'; import { Middleware } from 'koa';
import { z } from 'zod'; import { z } from 'zod';

View file

@ -1,8 +1,4 @@
import { import { ValidateConfig } from '@logto/connector-schemas';
ValidateConfig,
EmailConnectorInstance,
SmsConnectorInstance,
} from '@logto/connector-types';
import { Connector, ConnectorType } from '@logto/schemas'; import { Connector, ConnectorType } from '@logto/schemas';
import { mockConnectorInstanceList, mockMetadata, mockConnector } from '@/__mocks__'; import { mockConnectorInstanceList, mockMetadata, mockConnector } from '@/__mocks__';
@ -16,7 +12,7 @@ import connectorRoutes from './connector';
type ConnectorInstance = { type ConnectorInstance = {
connector: Connector; connector: Connector;
metadata: ConnectorMetadata; metadata: ConnectorMetadata;
validateConfig?: ValidateConfig; validateConfig?: ValidateConfig<unknown>;
sendMessage?: unknown; sendMessage?: unknown;
}; };
@ -111,12 +107,13 @@ describe('connector route', () => {
...mockMetadata, ...mockMetadata,
type: ConnectorType.SMS, type: ConnectorType.SMS,
}; };
const mockedSmsConnectorInstance: SmsConnectorInstance = { const mockedSmsConnectorInstance = {
connector: mockConnector, connector: mockConnector,
metadata: mockedMetadata, metadata: mockedMetadata,
validateConfig: jest.fn(), validateConfig: jest.fn(),
getConfig: jest.fn(), getConfig: jest.fn(),
sendMessage: jest.fn(), sendMessage: jest.fn(),
sendMessageBy: jest.fn(),
sendTestMessage: jest.fn(), sendTestMessage: jest.fn(),
}; };
getConnectorInstancesPlaceHolder.mockResolvedValueOnce([mockedSmsConnectorInstance]); getConnectorInstancesPlaceHolder.mockResolvedValueOnce([mockedSmsConnectorInstance]);
@ -132,12 +129,13 @@ describe('connector route', () => {
}); });
it('should get email connector and send test message', async () => { it('should get email connector and send test message', async () => {
const mockedEmailConnector: EmailConnectorInstance = { const mockedEmailConnector = {
connector: mockConnector, connector: mockConnector,
metadata: mockMetadata, metadata: mockMetadata,
validateConfig: jest.fn(), validateConfig: jest.fn(),
getConfig: jest.fn(), getConfig: jest.fn(),
sendMessage: jest.fn(), sendMessage: jest.fn(),
sendMessageBy: jest.fn(),
sendTestMessage: jest.fn(), sendTestMessage: jest.fn(),
}; };
getConnectorInstancesPlaceHolder.mockResolvedValueOnce([mockedEmailConnector]); getConnectorInstancesPlaceHolder.mockResolvedValueOnce([mockedEmailConnector]);

View file

@ -1,13 +1,13 @@
import {
ConnectorInstance,
EmailConnectorInstance,
SmsConnectorInstance,
} from '@logto/connector-types';
import { arbitraryObjectGuard, ConnectorDto, Connectors, ConnectorType } from '@logto/schemas'; import { arbitraryObjectGuard, ConnectorDto, Connectors, ConnectorType } from '@logto/schemas';
import { emailRegEx, phoneRegEx } from '@logto/shared'; import { emailRegEx, phoneRegEx } from '@logto/shared';
import { object, string } from 'zod'; import { object, string } from 'zod';
import { getConnectorInstances, getConnectorInstanceById } from '@/connectors'; import { getConnectorInstances, getConnectorInstanceById } from '@/connectors';
import {
ConnectorInstance,
EmailConnectorInstance,
SmsConnectorInstance,
} from '@/connectors/types';
import RequestError from '@/errors/RequestError'; import RequestError from '@/errors/RequestError';
import koaGuard from '@/middleware/koa-guard'; import koaGuard from '@/middleware/koa-guard';
import { updateConnector } from '@/queries/connector'; import { updateConnector } from '@/queries/connector';

View file

@ -1,4 +1,4 @@
import { ConnectorError, ConnectorErrorCodes, ValidateConfig } from '@logto/connector-types'; import { ConnectorError, ConnectorErrorCodes, ValidateConfig } from '@logto/connector-schemas';
import { Connector, ConnectorType } from '@logto/schemas'; import { Connector, ConnectorType } from '@logto/schemas';
import { mockConnectorInstanceList, mockMetadata, mockConnector } from '@/__mocks__'; import { mockConnectorInstanceList, mockMetadata, mockConnector } from '@/__mocks__';
@ -13,7 +13,7 @@ import connectorRoutes from './connector';
type ConnectorInstance = { type ConnectorInstance = {
connector: Connector; connector: Connector;
metadata: ConnectorMetadata; metadata: ConnectorMetadata;
validateConfig?: ValidateConfig; validateConfig?: ValidateConfig<unknown>;
sendMessage?: unknown; sendMessage?: unknown;
}; };
@ -38,7 +38,7 @@ const getConnectorInstanceByIdPlaceHolder = jest.fn(async (connectorId: string)
sendMessage: sendMessagePlaceHolder, sendMessage: sendMessagePlaceHolder,
}; };
}); });
const validateConfigPlaceHolder = jest.fn() as jest.MockedFunction<ValidateConfig>; const validateConfigPlaceHolder = jest.fn() as jest.MockedFunction<ValidateConfig<unknown>>;
const sendMessagePlaceHolder = jest.fn(); const sendMessagePlaceHolder = jest.fn();
jest.mock('@/queries/connector', () => ({ jest.mock('@/queries/connector', () => ({

View file

@ -1,4 +1,4 @@
import { ConnectorMetadata } from '@logto/connector-types'; import { ConnectorMetadata } from '@logto/connector-schemas';
import { SignInMode } from '@logto/schemas'; import { SignInMode } from '@logto/schemas';
import { import {
adminConsoleApplicationId, adminConsoleApplicationId,

View file

@ -936,10 +936,10 @@ importers:
'@logto/connector-facebook': ^1.0.0-beta.5 '@logto/connector-facebook': ^1.0.0-beta.5
'@logto/connector-github': ^1.0.0-beta.5 '@logto/connector-github': ^1.0.0-beta.5
'@logto/connector-google': ^1.0.0-beta.5 '@logto/connector-google': ^1.0.0-beta.5
'@logto/connector-schemas': ^1.0.0-beta.5
'@logto/connector-sendgrid-email': ^1.0.0-beta.5 '@logto/connector-sendgrid-email': ^1.0.0-beta.5
'@logto/connector-smtp': ^1.0.0-beta.5 '@logto/connector-smtp': ^1.0.0-beta.5
'@logto/connector-twilio-sms': ^1.0.0-beta.5 '@logto/connector-twilio-sms': ^1.0.0-beta.5
'@logto/connector-types': ^1.0.0-beta.5
'@logto/connector-wechat-native': ^1.0.0-beta.5 '@logto/connector-wechat-native': ^1.0.0-beta.5
'@logto/connector-wechat-web': ^1.0.0-beta.5 '@logto/connector-wechat-web': ^1.0.0-beta.5
'@logto/phrases': ^1.0.0-beta.5 '@logto/phrases': ^1.0.0-beta.5
@ -1021,10 +1021,10 @@ importers:
'@logto/connector-facebook': link:../connector-facebook '@logto/connector-facebook': link:../connector-facebook
'@logto/connector-github': link:../connector-github '@logto/connector-github': link:../connector-github
'@logto/connector-google': link:../connector-google '@logto/connector-google': link:../connector-google
'@logto/connector-schemas': link:../connector-schemas
'@logto/connector-sendgrid-email': link:../connector-sendgrid-mail '@logto/connector-sendgrid-email': link:../connector-sendgrid-mail
'@logto/connector-smtp': link:../connector-smtp '@logto/connector-smtp': link:../connector-smtp
'@logto/connector-twilio-sms': link:../connector-twilio-sms '@logto/connector-twilio-sms': link:../connector-twilio-sms
'@logto/connector-types': link:../connector-types
'@logto/connector-wechat-native': link:../connector-wechat-native '@logto/connector-wechat-native': link:../connector-wechat-native
'@logto/connector-wechat-web': link:../connector-wechat-web '@logto/connector-wechat-web': link:../connector-wechat-web
'@logto/phrases': link:../phrases '@logto/phrases': link:../phrases