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:
parent
05ae6e532e
commit
b076ba4bc9
24 changed files with 177 additions and 75 deletions
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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', () => ({
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue