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

refactor(connector): add @logto/connector-schemas

This commit is contained in:
Darcy Ye 2022-08-12 10:53:58 +08:00
parent 6c423a8207
commit c16f49cb2f
No known key found for this signature in database
GPG key ID: B46F4C07EDEFC610
8 changed files with 258 additions and 0 deletions

View file

@ -0,0 +1,37 @@
{
"name": "@logto/connector-schemas",
"version": "1.0.0-beta.4",
"main": "lib/index.js",
"author": "Silverhand Inc. <contact@silverhand.io>",
"license": "MPL-2.0",
"private": true,
"files": [
"lib"
],
"scripts": {
"precommit": "lint-staged",
"build": "rm -rf lib/ && tsc --p tsconfig.build.json",
"lint": "eslint --ext .ts src",
"lint:report": "pnpm lint --format json --output-file report.json",
"prepack": "pnpm build"
},
"engines": {
"node": "^16.0.0"
},
"dependencies": {
"@logto/phrases": "^1.0.0-beta.4"
},
"devDependencies": {
"@silverhand/eslint-config": "1.0.0-rc.2",
"@silverhand/essentials": "^1.1.6",
"@silverhand/ts-config": "1.0.0-rc.2",
"eslint": "^8.21.0",
"lint-staged": "^13.0.0",
"prettier": "^2.7.1",
"typescript": "^4.7.4"
},
"eslintConfig": {
"extends": "@silverhand"
},
"prettier": "@silverhand/eslint-config/.prettierrc"
}

View file

@ -0,0 +1,124 @@
import { ConnectorMetadata } from './types';
export type EmailMessageTypes = {
SignIn: {
code: string;
};
Register: {
code: string;
};
ForgotPassword: {
code: string;
};
Test: Record<string, unknown>;
};
export type SmsMessageTypes = EmailMessageTypes;
export type EmailSendMessageFunction<T = unknown> = (
address: string,
type: keyof EmailMessageTypes,
payload: EmailMessageTypes[typeof type]
) => Promise<T>;
export type EmailSendTestMessageFunction<T = unknown> = (
config: Record<string, unknown>,
address: string,
type: keyof EmailMessageTypes,
payload: EmailMessageTypes[typeof type]
) => Promise<T>;
export type EmailSendMessageByFunction<T> = (
config: T,
address: string,
type: keyof EmailMessageTypes,
payload: EmailMessageTypes[typeof type]
) => Promise<unknown>;
export type SmsSendMessageFunction<T = unknown> = (
phone: string,
type: keyof SmsMessageTypes,
payload: SmsMessageTypes[typeof type]
) => Promise<T>;
export type SmsSendTestMessageFunction<T = unknown> = (
config: Record<string, unknown>,
phone: string,
type: keyof SmsMessageTypes,
payload: SmsMessageTypes[typeof type]
) => Promise<T>;
export type SmsSendMessageByFunction<T> = (
config: T,
phone: string,
type: keyof SmsMessageTypes,
payload: SmsMessageTypes[typeof type]
) => Promise<unknown>;
export type ValidateConfig<T> = (config: unknown) => asserts config is T;
export type GetAuthorizationUri = (payload: {
state: string;
redirectUri: string;
}) => Promise<string>;
export type GetUserInfo = (
data: unknown
) => Promise<{ id: string } & Record<string, string | undefined>>;
export type GetConnectorConfig = (id: string) => Promise<unknown>;
export type AuthResponseParser<T = Record<string, unknown>> = (response: unknown) => Promise<T>;
abstract class BaseConnector<T> {
public getConfig: GetConnectorConfig;
public metadata!: ConnectorMetadata;
constructor(getConnectorConfig: GetConnectorConfig) {
this.getConfig = getConnectorConfig;
}
public abstract validateConfig(config: unknown): asserts config is T;
}
export abstract class SmsConnector<T> extends BaseConnector<T> {
protected abstract readonly sendMessageBy: EmailSendMessageByFunction<T>;
public sendMessage: EmailSendMessageFunction = async (address, type, data) => {
const config = await this.getConfig(this.metadata.id);
this.validateConfig(config);
return this.sendMessageBy(config, address, type, data);
};
public sendTestMessage?: EmailSendTestMessageFunction = async (config, address, type, data) => {
this.validateConfig(config);
return this.sendMessageBy(config, address, type, data);
};
}
export abstract class EmailConnector<T> extends BaseConnector<T> {
protected abstract readonly sendMessageBy: SmsSendMessageByFunction<T>;
public sendMessage: SmsSendMessageFunction = async (address, type, data) => {
const config = await this.getConfig(this.metadata.id);
this.validateConfig(config);
return this.sendMessageBy(config, address, type, data);
};
public sendTestMessage?: SmsSendTestMessageFunction = async (config, address, type, data) => {
this.validateConfig(config);
return this.sendMessageBy(config, address, type, data);
};
}
export abstract class SocialConnector<T> extends BaseConnector<T> {
public abstract getAuthorizationUri: GetAuthorizationUri;
public abstract getUserInfo: GetUserInfo;
protected authResponseParser?: AuthResponseParser;
}

View file

@ -0,0 +1,13 @@
import { ConnectorErrorCodes } from './types';
export class ConnectorError extends Error {
public code: ConnectorErrorCodes;
public data: unknown;
constructor(code: ConnectorErrorCodes, data?: unknown) {
const message = typeof data === 'string' ? data : 'Connector error occurred.';
super(message);
this.code = code;
this.data = typeof data === 'string' ? { message: data } : data;
}
}

View file

@ -0,0 +1,3 @@
export * from './types';
export * from './error';
export * from './class';

View file

@ -0,0 +1,44 @@
import type { Language } from '@logto/phrases';
import { Nullable } from '@silverhand/essentials';
export enum ConnectorType {
Email = 'Email',
SMS = 'SMS',
Social = 'Social',
}
export enum ConnectorPlatform {
Native = 'Native',
Universal = 'Universal',
Web = 'Web',
}
export enum ConnectorErrorCodes {
General,
InsufficientRequestParameters,
InvalidConfig,
InvalidResponse,
TemplateNotFound,
NotImplemented,
SocialAuthCodeInvalid,
SocialAccessTokenInvalid,
SocialIdTokenInvalid,
AuthorizationFailed,
}
type i18nPhrases = { [Language.English]: string } & {
[key in Exclude<Language, Language.English>]?: 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;
};

View file

@ -0,0 +1,5 @@
{
"extends": "./tsconfig",
"include": ["src"],
"exclude": ["src/**/*.test.ts"]
}

View file

@ -0,0 +1,11 @@
{
"extends": "@silverhand/ts-config/tsconfig.base",
"compilerOptions": {
"outDir": "lib",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src"]
}

View file

@ -534,6 +534,27 @@ importers:
tsc-watch: 5.0.3_typescript@4.7.4
typescript: 4.7.4
packages/connector-schemas:
specifiers:
'@logto/phrases': ^1.0.0-beta.4
'@silverhand/eslint-config': 1.0.0-rc.2
'@silverhand/essentials': ^1.1.6
'@silverhand/ts-config': 1.0.0-rc.2
eslint: ^8.21.0
lint-staged: ^13.0.0
prettier: ^2.7.1
typescript: ^4.7.4
dependencies:
'@logto/phrases': link:../phrases
devDependencies:
'@silverhand/eslint-config': 1.0.0-rc.2_swk2g7ygmfleszo5c33j4vooni
'@silverhand/essentials': 1.1.7
'@silverhand/ts-config': 1.0.0-rc.2_typescript@4.7.4
eslint: 8.21.0
lint-staged: 13.0.0
prettier: 2.7.1
typescript: 4.7.4
packages/connector-sendgrid-mail:
specifiers:
'@jest/types': ^28.1.3