mirror of
https://github.com/logto-io/logto.git
synced 2025-04-14 23:11:31 -05:00
refactor: connector-core types (#1843)
* refactor: connector-core types * refactor: fix rebase issues * refactor: remove unused types * refactor: fix connector error code * refactor(core): add comments * refactor: remove unused types
This commit is contained in:
parent
8c2fba81fd
commit
139dec727d
77 changed files with 441 additions and 235 deletions
|
@ -1,4 +1,4 @@
|
|||
import { ConnectorType, ConnectorMetadata, ConnectorPlatform } from '@logto/connector-core';
|
||||
import { ConnectorMetadata, ConnectorPlatform } from '@logto/connector-core';
|
||||
|
||||
export const authorizationEndpoint = 'alipay://'; // This is used to arouse the native Alipay App
|
||||
export const alipayEndpoint = 'https://openapi.alipay.com/gateway.do';
|
||||
|
@ -18,7 +18,6 @@ export const invalidAccessTokenSubCode = ['isv.code-invalid'];
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'alipay-native',
|
||||
target: 'alipay',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Native,
|
||||
name: {
|
||||
en: 'Alipay',
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
CreateConnector,
|
||||
SocialConnector,
|
||||
validateConfig,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
import dayjs from 'dayjs';
|
||||
|
@ -182,6 +183,7 @@ const authorizationCallbackHandler = async (parameterObject: unknown) => {
|
|||
const createAlipayNativeConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: alipayNativeConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
|
|
|
@ -21,7 +21,6 @@ export const invalidAccessTokenSubCode = ['isv.code-invalid'];
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'alipay-web',
|
||||
target: 'alipay',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Web,
|
||||
name: {
|
||||
en: 'Alipay',
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
CreateConnector,
|
||||
SocialConnector,
|
||||
validateConfig,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
import dayjs from 'dayjs';
|
||||
|
@ -192,6 +193,7 @@ const authorizationCallbackHandler = async (parameterObject: unknown) => {
|
|||
const createAlipayConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: alipayConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
|
|
|
@ -12,7 +12,6 @@ export const staticConfigs = {
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'aliyun-direct-mail',
|
||||
target: 'aliyun-dm',
|
||||
type: ConnectorType.Email,
|
||||
platform: null,
|
||||
name: {
|
||||
en: 'Aliyun Direct Mail',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
ConnectorError,
|
||||
ConnectorErrorCodes,
|
||||
ConnectorType,
|
||||
CreateConnector,
|
||||
EmailConnector,
|
||||
GetConnectorConfig,
|
||||
|
@ -95,6 +96,7 @@ const errorHandler = (errorResponseBody: string) => {
|
|||
const createAliyunDmConnector: CreateConnector<EmailConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Email,
|
||||
configGuard: aliyunDmConfigGuard,
|
||||
sendMessage: sendMessage(getConfig),
|
||||
};
|
||||
|
|
|
@ -28,7 +28,6 @@ export enum SmsTemplateType {
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'aliyun-short-message-service',
|
||||
target: 'aliyun-sms',
|
||||
type: ConnectorType.SMS,
|
||||
platform: null,
|
||||
name: {
|
||||
en: 'Aliyun Short Message Service',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { MessageTypes } from '@logto/connector-core';
|
||||
|
||||
import createConnector from '.';
|
||||
import { mockedConnectorConfig, mockedValidConnectorConfig, phoneTest, codeTest } from './mock';
|
||||
import { mockedConnectorConfig, phoneTest, codeTest } from './mock';
|
||||
import { sendSms } from './single-send-text';
|
||||
|
||||
const getConfig = jest.fn().mockResolvedValue(mockedConnectorConfig);
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
SmsConnector,
|
||||
CreateConnector,
|
||||
validateConfig,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
import { HTTPError } from 'got';
|
||||
|
@ -87,6 +88,7 @@ const parseResponseString = (response: string) => {
|
|||
const createAliyunSmsConnector: CreateConnector<SmsConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Sms,
|
||||
configGuard: aliyunSmsConfigGuard,
|
||||
sendMessage: sendMessage(getConfig),
|
||||
};
|
||||
|
|
|
@ -11,13 +11,6 @@ export const mockedConnectorConfig = {
|
|||
],
|
||||
};
|
||||
|
||||
export const mockedValidConnectorConfig = {
|
||||
accessKeyId: 'accessKeyId',
|
||||
accessKeySecret: 'accessKeySecret',
|
||||
signName: 'signName',
|
||||
templates: [],
|
||||
};
|
||||
|
||||
export const phoneTest = '13012345678';
|
||||
export const codeTest = '1234';
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ export const scope = ''; // Note: `openid` is required when adding more scope(s)
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'apple-universal',
|
||||
target: 'apple',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
name: {
|
||||
en: 'Apple',
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
validateConfig,
|
||||
CreateConnector,
|
||||
SocialConnector,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { createRemoteJWKSet, jwtVerify } from 'jose';
|
||||
|
||||
|
@ -80,6 +81,7 @@ const authorizationCallbackHandler = async (parameterObject: unknown) => {
|
|||
const createAppleConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: appleConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
|
|
|
@ -6,7 +6,6 @@ export const scopes = ['User.Read'];
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'azuread-universal',
|
||||
target: 'azuread',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
name: {
|
||||
en: 'Azure Active Directory',
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
validateConfig,
|
||||
CreateConnector,
|
||||
SocialConnector,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert, conditional } from '@silverhand/essentials';
|
||||
import got, { HTTPError } from 'got';
|
||||
|
@ -152,6 +153,7 @@ const authorizationCallbackHandler = async (parameterObject: unknown) => {
|
|||
const createAzureAdConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: azureADConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
|
|
|
@ -2,9 +2,10 @@ import type { LanguageKey } from '@logto/shared';
|
|||
import { Nullable } from '@silverhand/essentials';
|
||||
import { z, ZodType } from 'zod';
|
||||
|
||||
// MARK: Foundation
|
||||
export enum ConnectorType {
|
||||
Email = 'Email',
|
||||
SMS = 'SMS',
|
||||
Sms = 'Sms',
|
||||
Social = 'Social',
|
||||
}
|
||||
|
||||
|
@ -18,22 +19,10 @@ type I18nPhrases = { en: string } & {
|
|||
[K in Exclude<LanguageKey, 'en'>]?: string;
|
||||
};
|
||||
|
||||
export type ConnectorMetadata = {
|
||||
id: string;
|
||||
target: string;
|
||||
type: ConnectorType;
|
||||
platform: Nullable<ConnectorPlatform>;
|
||||
name: I18nPhrases;
|
||||
logo: string;
|
||||
logoDark: Nullable<string>;
|
||||
description: I18nPhrases;
|
||||
readme: string;
|
||||
configTemplate: string;
|
||||
};
|
||||
|
||||
export enum ConnectorErrorCodes {
|
||||
General = 'general',
|
||||
InvalidMetadata = 'invalid_metadata',
|
||||
UnexpectedType = 'unexpected_type',
|
||||
InvalidConfigGuard = 'invalid_config_guard',
|
||||
InsufficientRequestParameters = 'insufficient_request_parameters',
|
||||
InvalidConfig = 'invalid_config',
|
||||
|
@ -67,34 +56,52 @@ export enum MessageTypes {
|
|||
|
||||
export const messageTypesGuard = z.nativeEnum(MessageTypes);
|
||||
|
||||
export type BaseConnector = {
|
||||
export type ConnectorMetadata = {
|
||||
id: string;
|
||||
target: string;
|
||||
platform: Nullable<ConnectorPlatform>;
|
||||
name: I18nPhrases;
|
||||
logo: string;
|
||||
logoDark: Nullable<string>;
|
||||
description: I18nPhrases;
|
||||
readme: string;
|
||||
configTemplate: string;
|
||||
};
|
||||
|
||||
export type BaseConnector<Type extends ConnectorType> = {
|
||||
type: Type;
|
||||
metadata: ConnectorMetadata;
|
||||
configGuard: ZodType;
|
||||
};
|
||||
|
||||
export type SmsConnector = {
|
||||
export type CreateConnector<T extends BaseConnector<ConnectorType>> = (options: {
|
||||
getConfig: GetConnectorConfig;
|
||||
}) => Promise<T>;
|
||||
|
||||
export type GetConnectorConfig = (id: string) => Promise<unknown>;
|
||||
|
||||
export type AllConnector = SmsConnector | EmailConnector | SocialConnector;
|
||||
|
||||
// MARK: SMS + Email connector
|
||||
export type SmsConnector = BaseConnector<ConnectorType.Sms> & {
|
||||
sendMessage: SendMessageFunction;
|
||||
} & BaseConnector;
|
||||
};
|
||||
|
||||
export type EmailConnector = SmsConnector;
|
||||
|
||||
export type SocialConnector = {
|
||||
getAuthorizationUri: GetAuthorizationUri;
|
||||
getUserInfo: GetUserInfo;
|
||||
} & BaseConnector;
|
||||
|
||||
export type GeneralConnector = BaseConnector &
|
||||
Partial<SocialConnector & EmailConnector & SmsConnector>;
|
||||
|
||||
export type CreateConnector<
|
||||
T extends SocialConnector | EmailConnector | SmsConnector | GeneralConnector
|
||||
> = (options: { getConfig: GetConnectorConfig }) => Promise<T>;
|
||||
export type EmailConnector = BaseConnector<ConnectorType.Email> & {
|
||||
sendMessage: SendMessageFunction;
|
||||
};
|
||||
|
||||
export type SendMessageFunction = (
|
||||
data: { to: string; type: MessageTypes; payload: { code: string } },
|
||||
config?: unknown
|
||||
) => Promise<unknown>;
|
||||
|
||||
// MARK: Social connector
|
||||
export type SocialConnector = BaseConnector<ConnectorType.Social> & {
|
||||
getAuthorizationUri: GetAuthorizationUri;
|
||||
getUserInfo: GetUserInfo;
|
||||
};
|
||||
|
||||
export type GetAuthorizationUri = (payload: {
|
||||
state: string;
|
||||
redirectUri: string;
|
||||
|
@ -103,5 +110,3 @@ export type GetAuthorizationUri = (payload: {
|
|||
export type GetUserInfo = (
|
||||
data: unknown
|
||||
) => Promise<{ id: string } & Record<string, string | undefined>>;
|
||||
|
||||
export type GetConnectorConfig = (id: string) => Promise<unknown>;
|
||||
|
|
|
@ -17,7 +17,6 @@ export const scope = 'email,public_profile';
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'facebook-universal',
|
||||
target: 'facebook',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
name: {
|
||||
en: 'Facebook',
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
GetUserInfo,
|
||||
GetConnectorConfig,
|
||||
validateConfig,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
import got, { HTTPError } from 'got';
|
||||
|
@ -160,6 +161,7 @@ const authorizationCallbackHandler = async (parameterObject: unknown) => {
|
|||
const createFacebookConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: facebookConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
|
|
|
@ -8,7 +8,6 @@ export const userInfoEndpoint = 'https://api.github.com/user';
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'github-universal',
|
||||
target: 'github',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
name: {
|
||||
en: 'GitHub',
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
CreateConnector,
|
||||
GetConnectorConfig,
|
||||
validateConfig,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert, conditional } from '@silverhand/essentials';
|
||||
import got, { HTTPError } from 'got';
|
||||
|
@ -145,6 +146,7 @@ const getUserInfo =
|
|||
const createGithubConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: githubConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
|
|
|
@ -8,7 +8,6 @@ export const scope = 'openid profile email';
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'google-universal',
|
||||
target: 'google',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
name: {
|
||||
en: 'Google',
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
validateConfig,
|
||||
CreateConnector,
|
||||
SocialConnector,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { conditional, assert } from '@silverhand/essentials';
|
||||
import got, { HTTPError } from 'got';
|
||||
|
@ -143,6 +144,7 @@ const getUserInfoErrorHandler = (error: unknown) => {
|
|||
const createGoogleConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: googleConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ConnectorMetadata, ConnectorPlatform, ConnectorType } from '@logto/connector-core';
|
||||
import { ConnectorMetadata, ConnectorPlatform } from '@logto/connector-core';
|
||||
|
||||
export const authorizationEndpoint = 'https://kauth.kakao.com/oauth/authorize';
|
||||
export const accessTokenEndpoint = 'https://kauth.kakao.com/oauth/token';
|
||||
|
@ -7,7 +7,6 @@ export const userInfoEndpoint = 'https://kapi.kakao.com/v2/user/me';
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'kakao-universal',
|
||||
target: 'kakao',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
name: {
|
||||
en: 'Kakao',
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import {
|
||||
ConnectorError,
|
||||
ConnectorErrorCodes,
|
||||
ConnectorType,
|
||||
CreateConnector,
|
||||
GetAuthorizationUri,
|
||||
GetConnectorConfig,
|
||||
|
@ -147,6 +148,7 @@ const getUserInfoErrorHandler = (error: unknown) => {
|
|||
const createKakaoConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: kakaoConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
|
|
|
@ -3,7 +3,6 @@ import { ConnectorType, ConnectorMetadata } from '@logto/connector-core';
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'mock-email-service',
|
||||
target: 'mock-mail',
|
||||
type: ConnectorType.Email,
|
||||
platform: null,
|
||||
name: {
|
||||
en: 'Mock Mail Service',
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
CreateConnector,
|
||||
EmailConnector,
|
||||
validateConfig,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
|
||||
|
@ -43,6 +44,7 @@ const sendMessage =
|
|||
const createMockEmailConnector: CreateConnector<EmailConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Email,
|
||||
configGuard: mockMailConfigGuard,
|
||||
sendMessage: sendMessage(getConfig),
|
||||
};
|
||||
|
|
|
@ -3,7 +3,6 @@ import { ConnectorType, ConnectorMetadata } from '@logto/connector-core';
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'mock-short-message-service',
|
||||
target: 'mock-sms',
|
||||
type: ConnectorType.SMS,
|
||||
platform: null,
|
||||
name: {
|
||||
en: 'Mock SMS Service',
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
validateConfig,
|
||||
CreateConnector,
|
||||
SmsConnector,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
|
||||
|
@ -43,6 +44,7 @@ const sendMessage =
|
|||
const createMockSmsConnector: CreateConnector<SmsConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Sms,
|
||||
configGuard: mockSmsConfigGuard,
|
||||
sendMessage: sendMessage(getConfig),
|
||||
};
|
||||
|
|
|
@ -3,7 +3,6 @@ import { ConnectorMetadata, ConnectorType, ConnectorPlatform } from '@logto/conn
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'mock-social-connector',
|
||||
target: 'mock-social',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
name: {
|
||||
en: 'Mock Social',
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
GetUserInfo,
|
||||
CreateConnector,
|
||||
SocialConnector,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { z } from 'zod';
|
||||
|
||||
|
@ -36,6 +37,7 @@ const getUserInfo: GetUserInfo = async (data) => {
|
|||
const createMockSocialConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: mockSocialConfigGuard,
|
||||
getAuthorizationUri,
|
||||
getUserInfo,
|
||||
|
|
|
@ -5,7 +5,6 @@ export const endpoint = 'https://api.sendgrid.com/v3/mail/send';
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'sendgrid-email-service',
|
||||
target: 'sendgrid-mail',
|
||||
type: ConnectorType.Email,
|
||||
platform: null,
|
||||
name: {
|
||||
en: 'SendGrid Mail Service',
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
validateConfig,
|
||||
CreateConnector,
|
||||
EmailConnector,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
import got, { HTTPError } from 'got';
|
||||
|
@ -87,6 +88,7 @@ const sendMessage =
|
|||
const createSendGridMailConnector: CreateConnector<EmailConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Email,
|
||||
configGuard: sendGridMailConfigGuard,
|
||||
sendMessage: sendMessage(getConfig),
|
||||
};
|
||||
|
|
|
@ -3,7 +3,6 @@ import { ConnectorType, ConnectorMetadata } from '@logto/connector-core';
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'simple-mail-transfer-protocol',
|
||||
target: 'smtp',
|
||||
type: ConnectorType.Email,
|
||||
platform: null,
|
||||
name: {
|
||||
en: 'SMTP',
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
EmailConnector,
|
||||
SendMessageFunction,
|
||||
validateConfig,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
import nodemailer from 'nodemailer';
|
||||
|
@ -89,6 +90,7 @@ const parseContents = (contents: string, contentType: ContextType) => {
|
|||
const createSmtpConnector: CreateConnector<EmailConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Email,
|
||||
configGuard: smtpConfigGuard,
|
||||
sendMessage: sendMessage(getConfig),
|
||||
};
|
||||
|
|
|
@ -5,7 +5,6 @@ export const endpoint = 'https://api.twilio.com/2010-04-01/Accounts/{{accountSID
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'twilio-short-message-service',
|
||||
target: 'twilio-sms',
|
||||
type: ConnectorType.SMS,
|
||||
platform: null,
|
||||
name: {
|
||||
en: 'Twilio SMS Service',
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
validateConfig,
|
||||
CreateConnector,
|
||||
SmsConnector,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
import got, { HTTPError } from 'got';
|
||||
|
@ -68,6 +69,7 @@ const sendMessage =
|
|||
const createTwilioSmsConnector: CreateConnector<SmsConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Sms,
|
||||
configGuard: twilioSmsConfigGuard,
|
||||
sendMessage: sendMessage(getConfig),
|
||||
};
|
||||
|
|
|
@ -13,7 +13,6 @@ export const invalidAccessTokenErrcode = [40_001, 40_014];
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'wechat-native',
|
||||
target: 'wechat',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Native,
|
||||
name: {
|
||||
en: 'WeChat',
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
validateConfig,
|
||||
CreateConnector,
|
||||
SocialConnector,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
import got, { HTTPError } from 'got';
|
||||
|
@ -167,6 +168,7 @@ const authorizationCallbackHandler = async (parameterObject: unknown) => {
|
|||
const createWechatNativeConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: wechatNativeConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
|
|
|
@ -13,7 +13,6 @@ export const invalidAccessTokenErrcode = [40_001, 40_014];
|
|||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'wechat-web',
|
||||
target: 'wechat',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Web,
|
||||
name: {
|
||||
en: 'WeChat',
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
validateConfig,
|
||||
CreateConnector,
|
||||
SocialConnector,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
import { assert } from '@silverhand/essentials';
|
||||
import got, { HTTPError } from 'got';
|
||||
|
@ -168,6 +169,7 @@ const authorizationCallbackHandler = async (parameterObject: unknown) => {
|
|||
const createWechatConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: wechatConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
|
|
|
@ -9,7 +9,7 @@ type TitlePlaceHolder = {
|
|||
};
|
||||
|
||||
export const connectorTitlePlaceHolder: TitlePlaceHolder = Object.freeze({
|
||||
[ConnectorType.SMS]: 'connectors.type.sms',
|
||||
[ConnectorType.Sms]: 'connectors.type.sms',
|
||||
[ConnectorType.Email]: 'connectors.type.email',
|
||||
[ConnectorType.Social]: 'connectors.type.social',
|
||||
});
|
||||
|
@ -29,6 +29,6 @@ type ConnectorPlaceholderIcon = {
|
|||
};
|
||||
|
||||
export const connectorPlaceholderIcon: ConnectorPlaceholderIcon = Object.freeze({
|
||||
[ConnectorType.SMS]: SmsConnectorIcon,
|
||||
[ConnectorType.Sms]: SmsConnectorIcon,
|
||||
[ConnectorType.Email]: EmailConnector,
|
||||
} as const);
|
||||
|
|
|
@ -14,7 +14,7 @@ const useConnectorInUse = (type?: ConnectorType, target?: string): boolean | und
|
|||
return data.signInMethods.email !== SignInMethodState.Disabled;
|
||||
}
|
||||
|
||||
if (type === ConnectorType.SMS) {
|
||||
if (type === ConnectorType.Sms) {
|
||||
return data.signInMethods.sms !== SignInMethodState.Disabled;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ const ConnectorContent = ({ isDeleted, connectorData, onConnectorUpdated }: Prop
|
|||
|
||||
const { metadata, ...rest } = await api
|
||||
.patch(`/api/connectors/${connectorData.id}`, { json: { config: result.data } })
|
||||
.json<Connector & { metadata: ConnectorMetadata }>();
|
||||
.json<Connector & { metadata: ConnectorMetadata; type: ConnectorType }>();
|
||||
|
||||
onConnectorUpdated({ ...rest, ...metadata });
|
||||
reset({ configJson: JSON.stringify(result.data, null, 2) });
|
||||
|
|
|
@ -13,7 +13,7 @@ const ConnectorTypeName = ({ type }: Props) => {
|
|||
return (
|
||||
<div className={styles.connectorType}>
|
||||
{type === ConnectorType.Email && t('connector_details.type_email')}
|
||||
{type === ConnectorType.SMS && t('connector_details.type_sms')}
|
||||
{type === ConnectorType.Sms && t('connector_details.type_sms')}
|
||||
{type === ConnectorType.Social && t('connector_details.type_social')}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -39,7 +39,7 @@ const SenderTester = ({ connectorId, connectorType, config, className }: Props)
|
|||
} = useForm<FormData>();
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const api = useApi();
|
||||
const isSms = connectorType === ConnectorType.SMS;
|
||||
const isSms = connectorType === ConnectorType.Sms;
|
||||
|
||||
useEffect(() => {
|
||||
if (!showTooltip) {
|
||||
|
|
|
@ -143,7 +143,7 @@ const ConnectorDetails = () => {
|
|||
}}
|
||||
>
|
||||
{t(
|
||||
data.type === ConnectorType.SMS
|
||||
data.type === ConnectorType.Sms
|
||||
? 'connector_details.options_change_sms'
|
||||
: 'connector_details.options_change_email'
|
||||
)}
|
||||
|
|
|
@ -46,7 +46,7 @@ const CreateForm = ({ onClose, isOpen: isFormOpen, type }: Props) => {
|
|||
return 'connectors.setup_title.email';
|
||||
}
|
||||
|
||||
if (type === ConnectorType.SMS) {
|
||||
if (type === ConnectorType.Sms) {
|
||||
return 'connectors.setup_title.sms';
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ const Guide = ({ connector, onClose }: Props) => {
|
|||
const connectorName = result.success ? name[result.data] : name.en;
|
||||
|
||||
const isSocialConnector =
|
||||
connectorType !== ConnectorType.SMS && connectorType !== ConnectorType.Email;
|
||||
connectorType !== ConnectorType.Sms && connectorType !== ConnectorType.Email;
|
||||
const methods = useForm<GuideForm>({ reValidateMode: 'onBlur' });
|
||||
const {
|
||||
control,
|
||||
|
|
|
@ -42,7 +42,7 @@ const Connectors = () => {
|
|||
|
||||
const smsConnector = useMemo(() => {
|
||||
const smsConnectorGroup = data?.find(
|
||||
({ enabled, type }) => enabled && type === ConnectorType.SMS
|
||||
({ enabled, type }) => enabled && type === ConnectorType.Sms
|
||||
);
|
||||
|
||||
return smsConnectorGroup?.connectors[0];
|
||||
|
@ -119,9 +119,9 @@ const Connectors = () => {
|
|||
{!isLoading && !isSocial && (
|
||||
<ConnectorRow
|
||||
connectors={smsConnector ? [smsConnector] : []}
|
||||
type={ConnectorType.SMS}
|
||||
type={ConnectorType.Sms}
|
||||
onClickSetup={() => {
|
||||
setCreateType(ConnectorType.SMS);
|
||||
setCreateType(ConnectorType.Sms);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -19,8 +19,8 @@ const ConnectorSetupWarning = ({ method }: Props) => {
|
|||
return;
|
||||
}
|
||||
|
||||
if (method === SignInMethodKey.SMS) {
|
||||
return ConnectorType.SMS;
|
||||
if (method === SignInMethodKey.Sms) {
|
||||
return ConnectorType.Sms;
|
||||
}
|
||||
|
||||
if (method === SignInMethodKey.Email) {
|
||||
|
|
|
@ -55,7 +55,7 @@ const SignInMethodsForm = () => {
|
|||
|
||||
const enabled =
|
||||
(method === SignInMethodKey.Email && email) ||
|
||||
(method === SignInMethodKey.SMS && sms) ||
|
||||
(method === SignInMethodKey.Sms && sms) ||
|
||||
(method === SignInMethodKey.Social && social);
|
||||
|
||||
return (
|
||||
|
|
|
@ -51,7 +51,7 @@ export const signInExperienceParser = {
|
|||
primary: primaryMethod,
|
||||
enableSecondary: secondaryMethods.length > 0,
|
||||
username: secondaryMethods.includes(SignInMethodKey.Username),
|
||||
sms: secondaryMethods.includes(SignInMethodKey.SMS),
|
||||
sms: secondaryMethods.includes(SignInMethodKey.Sms),
|
||||
email: secondaryMethods.includes(SignInMethodKey.Email),
|
||||
social: secondaryMethods.includes(SignInMethodKey.Social),
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@logto/core",
|
||||
"version": "1.0.0-beta.5",
|
||||
"version": "1.0.0-beta.6",
|
||||
"description": "The open source identity solution.",
|
||||
"main": "build/index.js",
|
||||
"author": "Silverhand Inc. <contact@silverhand.io>",
|
||||
|
|
|
@ -7,7 +7,6 @@ import { LogtoConnector } from '@/connectors/types';
|
|||
export const mockMetadata: ConnectorMetadata = {
|
||||
id: 'id',
|
||||
target: 'connector',
|
||||
type: ConnectorType.Email,
|
||||
platform: null,
|
||||
name: {
|
||||
en: 'Connector',
|
||||
|
@ -34,7 +33,7 @@ export const mockConnector: Connector = {
|
|||
createdAt: 1_234_567_890_123,
|
||||
};
|
||||
|
||||
export const mockLogtoConnector: Omit<LogtoConnector, 'metadata' | 'dbEntry'> = {
|
||||
export const mockLogtoConnector = {
|
||||
getAuthorizationUri: jest.fn(),
|
||||
getUserInfo: jest.fn(),
|
||||
sendMessage: jest.fn(),
|
||||
|
@ -46,7 +45,6 @@ const mockMetadata0: ConnectorMetadata = {
|
|||
...mockMetadata,
|
||||
id: 'id0',
|
||||
target: 'connector_0',
|
||||
type: ConnectorType.Email,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
};
|
||||
|
||||
|
@ -54,7 +52,6 @@ const mockMetadata1: ConnectorMetadata = {
|
|||
...mockMetadata,
|
||||
id: 'id1',
|
||||
target: 'connector_1',
|
||||
type: ConnectorType.SMS,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
};
|
||||
|
||||
|
@ -62,7 +59,6 @@ const mockMetadata2: ConnectorMetadata = {
|
|||
...mockMetadata,
|
||||
id: 'id2',
|
||||
target: 'connector_2',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
};
|
||||
|
||||
|
@ -70,7 +66,6 @@ const mockMetadata3: ConnectorMetadata = {
|
|||
...mockMetadata,
|
||||
id: 'id3',
|
||||
target: 'connector_3',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
};
|
||||
|
||||
|
@ -78,7 +73,6 @@ const mockMetadata4: ConnectorMetadata = {
|
|||
...mockMetadata,
|
||||
id: 'id4',
|
||||
target: 'connector_4',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
};
|
||||
|
||||
|
@ -86,7 +80,6 @@ const mockMetadata5: ConnectorMetadata = {
|
|||
...mockMetadata,
|
||||
id: 'id5',
|
||||
target: 'connector_5',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
};
|
||||
|
||||
|
@ -94,7 +87,6 @@ const mockMetadata6: ConnectorMetadata = {
|
|||
...mockMetadata,
|
||||
id: 'id6',
|
||||
target: 'connector_6',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Universal,
|
||||
};
|
||||
|
||||
|
@ -160,37 +152,44 @@ export const mockConnectorList: Connector[] = [
|
|||
export const mockLogtoConnectorList: LogtoConnector[] = [
|
||||
{
|
||||
dbEntry: mockConnector0,
|
||||
metadata: { ...mockMetadata0, type: ConnectorType.Social },
|
||||
metadata: { ...mockMetadata0 },
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
{
|
||||
dbEntry: mockConnector1,
|
||||
metadata: mockMetadata1,
|
||||
type: ConnectorType.Sms,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
{
|
||||
dbEntry: mockConnector2,
|
||||
metadata: mockMetadata2,
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
{
|
||||
dbEntry: mockConnector3,
|
||||
metadata: mockMetadata3,
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
{
|
||||
dbEntry: mockConnector4,
|
||||
metadata: { ...mockMetadata4, type: ConnectorType.Email, platform: null },
|
||||
metadata: { ...mockMetadata4, platform: null },
|
||||
type: ConnectorType.Email,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
{
|
||||
dbEntry: mockConnector5,
|
||||
metadata: { ...mockMetadata5, type: ConnectorType.SMS, platform: null },
|
||||
metadata: { ...mockMetadata5, platform: null },
|
||||
type: ConnectorType.Sms,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
{
|
||||
dbEntry: mockConnector6,
|
||||
metadata: { ...mockMetadata6, type: ConnectorType.Email, platform: null },
|
||||
metadata: { ...mockMetadata6, platform: null },
|
||||
type: ConnectorType.Email,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
];
|
||||
|
@ -204,9 +203,9 @@ export const mockAliyunDmConnector: LogtoConnector = {
|
|||
...mockMetadata,
|
||||
id: 'aliyun-dm',
|
||||
target: 'aliyun-dm',
|
||||
type: ConnectorType.Email,
|
||||
platform: null,
|
||||
},
|
||||
type: ConnectorType.Email,
|
||||
...mockLogtoConnector,
|
||||
};
|
||||
|
||||
|
@ -219,9 +218,9 @@ export const mockAliyunSmsConnector: LogtoConnector = {
|
|||
...mockMetadata,
|
||||
id: 'aliyun-sms',
|
||||
target: 'aliyun-sms',
|
||||
type: ConnectorType.SMS,
|
||||
platform: null,
|
||||
},
|
||||
type: ConnectorType.Sms,
|
||||
...mockLogtoConnector,
|
||||
};
|
||||
|
||||
|
@ -234,9 +233,9 @@ export const mockFacebookConnector: LogtoConnector = {
|
|||
...mockMetadata,
|
||||
id: 'facebook',
|
||||
target: 'facebook',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Web,
|
||||
},
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
};
|
||||
|
||||
|
@ -249,9 +248,9 @@ export const mockGithubConnector: LogtoConnector = {
|
|||
...mockMetadata,
|
||||
id: 'github',
|
||||
target: 'github',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Web,
|
||||
},
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
};
|
||||
|
||||
|
@ -264,9 +263,9 @@ export const mockWechatConnector: LogtoConnector = {
|
|||
...mockMetadata,
|
||||
id: 'wechat-web',
|
||||
target: 'wechat',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Web,
|
||||
},
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
};
|
||||
|
||||
|
@ -279,9 +278,9 @@ export const mockWechatNativeConnector: LogtoConnector = {
|
|||
...mockMetadata,
|
||||
id: 'wechat-native',
|
||||
target: 'wechat',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Native,
|
||||
},
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
};
|
||||
|
||||
|
@ -295,9 +294,9 @@ export const mockGoogleConnector: LogtoConnector = {
|
|||
...mockMetadata,
|
||||
id: 'google',
|
||||
target: 'google',
|
||||
type: ConnectorType.Social,
|
||||
platform: ConnectorPlatform.Web,
|
||||
},
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import { ConnectorError, ConnectorErrorCodes, GeneralConnector } from '@logto/connector-core';
|
||||
|
||||
import { LogtoConnector } from './types';
|
||||
import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-core';
|
||||
|
||||
export const defaultConnectorPackages = [
|
||||
'@logto/connector-alipay-web',
|
||||
|
@ -24,10 +22,9 @@ const notImplemented = () => {
|
|||
throw new ConnectorError(ConnectorErrorCodes.NotImplemented);
|
||||
};
|
||||
|
||||
export const defaultConnectorMethods: Omit<LogtoConnector, 'metadata' | 'configGuard' | 'dbEntry'> =
|
||||
{
|
||||
getAuthorizationUri: notImplemented,
|
||||
getUserInfo: notImplemented,
|
||||
sendMessage: notImplemented,
|
||||
validateConfig: notImplemented,
|
||||
};
|
||||
export const defaultConnectorMethods = {
|
||||
getAuthorizationUri: notImplemented,
|
||||
getUserInfo: notImplemented,
|
||||
sendMessage: notImplemented,
|
||||
validateConfig: notImplemented,
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { existsSync, readFileSync } from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { CreateConnector, GeneralConnector, validateConfig } from '@logto/connector-core';
|
||||
import { AllConnector, CreateConnector, validateConfig } from '@logto/connector-core';
|
||||
import resolvePackagePath from 'resolve-package-path';
|
||||
|
||||
import envSet from '@/env-set';
|
||||
|
@ -9,11 +9,11 @@ import RequestError from '@/errors/RequestError';
|
|||
import { findAllConnectors, insertConnector } from '@/queries/connector';
|
||||
|
||||
import { defaultConnectorMethods, defaultConnectorPackages } from './consts';
|
||||
import { LogtoConnector } from './types';
|
||||
import { LoadConnector, LogtoConnector } from './types';
|
||||
import { getConnectorConfig, validateConnectorModule } from './utilities';
|
||||
|
||||
// eslint-disable-next-line @silverhand/fp/no-let
|
||||
let cachedConnectors: Array<Omit<LogtoConnector, 'dbEntry'>> | undefined;
|
||||
let cachedConnectors: LoadConnector[] | undefined;
|
||||
|
||||
const loadConnectors = async () => {
|
||||
if (cachedConnectors) {
|
||||
|
@ -31,12 +31,12 @@ const loadConnectors = async () => {
|
|||
connectorPackages.map(async (packageName) => {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
const { default: createConnector } = (await import(packageName)) as {
|
||||
default: CreateConnector<GeneralConnector>;
|
||||
default: CreateConnector<AllConnector>;
|
||||
};
|
||||
const rawConnector = await createConnector({ getConfig: getConnectorConfig });
|
||||
validateConnectorModule(rawConnector);
|
||||
|
||||
const connector: Omit<LogtoConnector, 'dbEntry'> = {
|
||||
const connector: LoadConnector = {
|
||||
...defaultConnectorMethods,
|
||||
...rawConnector,
|
||||
validateConfig: (config: unknown) => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { GeneralConnector } from '@logto/connector-core';
|
||||
import { AllConnector } from '@logto/connector-core';
|
||||
import { Connector, PasscodeType } from '@logto/schemas';
|
||||
import { z } from 'zod';
|
||||
|
||||
|
@ -16,7 +16,16 @@ export const socialUserInfoGuard = z.object({
|
|||
|
||||
export type SocialUserInfo = z.infer<typeof socialUserInfoGuard>;
|
||||
|
||||
export type LogtoConnector = Required<GeneralConnector> & {
|
||||
dbEntry: Connector;
|
||||
/**
|
||||
* Dynamic loaded connector type.
|
||||
*/
|
||||
export type LoadConnector<T extends AllConnector = AllConnector> = T & {
|
||||
validateConfig: (config: unknown) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* The connector type with full context.
|
||||
*/
|
||||
export type LogtoConnector<T extends AllConnector = AllConnector> = LoadConnector<T> & {
|
||||
dbEntry: Connector;
|
||||
};
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import { ConnectorError, ConnectorErrorCodes, GeneralConnector } from '@logto/connector-core';
|
||||
import {
|
||||
BaseConnector,
|
||||
ConnectorError,
|
||||
ConnectorErrorCodes,
|
||||
ConnectorType,
|
||||
} from '@logto/connector-core';
|
||||
|
||||
import RequestError from '@/errors/RequestError';
|
||||
import { findAllConnectors } from '@/queries/connector';
|
||||
|
@ -14,8 +19,8 @@ export const getConnectorConfig = async (id: string): Promise<unknown> => {
|
|||
};
|
||||
|
||||
export function validateConnectorModule(
|
||||
connector: Partial<GeneralConnector>
|
||||
): asserts connector is GeneralConnector {
|
||||
connector: Partial<BaseConnector<ConnectorType>>
|
||||
): asserts connector is BaseConnector<ConnectorType> {
|
||||
if (!connector.metadata) {
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidMetadata);
|
||||
}
|
||||
|
@ -23,4 +28,8 @@ export function validateConnectorModule(
|
|||
if (!connector.configGuard) {
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfigGuard);
|
||||
}
|
||||
|
||||
if (!connector.type || !Object.values(ConnectorType).includes(connector.type)) {
|
||||
throw new ConnectorError(ConnectorErrorCodes.UnexpectedType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,9 +135,10 @@ describe('sendPasscode', () => {
|
|||
},
|
||||
metadata: {
|
||||
...mockMetadata,
|
||||
type: ConnectorType.Email,
|
||||
platform: null,
|
||||
},
|
||||
type: ConnectorType.Email,
|
||||
sendMessage: jest.fn(),
|
||||
configGuard: any(),
|
||||
},
|
||||
]);
|
||||
|
@ -155,7 +156,7 @@ describe('sendPasscode', () => {
|
|||
await expect(sendPasscode(passcode)).rejects.toThrowError(
|
||||
new RequestError({
|
||||
code: 'connector.not_found',
|
||||
type: ConnectorType.SMS,
|
||||
type: ConnectorType.Sms,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -172,9 +173,9 @@ describe('sendPasscode', () => {
|
|||
},
|
||||
metadata: {
|
||||
...mockMetadata,
|
||||
type: ConnectorType.SMS,
|
||||
platform: null,
|
||||
},
|
||||
type: ConnectorType.Sms,
|
||||
sendMessage,
|
||||
},
|
||||
{
|
||||
|
@ -186,9 +187,9 @@ describe('sendPasscode', () => {
|
|||
},
|
||||
metadata: {
|
||||
...mockMetadata,
|
||||
type: ConnectorType.Email,
|
||||
platform: null,
|
||||
},
|
||||
type: ConnectorType.Email,
|
||||
sendMessage,
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
import { messageTypesGuard, ConnectorError, ConnectorErrorCodes } from '@logto/connector-core';
|
||||
import {
|
||||
messageTypesGuard,
|
||||
ConnectorError,
|
||||
ConnectorErrorCodes,
|
||||
EmailConnector,
|
||||
SmsConnector,
|
||||
} from '@logto/connector-core';
|
||||
import { Passcode, PasscodeType } from '@logto/schemas';
|
||||
import { customAlphabet, nanoid } from 'nanoid';
|
||||
|
||||
import { getLogtoConnectors } from '@/connectors';
|
||||
import { ConnectorType } from '@/connectors/types';
|
||||
import { ConnectorType, LogtoConnector } from '@/connectors/types';
|
||||
import RequestError from '@/errors/RequestError';
|
||||
import {
|
||||
consumePasscode,
|
||||
|
@ -46,22 +52,19 @@ export const sendPasscode = async (passcode: Passcode) => {
|
|||
throw new RequestError('passcode.phone_email_empty');
|
||||
}
|
||||
|
||||
const expectType = passcode.phone ? ConnectorType.Sms : ConnectorType.Email;
|
||||
const connectors = await getLogtoConnectors();
|
||||
|
||||
const emailConnector = connectors.find(
|
||||
(connector) => connector.dbEntry.enabled && connector.metadata.type === ConnectorType.Email
|
||||
const connector = connectors.find(
|
||||
(connector): connector is LogtoConnector<SmsConnector | EmailConnector> =>
|
||||
connector.dbEntry.enabled && connector.type === expectType
|
||||
);
|
||||
const smsConnector = connectors.find(
|
||||
(connector) => connector.dbEntry.enabled && connector.metadata.type === ConnectorType.SMS
|
||||
);
|
||||
|
||||
const connector = passcode.email ? emailConnector : smsConnector;
|
||||
|
||||
assertThat(
|
||||
connector,
|
||||
new RequestError({
|
||||
code: 'connector.not_found',
|
||||
type: passcode.email ? ConnectorType.Email : ConnectorType.SMS,
|
||||
type: expectType,
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ describe('validate sign-in methods', () => {
|
|||
}).toMatchError(
|
||||
new RequestError({
|
||||
code: 'sign_in_experiences.enabled_connector_not_found',
|
||||
type: ConnectorType.SMS,
|
||||
type: ConnectorType.Sms,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
|
|
@ -41,7 +41,7 @@ export const validateSignInMethods = (
|
|||
|
||||
if (isEnabled(signInMethods.email)) {
|
||||
assertThat(
|
||||
enabledConnectors.some((item) => item.metadata.type === ConnectorType.Email),
|
||||
enabledConnectors.some((item) => item.type === ConnectorType.Email),
|
||||
new RequestError({
|
||||
code: 'sign_in_experiences.enabled_connector_not_found',
|
||||
type: ConnectorType.Email,
|
||||
|
@ -51,17 +51,17 @@ export const validateSignInMethods = (
|
|||
|
||||
if (isEnabled(signInMethods.sms)) {
|
||||
assertThat(
|
||||
enabledConnectors.some((item) => item.metadata.type === ConnectorType.SMS),
|
||||
enabledConnectors.some((item) => item.type === ConnectorType.Sms),
|
||||
new RequestError({
|
||||
code: 'sign_in_experiences.enabled_connector_not_found',
|
||||
type: ConnectorType.SMS,
|
||||
type: ConnectorType.Sms,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (isEnabled(signInMethods.social)) {
|
||||
assertThat(
|
||||
enabledConnectors.some((item) => item.metadata.type === ConnectorType.Social),
|
||||
enabledConnectors.some((item) => item.type === ConnectorType.Social),
|
||||
new RequestError({
|
||||
code: 'sign_in_experiences.enabled_connector_not_found',
|
||||
type: ConnectorType.Social,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { User } from '@logto/schemas';
|
||||
import { ConnectorType, User } from '@logto/schemas';
|
||||
import { Nullable } from '@silverhand/essentials';
|
||||
import { InteractionResults } from 'oidc-provider';
|
||||
import { z } from 'zod';
|
||||
|
@ -41,6 +41,15 @@ export const getUserInfoByAuthCode = async (
|
|||
): Promise<SocialUserInfo> => {
|
||||
const connector = await getConnector(connectorId);
|
||||
|
||||
assertThat(
|
||||
connector.type === ConnectorType.Social,
|
||||
new RequestError({
|
||||
code: 'session.invalid_connector_id',
|
||||
status: 422,
|
||||
connectorId,
|
||||
})
|
||||
);
|
||||
|
||||
return connector.getUserInfo(data);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { MessageTypes } from '@logto/connector-core';
|
||||
import { EmailConnector, MessageTypes, SmsConnector } from '@logto/connector-core';
|
||||
import { Connector, ConnectorType } from '@logto/schemas';
|
||||
import { any } from 'zod';
|
||||
|
||||
|
@ -49,9 +49,7 @@ describe('connector route', () => {
|
|||
|
||||
it('throws if more than one SMS connector is enabled', async () => {
|
||||
getLogtoConnectorsPlaceHolder.mockResolvedValueOnce(
|
||||
mockLogtoConnectorList.filter(
|
||||
(connector) => connector.metadata.type !== ConnectorType.Email
|
||||
)
|
||||
mockLogtoConnectorList.filter((connector) => connector.type !== ConnectorType.Email)
|
||||
);
|
||||
const response = await connectorRequest.get('/connectors').send({});
|
||||
expect(response).toHaveProperty('statusCode', 400);
|
||||
|
@ -59,9 +57,7 @@ describe('connector route', () => {
|
|||
|
||||
it('shows all connectors', async () => {
|
||||
getLogtoConnectorsPlaceHolder.mockResolvedValueOnce(
|
||||
mockLogtoConnectorList.filter(
|
||||
(connector) => connector.metadata.type === ConnectorType.Social
|
||||
)
|
||||
mockLogtoConnectorList.filter((connector) => connector.type === ConnectorType.Social)
|
||||
);
|
||||
const response = await connectorRequest.get('/connectors').send({});
|
||||
expect(response).toHaveProperty('statusCode', 200);
|
||||
|
@ -100,12 +96,12 @@ describe('connector route', () => {
|
|||
it('should get SMS connector and send test message', async () => {
|
||||
const mockedMetadata = {
|
||||
...mockMetadata,
|
||||
type: ConnectorType.SMS,
|
||||
};
|
||||
const sendMessage = jest.fn();
|
||||
const mockedSmsConnector: LogtoConnector = {
|
||||
const mockedSmsConnector: LogtoConnector<SmsConnector> = {
|
||||
dbEntry: mockConnector,
|
||||
metadata: mockedMetadata,
|
||||
type: ConnectorType.Sms,
|
||||
configGuard: any(),
|
||||
...defaultConnectorMethods,
|
||||
sendMessage,
|
||||
|
@ -130,9 +126,10 @@ describe('connector route', () => {
|
|||
|
||||
it('should get email connector and send test message', async () => {
|
||||
const sendMessage = jest.fn();
|
||||
const mockedEmailConnector: LogtoConnector = {
|
||||
const mockedEmailConnector: LogtoConnector<EmailConnector> = {
|
||||
dbEntry: mockConnector,
|
||||
metadata: mockMetadata,
|
||||
type: ConnectorType.Email,
|
||||
configGuard: any(),
|
||||
...defaultConnectorMethods,
|
||||
sendMessage,
|
||||
|
|
|
@ -12,9 +12,10 @@ import assertThat from '@/utils/assert-that';
|
|||
|
||||
import { AuthedRouter } from './types';
|
||||
|
||||
const transpileLogtoConnector = ({ dbEntry, metadata }: LogtoConnector): ConnectorDto => ({
|
||||
...dbEntry,
|
||||
const transpileLogtoConnector = ({ dbEntry, metadata, type }: LogtoConnector): ConnectorDto => ({
|
||||
type,
|
||||
...metadata,
|
||||
...dbEntry,
|
||||
});
|
||||
|
||||
export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
||||
|
@ -31,14 +32,13 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
|
||||
assertThat(
|
||||
connectors.filter(
|
||||
(connector) =>
|
||||
connector.dbEntry.enabled && connector.metadata.type === ConnectorType.Email
|
||||
(connector) => connector.dbEntry.enabled && connector.type === ConnectorType.Email
|
||||
).length <= 1,
|
||||
'connector.more_than_one_email'
|
||||
);
|
||||
assertThat(
|
||||
connectors.filter(
|
||||
(connector) => connector.dbEntry.enabled && connector.metadata.type === ConnectorType.SMS
|
||||
(connector) => connector.dbEntry.enabled && connector.type === ConnectorType.Sms
|
||||
).length <= 1,
|
||||
'connector.more_than_one_sms'
|
||||
);
|
||||
|
@ -80,6 +80,7 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
} = ctx.guard;
|
||||
|
||||
const {
|
||||
type,
|
||||
dbEntry: { config },
|
||||
metadata,
|
||||
validateConfig,
|
||||
|
@ -91,15 +92,12 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
|
||||
// Only allow one enabled connector for SMS and Email.
|
||||
// disable other connectors before enable this one.
|
||||
if (
|
||||
enabled &&
|
||||
(metadata.type === ConnectorType.SMS || metadata.type === ConnectorType.Email)
|
||||
) {
|
||||
if (enabled && (type === ConnectorType.Sms || type === ConnectorType.Email)) {
|
||||
const connectors = await getLogtoConnectors();
|
||||
await Promise.all(
|
||||
connectors
|
||||
.filter(
|
||||
({ dbEntry: { enabled }, metadata: { type } }) => type === metadata.type && enabled
|
||||
({ dbEntry: { enabled }, type: currentType }) => type === currentType && enabled
|
||||
)
|
||||
.map(async ({ dbEntry: { id } }) =>
|
||||
updateConnector({ set: { enabled: false }, where: { id }, jsonbMode: 'merge' })
|
||||
|
@ -112,7 +110,7 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
where: { id },
|
||||
jsonbMode: 'merge',
|
||||
});
|
||||
ctx.body = { ...connector, metadata };
|
||||
ctx.body = { ...connector, metadata, type };
|
||||
|
||||
return next();
|
||||
}
|
||||
|
@ -130,14 +128,14 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
body,
|
||||
} = ctx.guard;
|
||||
|
||||
const { metadata, validateConfig } = await getLogtoConnectorById(id);
|
||||
const { metadata, type, validateConfig } = await getLogtoConnectorById(id);
|
||||
|
||||
if (body.config) {
|
||||
validateConfig(body.config);
|
||||
}
|
||||
|
||||
const connector = await updateConnector({ set: body, where: { id }, jsonbMode: 'replace' });
|
||||
ctx.body = { ...connector, metadata };
|
||||
ctx.body = { ...connector, metadata, type };
|
||||
|
||||
return next();
|
||||
}
|
||||
|
@ -164,21 +162,17 @@ export default function connectorRoutes<T extends AuthedRouter>(router: T) {
|
|||
const subject = phone ?? email;
|
||||
assertThat(subject, new RequestError({ code: 'guard.invalid_input' }));
|
||||
|
||||
const connector = phone
|
||||
? logtoConnectors.find(
|
||||
({ metadata: { id: id_, type } }) => id_ === id && type === ConnectorType.SMS
|
||||
)
|
||||
: logtoConnectors.find(
|
||||
({ metadata: { id: id_, type } }) => id_ === id && type === ConnectorType.Email
|
||||
);
|
||||
const connector = logtoConnectors.find(({ metadata: { id: currentId } }) => currentId === id);
|
||||
const expectType = phone ? ConnectorType.Sms : ConnectorType.Email;
|
||||
|
||||
assertThat(
|
||||
connector,
|
||||
new RequestError({
|
||||
code: 'connector.not_found',
|
||||
type: phone ? ConnectorType.SMS : ConnectorType.Email,
|
||||
type: expectType,
|
||||
})
|
||||
);
|
||||
assertThat(connector.type === expectType, 'connector.unexpected_type');
|
||||
|
||||
const { sendMessage } = connector;
|
||||
|
||||
|
|
|
@ -75,7 +75,8 @@ describe('connector PATCH routes', () => {
|
|||
getLogtoConnectorsPlaceholder.mockResolvedValueOnce([
|
||||
{
|
||||
dbEntry: mockConnector,
|
||||
metadata: { ...mockMetadata, type: ConnectorType.Social },
|
||||
metadata: mockMetadata,
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
]);
|
||||
|
@ -90,7 +91,8 @@ describe('connector PATCH routes', () => {
|
|||
})
|
||||
);
|
||||
expect(response.body).toMatchObject({
|
||||
metadata: { ...mockMetadata, type: ConnectorType.Social },
|
||||
metadata: mockMetadata,
|
||||
type: ConnectorType.Social,
|
||||
});
|
||||
expect(response).toHaveProperty('statusCode', 200);
|
||||
});
|
||||
|
@ -100,6 +102,7 @@ describe('connector PATCH routes', () => {
|
|||
{
|
||||
dbEntry: mockConnector,
|
||||
metadata: mockMetadata,
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
validateConfig: () => {
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig);
|
||||
|
@ -117,6 +120,7 @@ describe('connector PATCH routes', () => {
|
|||
{
|
||||
dbEntry: mockConnector,
|
||||
metadata: mockMetadata,
|
||||
type: ConnectorType.Social,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
]);
|
||||
|
@ -141,7 +145,6 @@ describe('connector PATCH routes', () => {
|
|||
const mockedMetadata = {
|
||||
...mockMetadata,
|
||||
id: 'id1',
|
||||
type: ConnectorType.SMS,
|
||||
};
|
||||
const mockedConnector = {
|
||||
...mockConnector,
|
||||
|
@ -150,6 +153,7 @@ describe('connector PATCH routes', () => {
|
|||
getLogtoConnectorByIdPlaceholder.mockResolvedValueOnce({
|
||||
dbEntry: mockedConnector,
|
||||
metadata: mockedMetadata,
|
||||
type: ConnectorType.Sms,
|
||||
...mockLogtoConnector,
|
||||
});
|
||||
const response = await connectorRequest
|
||||
|
@ -189,10 +193,8 @@ describe('connector PATCH routes', () => {
|
|||
getLogtoConnectorsPlaceholder.mockResolvedValueOnce([
|
||||
{
|
||||
dbEntry: mockConnector,
|
||||
metadata: {
|
||||
...mockMetadata,
|
||||
type: ConnectorType.SMS,
|
||||
},
|
||||
metadata: mockMetadata,
|
||||
type: ConnectorType.Sms,
|
||||
...mockLogtoConnector,
|
||||
validateConfig: () => {
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig);
|
||||
|
@ -210,6 +212,7 @@ describe('connector PATCH routes', () => {
|
|||
{
|
||||
dbEntry: mockConnector,
|
||||
metadata: mockMetadata,
|
||||
type: ConnectorType.Sms,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
]);
|
||||
|
@ -252,6 +255,7 @@ describe('connector PATCH routes', () => {
|
|||
{
|
||||
dbEntry: mockConnector,
|
||||
metadata: mockMetadata,
|
||||
type: ConnectorType.Sms,
|
||||
...mockLogtoConnector,
|
||||
validateConfig: () => {
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig);
|
||||
|
@ -269,6 +273,7 @@ describe('connector PATCH routes', () => {
|
|||
{
|
||||
dbEntry: mockConnector,
|
||||
metadata: mockMetadata,
|
||||
type: ConnectorType.Sms,
|
||||
...mockLogtoConnector,
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -61,10 +61,14 @@ const getLogtoConnectorByIdHelper = jest.fn(async (connectorId: string) => {
|
|||
: connectorId === 'social_disabled'
|
||||
? 'social_disabled'
|
||||
: 'others',
|
||||
type: connectorId.startsWith('social') ? ConnectorType.Social : ConnectorType.SMS,
|
||||
};
|
||||
|
||||
return { dbEntry: database, metadata, getAuthorizationUri: jest.fn(async () => '') };
|
||||
return {
|
||||
dbEntry: database,
|
||||
metadata,
|
||||
type: connectorId.startsWith('social') ? ConnectorType.Social : ConnectorType.Sms,
|
||||
getAuthorizationUri: jest.fn(async () => ''),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('@/connectors', () => ({
|
||||
|
@ -72,7 +76,7 @@ jest.mock('@/connectors', () => ({
|
|||
getLogtoConnectorById: jest.fn(async (connectorId: string) => {
|
||||
const connector = await getLogtoConnectorByIdHelper(connectorId);
|
||||
|
||||
if (connector.metadata.type !== ConnectorType.Social) {
|
||||
if (connector.type !== ConnectorType.Social) {
|
||||
throw new RequestError({
|
||||
code: 'entity.not_found',
|
||||
status: 404,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { userInfoSelectFields } from '@logto/schemas';
|
||||
import { ConnectorType, userInfoSelectFields } from '@logto/schemas';
|
||||
import { redirectUriRegEx } from '@logto/shared';
|
||||
import pick from 'lodash.pick';
|
||||
import { Provider } from 'oidc-provider';
|
||||
|
@ -45,6 +45,7 @@ export default function socialRoutes<T extends AnonymousRouter>(router: T, provi
|
|||
assertThat(state && redirectUri, 'session.insufficient_info');
|
||||
const connector = await getLogtoConnectorById(connectorId);
|
||||
assertThat(connector.dbEntry.enabled, 'connector.not_enabled');
|
||||
assertThat(connector.type === ConnectorType.Social, 'connector.unexpected_type');
|
||||
const redirectTo = await connector.getAuthorizationUri({ state, redirectUri });
|
||||
ctx.body = { redirectTo };
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ export default function signInExperiencesRoutes<T extends AuthedRouter>(router:
|
|||
const filteredSocialSignInConnectorTargets = socialSignInConnectorTargets?.filter((target) =>
|
||||
enabledConnectors.some(
|
||||
(connector) =>
|
||||
connector.metadata.target === target && connector.metadata.type === ConnectorType.Social
|
||||
connector.metadata.target === target && connector.type === ConnectorType.Social
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ test('connector set-up flow', async () => {
|
|||
*/
|
||||
await Promise.all(
|
||||
[
|
||||
{ id: mockSmsConnectorId, config: mockSmsConnectorConfig, type: ConnectorType.SMS },
|
||||
{ id: mockSmsConnectorId, config: mockSmsConnectorConfig, type: ConnectorType.Sms },
|
||||
{ id: mockEmailConnectorId, config: mockEmailConnectorConfig, type: ConnectorType.Email },
|
||||
].map(async ({ id, config, type }) => {
|
||||
const updatedConnector = await updateConnectorConfig(id, config);
|
||||
|
|
|
@ -64,6 +64,7 @@ const errors = {
|
|||
not_enabled: 'The connector is not enabled.',
|
||||
invalid_metadata: "The connector's metadata is invalid.",
|
||||
invalid_config_guard: "The connector's config guard is invalid.",
|
||||
unexpected_type: "The connector's type is unexpected.",
|
||||
insufficient_request_parameters: 'The request might miss some input parameters.',
|
||||
invalid_config: "The connector's config is invalid.",
|
||||
invalid_response: "The connector's response is invalid.",
|
||||
|
|
|
@ -69,6 +69,7 @@ const errors = {
|
|||
not_enabled: "Le connecteur n'est pas activé.",
|
||||
invalid_metadata: "The connector's metadata is invalid.", // UNTRANSLATED
|
||||
invalid_config_guard: "The connector's config guard is invalid.", // UNTRANSLATED
|
||||
unexpected_type: "The connector's type is unexpected.", // UNTRANSLATED
|
||||
insufficient_request_parameters: 'Certains paramètres peuvent manquer dans la requête.',
|
||||
invalid_config: "La configuration du connecteur n'est pas valide.",
|
||||
invalid_response: "La réponse du connecteur n'est pas valide.",
|
||||
|
|
|
@ -63,6 +63,7 @@ const errors = {
|
|||
not_enabled: '연동이 활성화 되지 않았어요.',
|
||||
invalid_metadata: "The connector's metadata is invalid.", // UNTRANSLATED
|
||||
invalid_config_guard: "The connector's config guard is invalid.", // UNTRANSLATED
|
||||
unexpected_type: "The connector's type is unexpected.", // UNTRANSLATED
|
||||
insufficient_request_parameters: '요청 데이터에서 일부 정보가 없어요.',
|
||||
invalid_config: '연동 설정이 유효하지 않아요.',
|
||||
invalid_response: '연동 응답이 유효하지 않아요.',
|
||||
|
|
|
@ -65,6 +65,7 @@ const errors = {
|
|||
not_enabled: 'Bağlayıcı etkin değil.',
|
||||
invalid_metadata: "The connector's metadata is invalid.", // UNTRANSLATED
|
||||
invalid_config_guard: "The connector's config guard is invalid.", // UNTRANSLATED
|
||||
unexpected_type: "The connector's type is unexpected.", // UNTRANSLATED
|
||||
insufficient_request_parameters: 'İstek, bazı input parametrelerini atlayabilir.',
|
||||
invalid_config: 'Bağlayıcının ayarları geçersiz.',
|
||||
invalid_response: 'Bağlayıcının yanıtı geçersiz.',
|
||||
|
|
|
@ -63,6 +63,7 @@ const errors = {
|
|||
not_enabled: '连接器尚未启用',
|
||||
invalid_metadata: '连接器 metadata 参数错误',
|
||||
invalid_config_guard: '连接器配置 guard 错误',
|
||||
unexpected_type: '连接器类型错误',
|
||||
insufficient_request_parameters: '请求参数缺失',
|
||||
invalid_config: '连接器配置错误',
|
||||
invalid_response: '连接器错误响应',
|
||||
|
|
|
@ -111,7 +111,7 @@ export type LanguageInfo = z.infer<typeof languageInfoGuard>;
|
|||
export enum SignInMethodKey {
|
||||
Username = 'username',
|
||||
Email = 'email',
|
||||
SMS = 'sms',
|
||||
Sms = 'sms',
|
||||
Social = 'social',
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ export enum SignInMethodState {
|
|||
export const signInMethodsGuard = z.object({
|
||||
[SignInMethodKey.Username]: z.nativeEnum(SignInMethodState),
|
||||
[SignInMethodKey.Email]: z.nativeEnum(SignInMethodState),
|
||||
[SignInMethodKey.SMS]: z.nativeEnum(SignInMethodState),
|
||||
[SignInMethodKey.Sms]: z.nativeEnum(SignInMethodState),
|
||||
[SignInMethodKey.Social]: z.nativeEnum(SignInMethodState),
|
||||
});
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import { ConnectorMetadata } from '@logto/connector-core';
|
||||
import { BaseConnector, ConnectorMetadata, ConnectorType } from '@logto/connector-core';
|
||||
|
||||
import { Connector } from '../db-entries';
|
||||
|
||||
export type { ConnectorMetadata } from '@logto/connector-core';
|
||||
export { ConnectorType, ConnectorPlatform } from '@logto/connector-core';
|
||||
|
||||
export type ConnectorDto = Connector & ConnectorMetadata;
|
||||
export type ConnectorDto = Connector &
|
||||
Omit<BaseConnector<ConnectorType>, 'configGuard' | 'metadata'> &
|
||||
ConnectorMetadata;
|
||||
|
|
253
pnpm-lock.yaml
generated
253
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue