mirror of
https://github.com/logto-io/logto.git
synced 2025-01-20 21:32:31 -05:00
feat(connector-sendgrid-email): add sendgrid email connector (#850)
* feat(connector-sendgrid-mail): add SendGrid Mail connector * feat(core): add SendGrid Mail connector to initializer and fix usageType
This commit is contained in:
parent
646bd36758
commit
b887655827
20 changed files with 523 additions and 106 deletions
|
@ -6,17 +6,17 @@
|
|||
"fromAlias": "<connector-alias>",
|
||||
"templates": [
|
||||
{
|
||||
"usageType": "SIGN_IN",
|
||||
"usageType": "SignIn",
|
||||
"subject": "<sign-in-template-subject>",
|
||||
"content": "<sign-in-template-content>"
|
||||
},
|
||||
{
|
||||
"usageType": "REGISTER",
|
||||
"usageType": "Register",
|
||||
"subject": "<register-template-subject>",
|
||||
"content": "<register-template-content>"
|
||||
},
|
||||
{
|
||||
"usageType": "TEST",
|
||||
"usageType": "Test",
|
||||
"subject": "<test-template-subject>",
|
||||
"content": "<test-template-content>"
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"templates": [
|
||||
{
|
||||
"type": 0,
|
||||
"usageType": "SIGN_IN",
|
||||
"usageType": "SignIn",
|
||||
"code": "<temporary-passcode>",
|
||||
"name": "<sign-in-template-name>",
|
||||
"content": "<sign-in-template-content>",
|
||||
|
@ -14,7 +14,7 @@
|
|||
},
|
||||
{
|
||||
"type": 0,
|
||||
"usageType": "REGISTER",
|
||||
"usageType": "Register",
|
||||
"code": "<temporary-passcode>",
|
||||
"name": "<register-template-name>",
|
||||
"content": "<register-template-content>",
|
||||
|
@ -22,7 +22,7 @@
|
|||
},
|
||||
{
|
||||
"type": 0,
|
||||
"usageType": "TEST",
|
||||
"usageType": "Test",
|
||||
"code": "<temporary-passcode>",
|
||||
"name": "<test-template-name>",
|
||||
"content": "<test-template-content>",
|
||||
|
|
2
packages/connector-sendgrid-mail/README.md
Normal file
2
packages/connector-sendgrid-mail/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
### SendGrid Mail README
|
||||
placeholder
|
26
packages/connector-sendgrid-mail/docs/config-template.md
Normal file
26
packages/connector-sendgrid-mail/docs/config-template.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
```json
|
||||
{
|
||||
"apiKey": "<api-key>",
|
||||
"fromEmail": "noreply@logto.test.io",
|
||||
"templates": [
|
||||
{
|
||||
"usageType": "SignIn",
|
||||
"type": "text/plain",
|
||||
"subject": "Logto SignIn Template",
|
||||
"content": "This is for sign-in purposes only. Your passcode is {{code}}.",
|
||||
},
|
||||
{
|
||||
"usageType": "Register",
|
||||
"type": "text/plain",
|
||||
"subject": "Logto Register Template",
|
||||
"content": "This is for registering purposes only. Your passcode is {{code}}.",
|
||||
},
|
||||
{
|
||||
"usageType": "Test",
|
||||
"type": "text/plain",
|
||||
"subject": "Logto Test Template",
|
||||
"content": "This is for testing purposes only. Your passcode is {{code}}.",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
8
packages/connector-sendgrid-mail/jest.config.ts
Normal file
8
packages/connector-sendgrid-mail/jest.config.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { Config, merge } from '@silverhand/jest-config';
|
||||
|
||||
const config: Config.InitialOptions = merge({
|
||||
testEnvironment: 'node',
|
||||
setupFilesAfterEnv: ['jest-matcher-specific-error'],
|
||||
});
|
||||
|
||||
export default config;
|
55
packages/connector-sendgrid-mail/package.json
Normal file
55
packages/connector-sendgrid-mail/package.json
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "@logto/connector-sendgrid-email",
|
||||
"version": "0.1.0",
|
||||
"description": "SendGrid Email Service connector implementation.",
|
||||
"main": "./lib/index.js",
|
||||
"exports": "./lib/index.js",
|
||||
"author": "Silverhand Inc. <contact@silverhand.io>",
|
||||
"license": "MPL-2.0",
|
||||
"files": [
|
||||
"lib",
|
||||
"docs"
|
||||
],
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"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",
|
||||
"dev": "rm -rf lib/ && tsc-watch -p tsconfig.build.json --preserveWatchOutput --onSuccess \"node ./lib/index.js\"",
|
||||
"test": "jest",
|
||||
"test:coverage": "jest --coverage --silent",
|
||||
"prepack": "pnpm build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@logto/connector-types": "^0.1.0",
|
||||
"@logto/shared": "^0.1.0",
|
||||
"@silverhand/essentials": "^1.1.6",
|
||||
"@silverhand/jest-config": "^0.14.0",
|
||||
"got": "^11.8.2",
|
||||
"zod": "^3.14.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/types": "^27.5.1",
|
||||
"@silverhand/eslint-config": "^0.14.0",
|
||||
"@silverhand/ts-config": "^0.14.0",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/node": "^16.3.1",
|
||||
"eslint": "^8.10.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-matcher-specific-error": "^1.0.0",
|
||||
"lint-staged": "^12.0.0",
|
||||
"prettier": "^2.3.2",
|
||||
"ts-jest": "^27.1.1",
|
||||
"tsc-watch": "^5.0.0",
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "@silverhand"
|
||||
},
|
||||
"prettier": "@silverhand/eslint-config/.prettierrc"
|
||||
}
|
30
packages/connector-sendgrid-mail/src/constant.ts
Normal file
30
packages/connector-sendgrid-mail/src/constant.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import path from 'path';
|
||||
|
||||
import { ConnectorType, ConnectorMetadata } from '@logto/connector-types';
|
||||
import { getFileContents } from '@logto/shared';
|
||||
|
||||
export const endpoint = 'https://api.sendgrid.com/v3/mail/send';
|
||||
|
||||
// eslint-disable-next-line unicorn/prefer-module
|
||||
const currentPath = __dirname;
|
||||
const pathToReadmeFile = path.join(currentPath, '..', 'README.md');
|
||||
const pathToConfigTemplate = path.join(currentPath, '..', 'docs', 'config-template.md');
|
||||
const readmeContentFallback = 'Please check README.md file directory.';
|
||||
const configTemplateFallback = 'Please check config-template.md file directory.';
|
||||
|
||||
export const defaultMetadata: ConnectorMetadata = {
|
||||
target: 'sendgrid-mail',
|
||||
type: ConnectorType.Email,
|
||||
platform: null,
|
||||
name: {
|
||||
en: 'SendGrid Mail Service',
|
||||
'zh-CN': 'SendGrid 邮件服务',
|
||||
},
|
||||
logo: './logo.png',
|
||||
description: {
|
||||
en: 'Leverage the email service that customer-first brands trust for reliable inbox delivery at scale.',
|
||||
'zh-CN': '客户至上品牌信任的电子邮件服务,实现大规模可靠的收件箱递送。',
|
||||
},
|
||||
readme: getFileContents(pathToReadmeFile, readmeContentFallback),
|
||||
configTemplate: getFileContents(pathToConfigTemplate, configTemplateFallback),
|
||||
};
|
43
packages/connector-sendgrid-mail/src/index.test.ts
Normal file
43
packages/connector-sendgrid-mail/src/index.test.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { GetConnectorConfig } from '@logto/connector-types';
|
||||
|
||||
import { SendGridMailConnector } from '.';
|
||||
import { mockedConfig } from './mock';
|
||||
import { ContextType, SendGridMailConfig } from './types';
|
||||
|
||||
const getConnectorConfig = jest.fn() as GetConnectorConfig<SendGridMailConfig>;
|
||||
|
||||
const sendGridMailMethods = new SendGridMailConnector(getConnectorConfig);
|
||||
|
||||
jest.mock('got');
|
||||
|
||||
beforeAll(() => {
|
||||
jest.spyOn(sendGridMailMethods, 'getConfig').mockResolvedValue(mockedConfig);
|
||||
});
|
||||
|
||||
describe('validateConfig()', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should pass on valid config', async () => {
|
||||
await expect(
|
||||
sendGridMailMethods.validateConfig({
|
||||
apiKey: 'apiKey',
|
||||
fromEmail: 'noreply@logto.test.io',
|
||||
fromName: 'Logto Test',
|
||||
templates: [
|
||||
{
|
||||
usageType: 'Test',
|
||||
type: ContextType.Text,
|
||||
subject: 'Logto Test Template',
|
||||
content: 'This is for testing purposes only. Your passcode is {{code}}.',
|
||||
},
|
||||
],
|
||||
})
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
it('throws if config is invalid', async () => {
|
||||
await expect(sendGridMailMethods.validateConfig({})).rejects.toThrow();
|
||||
});
|
||||
});
|
90
packages/connector-sendgrid-mail/src/index.ts
Normal file
90
packages/connector-sendgrid-mail/src/index.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
import {
|
||||
ConnectorError,
|
||||
ConnectorErrorCodes,
|
||||
ConnectorMetadata,
|
||||
EmailSendMessageFunction,
|
||||
ValidateConfig,
|
||||
EmailConnector,
|
||||
GetConnectorConfig,
|
||||
} from '@logto/connector-types';
|
||||
import { assert, Nullable } from '@silverhand/essentials';
|
||||
import got from 'got';
|
||||
|
||||
import { defaultMetadata, endpoint } from './constant';
|
||||
import {
|
||||
sendGridMailConfigGuard,
|
||||
SendEmailResponse,
|
||||
SendGridMailConfig,
|
||||
EmailData,
|
||||
Personalization,
|
||||
Content,
|
||||
PublicParameters,
|
||||
} from './types';
|
||||
|
||||
export class SendGridMailConnector implements EmailConnector {
|
||||
public metadata: ConnectorMetadata = defaultMetadata;
|
||||
|
||||
public readonly getConfig: GetConnectorConfig<SendGridMailConfig>;
|
||||
|
||||
constructor(getConnectorConfig: GetConnectorConfig<SendGridMailConfig>) {
|
||||
this.getConfig = getConnectorConfig;
|
||||
}
|
||||
|
||||
public validateConfig: ValidateConfig = async (config: unknown) => {
|
||||
const result = sendGridMailConfigGuard.safeParse(config);
|
||||
|
||||
if (!result.success) {
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig, result.error.message);
|
||||
}
|
||||
};
|
||||
|
||||
public sendMessage: EmailSendMessageFunction<Nullable<SendEmailResponse>> = async (
|
||||
address,
|
||||
type,
|
||||
data
|
||||
) => {
|
||||
const config = await this.getConfig(this.metadata.target, this.metadata.platform);
|
||||
await this.validateConfig(config);
|
||||
const { apiKey, fromEmail, fromName, templates } = config;
|
||||
const template = templates.find((template) => template.usageType === type);
|
||||
|
||||
assert(
|
||||
template,
|
||||
new ConnectorError(
|
||||
ConnectorErrorCodes.TemplateNotFound,
|
||||
`Template not found for type: ${type}`
|
||||
)
|
||||
);
|
||||
|
||||
const toEmailData: EmailData[] = [{ email: address }];
|
||||
const fromEmailData: EmailData = fromName
|
||||
? { email: fromEmail, name: fromName }
|
||||
: { email: fromEmail };
|
||||
const personalizations: Personalization = { to: toEmailData };
|
||||
const content: Content = {
|
||||
type: template.type,
|
||||
value:
|
||||
typeof data.code === 'string'
|
||||
? template.content.replace(/{{code}}/g, data.code)
|
||||
: template.content,
|
||||
};
|
||||
const { subject } = template;
|
||||
|
||||
const parameters: PublicParameters = {
|
||||
personalizations: [personalizations],
|
||||
from: fromEmailData,
|
||||
subject,
|
||||
content: [content],
|
||||
};
|
||||
|
||||
return got
|
||||
.post(endpoint, {
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
json: parameters,
|
||||
})
|
||||
.json<Nullable<SendEmailResponse>>();
|
||||
};
|
||||
}
|
32
packages/connector-sendgrid-mail/src/mock.ts
Normal file
32
packages/connector-sendgrid-mail/src/mock.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import {
|
||||
Content,
|
||||
ContextType,
|
||||
EmailData,
|
||||
Personalization,
|
||||
PublicParameters,
|
||||
SendGridMailConfig,
|
||||
} from './types';
|
||||
|
||||
const receivers: EmailData[] = [{ email: 'foo@logto.io' }];
|
||||
const sender: EmailData = { email: 'noreply@logto.test.io', name: 'Logto Test' };
|
||||
export const mockedParameters: PublicParameters = {
|
||||
personalizations: [{ to: receivers }] as Personalization[],
|
||||
from: sender,
|
||||
subject: 'Test SendGrid Mail',
|
||||
content: [{ type: 'text/plain', value: 'This is a test template.' }] as Content[],
|
||||
};
|
||||
|
||||
export const mockedApiKey = 'apikey';
|
||||
|
||||
export const mockedConfig: SendGridMailConfig = {
|
||||
apiKey: mockedApiKey,
|
||||
fromEmail: 'noreply@logto.test.io',
|
||||
templates: [
|
||||
{
|
||||
usageType: 'Test',
|
||||
type: ContextType.Text,
|
||||
subject: 'Logto Test Template',
|
||||
content: 'This is for testing purposes only. Your passcode is {{code}}.',
|
||||
},
|
||||
],
|
||||
};
|
119
packages/connector-sendgrid-mail/src/types.ts
Normal file
119
packages/connector-sendgrid-mail/src/types.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
import { Nullable } from '@silverhand/essentials';
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* @doc https://docs.sendgrid.com/api-reference/mail-send/mail-send#body
|
||||
*/
|
||||
|
||||
export enum ContextType {
|
||||
Text = 'text/plain',
|
||||
Html = 'text/html',
|
||||
}
|
||||
|
||||
export type EmailData = {
|
||||
name?: string;
|
||||
email: string;
|
||||
};
|
||||
|
||||
export type Personalization = {
|
||||
to: EmailData[];
|
||||
from?: EmailData;
|
||||
cc?: EmailData | EmailData[];
|
||||
bcc?: EmailData | EmailData[];
|
||||
subject?: string;
|
||||
headers?: Record<string, string>;
|
||||
substitutions?: Record<string, string>;
|
||||
dynamic_template_data?: Record<string, any>;
|
||||
custom_args?: Record<string, string>;
|
||||
sendAt?: number;
|
||||
};
|
||||
|
||||
export type Content = {
|
||||
type: ContextType;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type Attachment = {
|
||||
content: string;
|
||||
type: ContextType;
|
||||
filename: string;
|
||||
disposition: 'inline' | 'attachment';
|
||||
content_id: string; // The attachment's content ID. This is used when the disposition is set to “inline” and the attachment is an image, allowing the file to be displayed within the body of your email.
|
||||
};
|
||||
|
||||
export type Asm = {
|
||||
group_id: number;
|
||||
groups_to_display?: number[]; // Maxitems: 25
|
||||
};
|
||||
|
||||
export type MailSettings = {
|
||||
bypass_list_management: { enable: boolean };
|
||||
bypass_spam_management: { enable: boolean };
|
||||
bypass_bounce_management: { enable: boolean };
|
||||
bypass_unsubscribe_management: { enable: boolean };
|
||||
footer: { enable: boolean; text: string; html: string };
|
||||
sandbox_mode: { enable: boolean };
|
||||
};
|
||||
|
||||
export type TrackingSettings = {
|
||||
click_tracking: { enable: boolean; enable_test: boolean };
|
||||
open_tracking: { enable: boolean; substitution_tag: string };
|
||||
subscription_tracking: { enable: boolean; test: string; html: string; substitution_tag: string };
|
||||
ganalytics: {
|
||||
enable: boolean;
|
||||
utm_source: string;
|
||||
utm_medium: string;
|
||||
utm_campaign: string;
|
||||
utm_term: string;
|
||||
utm_content: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type PublicParameters = {
|
||||
personalizations: Personalization[];
|
||||
from: EmailData;
|
||||
reply_to?: EmailData;
|
||||
reply_to_list?: EmailData[]; // Maxitems: 1000, uniqueItems: true
|
||||
subject: string; // MinLength: 1
|
||||
content: Content[];
|
||||
attachments?: Attachment[];
|
||||
template_id?: string; // An email template ID. The template content got here will overwrite all previous content fields.
|
||||
headers?: Record<string, string>; // An object containing key/value pairs of header names and the value to substitute for them. The key/value pairs must be strings. You must ensure these are properly encoded if they contain unicode characters. These headers cannot be one of the reserved headers.
|
||||
categories?: string[]; // An array of category names for this message. Each category name may not exceed 255 characters. Maxitems: 1000, uniqueItems: true
|
||||
custom_args?: string; // This parameter is overridden by custom_args set at the personalizations level. Total custom_args size may not exceed 10,000 bytes.
|
||||
send_at?: number; // A unix timestamp.
|
||||
batch_id?: string; // An ID representing a batch of emails to be sent at the same time.
|
||||
asm?: Asm; // An object allowing you to specify how to handle unsubscribes.
|
||||
ip_pool_name?: string; // The IP Pool that you would like to send this email from. maxLength: 64, minLength: 2
|
||||
mail_settings?: MailSettings;
|
||||
tracking_settings?: TrackingSettings;
|
||||
};
|
||||
|
||||
/**
|
||||
* UsageType here is used to specify the use case of the template, can be either
|
||||
* 'Register', 'SignIn', 'ForgotPassword' or 'Test'.
|
||||
*/
|
||||
const templateGuard = z.object({
|
||||
usageType: z.string(),
|
||||
type: z.nativeEnum(ContextType),
|
||||
subject: z.string(),
|
||||
content: z.string(), // With variable {{code}}, support HTML
|
||||
});
|
||||
|
||||
export const sendGridMailConfigGuard = z.object({
|
||||
apiKey: z.string(),
|
||||
fromEmail: z.string(),
|
||||
fromName: z.string().optional(),
|
||||
templates: z.array(templateGuard),
|
||||
});
|
||||
|
||||
export type SendGridMailConfig = z.infer<typeof sendGridMailConfigGuard>;
|
||||
|
||||
/**
|
||||
* @doc https://docs.sendgrid.com/api-reference/mail-send/mail-send#responses
|
||||
*/
|
||||
type HelpObject = Record<string, unknown>; // Helper text or docs for troubleshooting
|
||||
|
||||
type ErrorObject = { message: string; field?: Nullable<string>; help?: HelpObject };
|
||||
|
||||
export type SendEmailResponse = { errors: ErrorObject; id?: string };
|
10
packages/connector-sendgrid-mail/tsconfig.base.json
Normal file
10
packages/connector-sendgrid-mail/tsconfig.base.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "@silverhand/ts-config/tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
}
|
||||
}
|
5
packages/connector-sendgrid-mail/tsconfig.build.json
Normal file
5
packages/connector-sendgrid-mail/tsconfig.build.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"extends": "./tsconfig.base",
|
||||
"include": ["src"],
|
||||
"exclude": ["src/**/*.test.ts"]
|
||||
}
|
7
packages/connector-sendgrid-mail/tsconfig.json
Normal file
7
packages/connector-sendgrid-mail/tsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "./tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"types": ["node", "jest", "jest-matcher-specific-error"]
|
||||
},
|
||||
"include": ["src", "jest.config.ts"]
|
||||
}
|
6
packages/connector-sendgrid-mail/tsconfig.test.json
Normal file
6
packages/connector-sendgrid-mail/tsconfig.test.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": "./tsconfig",
|
||||
"compilerOptions": {
|
||||
"isolatedModules": false
|
||||
}
|
||||
}
|
|
@ -56,7 +56,7 @@ export type EmailMessageTypes = {
|
|||
Test: Record<string, unknown>;
|
||||
};
|
||||
|
||||
type SmsMessageTypes = EmailMessageTypes;
|
||||
export type SmsMessageTypes = EmailMessageTypes;
|
||||
|
||||
export type EmailSendMessageFunction<T = unknown> = (
|
||||
address: string,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"@logto/connector-facebook": "^0.1.0",
|
||||
"@logto/connector-github": "^0.1.0",
|
||||
"@logto/connector-google": "^0.1.0",
|
||||
"@logto/connector-sendgrid-email": "^0.1.0",
|
||||
"@logto/connector-types": "^0.1.0",
|
||||
"@logto/connector-wechat": "^0.1.0",
|
||||
"@logto/connector-wechat-native": "^0.1.0",
|
||||
|
|
|
@ -59,6 +59,14 @@ const googleConnector = {
|
|||
config: {},
|
||||
createdAt: 1_646_382_233_000,
|
||||
};
|
||||
const sendGridMailConnector = {
|
||||
id: 'sendgrid-mail',
|
||||
target: 'sendgrid-mail',
|
||||
platform: null,
|
||||
enabled: false,
|
||||
config: {},
|
||||
createdAt: 1_646_382_233_111,
|
||||
};
|
||||
const wechatConnector = {
|
||||
id: 'wechat',
|
||||
target: 'wechat',
|
||||
|
@ -83,6 +91,7 @@ const connectors = [
|
|||
facebookConnector,
|
||||
githubConnector,
|
||||
googleConnector,
|
||||
sendGridMailConnector,
|
||||
wechatConnector,
|
||||
wechatNativeConnector,
|
||||
];
|
||||
|
@ -106,8 +115,9 @@ describe('getConnectorInstances', () => {
|
|||
expect(connectorInstances[3]).toHaveProperty('connector', facebookConnector);
|
||||
expect(connectorInstances[4]).toHaveProperty('connector', githubConnector);
|
||||
expect(connectorInstances[5]).toHaveProperty('connector', googleConnector);
|
||||
expect(connectorInstances[6]).toHaveProperty('connector', wechatConnector);
|
||||
expect(connectorInstances[7]).toHaveProperty('connector', wechatNativeConnector);
|
||||
expect(connectorInstances[6]).toHaveProperty('connector', sendGridMailConnector);
|
||||
expect(connectorInstances[7]).toHaveProperty('connector', wechatConnector);
|
||||
expect(connectorInstances[8]).toHaveProperty('connector', wechatNativeConnector);
|
||||
});
|
||||
|
||||
test('should throw if any required connector does not exist in DB', async () => {
|
||||
|
|
|
@ -4,6 +4,7 @@ import { AliyunSmsConnector } from '@logto/connector-aliyun-sms';
|
|||
import { FacebookConnector } from '@logto/connector-facebook';
|
||||
import { GithubConnector } from '@logto/connector-github';
|
||||
import { GoogleConnector } from '@logto/connector-google';
|
||||
import { SendGridMailConnector } from '@logto/connector-sendgrid-email';
|
||||
import { WeChatConnector } from '@logto/connector-wechat';
|
||||
import { WeChatNativeConnector } from '@logto/connector-wechat-native';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
@ -21,6 +22,7 @@ const allConnectors: IConnector[] = [
|
|||
new FacebookConnector(getConnectorConfig),
|
||||
new GithubConnector(getConnectorConfig),
|
||||
new GoogleConnector(getConnectorConfig),
|
||||
new SendGridMailConnector(getConnectorConfig),
|
||||
new WeChatConnector(getConnectorConfig),
|
||||
new WeChatNativeConnector(getConnectorConfig),
|
||||
];
|
||||
|
|
165
pnpm-lock.yaml
generated
165
pnpm-lock.yaml
generated
|
@ -306,6 +306,49 @@ importers:
|
|||
tsc-watch: 5.0.3_typescript@4.6.3
|
||||
typescript: 4.6.3
|
||||
|
||||
packages/connector-sendgrid-mail:
|
||||
specifiers:
|
||||
'@jest/types': ^27.5.1
|
||||
'@logto/connector-types': ^0.1.0
|
||||
'@logto/shared': ^0.1.0
|
||||
'@silverhand/eslint-config': ^0.14.0
|
||||
'@silverhand/essentials': ^1.1.6
|
||||
'@silverhand/jest-config': ^0.14.0
|
||||
'@silverhand/ts-config': ^0.14.0
|
||||
'@types/jest': ^27.4.1
|
||||
'@types/node': ^16.3.1
|
||||
eslint: ^8.10.0
|
||||
got: ^11.8.2
|
||||
jest: ^27.5.1
|
||||
jest-matcher-specific-error: ^1.0.0
|
||||
lint-staged: ^12.0.0
|
||||
prettier: ^2.3.2
|
||||
ts-jest: ^27.1.1
|
||||
tsc-watch: ^5.0.0
|
||||
typescript: ^4.6.2
|
||||
zod: ^3.14.3
|
||||
dependencies:
|
||||
'@logto/connector-types': link:../connector-types
|
||||
'@logto/shared': link:../shared
|
||||
'@silverhand/essentials': 1.1.7
|
||||
'@silverhand/jest-config': 0.14.0_53ggqi2i4rbcfjtktmjua6zili
|
||||
got: 11.8.3
|
||||
zod: 3.14.3
|
||||
devDependencies:
|
||||
'@jest/types': 27.5.1
|
||||
'@silverhand/eslint-config': 0.14.0_rqoong6vegs374egqglqjbgiwm
|
||||
'@silverhand/ts-config': 0.14.0_typescript@4.6.4
|
||||
'@types/jest': 27.4.1
|
||||
'@types/node': 16.11.12
|
||||
eslint: 8.10.0
|
||||
jest: 27.5.1
|
||||
jest-matcher-specific-error: 1.0.0
|
||||
lint-staged: 12.4.0
|
||||
prettier: 2.5.1
|
||||
ts-jest: 27.1.1_53ggqi2i4rbcfjtktmjua6zili
|
||||
tsc-watch: 5.0.3_typescript@4.6.4
|
||||
typescript: 4.6.4
|
||||
|
||||
packages/connector-types:
|
||||
specifiers:
|
||||
'@jest/types': ^27.5.1
|
||||
|
@ -553,6 +596,7 @@ importers:
|
|||
'@logto/connector-facebook': ^0.1.0
|
||||
'@logto/connector-github': ^0.1.0
|
||||
'@logto/connector-google': ^0.1.0
|
||||
'@logto/connector-sendgrid-email': ^0.1.0
|
||||
'@logto/connector-types': ^0.1.0
|
||||
'@logto/connector-wechat': ^0.1.0
|
||||
'@logto/connector-wechat-native': ^0.1.0
|
||||
|
@ -623,6 +667,7 @@ importers:
|
|||
'@logto/connector-facebook': link:../connector-facebook
|
||||
'@logto/connector-github': link:../connector-github
|
||||
'@logto/connector-google': link:../connector-google
|
||||
'@logto/connector-sendgrid-email': link:../connector-sendgrid-mail
|
||||
'@logto/connector-types': link:../connector-types
|
||||
'@logto/connector-wechat': link:../connector-wechat
|
||||
'@logto/connector-wechat-native': link:../connector-wechat-native
|
||||
|
@ -3667,7 +3712,6 @@ packages:
|
|||
pacote: 11.3.5
|
||||
semver: 7.3.7
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -3836,7 +3880,6 @@ packages:
|
|||
whatwg-url: 8.7.0
|
||||
yargs-parser: 20.2.4
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -4034,7 +4077,6 @@ packages:
|
|||
npm-registry-fetch: 9.0.0
|
||||
npmlog: 4.1.2
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -4064,7 +4106,6 @@ packages:
|
|||
pify: 5.0.0
|
||||
read-package-json: 3.0.1
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -4199,7 +4240,6 @@ packages:
|
|||
pacote: 11.3.5
|
||||
semver: 7.3.7
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- encoding
|
||||
- supports-color
|
||||
dev: true
|
||||
|
@ -4498,8 +4538,6 @@ packages:
|
|||
promise-retry: 2.0.1
|
||||
semver: 7.3.7
|
||||
which: 2.0.2
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
dev: true
|
||||
|
||||
/@npmcli/installed-package-contents/1.0.7:
|
||||
|
@ -5514,7 +5552,6 @@ packages:
|
|||
stylelint-config-xo-scss: 0.15.0_zhymizk4kfitko2u2d4p3qwyee
|
||||
transitivePeerDependencies:
|
||||
- eslint
|
||||
- eslint-import-resolver-webpack
|
||||
- postcss
|
||||
- prettier
|
||||
- supports-color
|
||||
|
@ -5538,7 +5575,7 @@ packages:
|
|||
eslint-import-resolver-typescript: 2.5.0_rnagsyfcubvpoxo2ynj23pim7u
|
||||
eslint-plugin-consistent-default-export-name: 0.0.7
|
||||
eslint-plugin-eslint-comments: 3.2.0_eslint@8.10.0
|
||||
eslint-plugin-import: 2.25.4_sidoke6kqbkbdht6nlmwbfnany
|
||||
eslint-plugin-import: 2.25.4_eslint@8.10.0
|
||||
eslint-plugin-no-use-extend-native: 0.5.0
|
||||
eslint-plugin-node: 11.1.0_eslint@8.10.0
|
||||
eslint-plugin-prettier: 3.4.1_6pitu4b2tqihty6rv5qeiyb35m
|
||||
|
@ -5548,7 +5585,6 @@ packages:
|
|||
pkg-dir: 4.2.0
|
||||
prettier: 2.5.1
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: true
|
||||
|
@ -5570,7 +5606,7 @@ packages:
|
|||
eslint-import-resolver-typescript: 2.5.0_rnagsyfcubvpoxo2ynj23pim7u
|
||||
eslint-plugin-consistent-default-export-name: 0.0.7
|
||||
eslint-plugin-eslint-comments: 3.2.0_eslint@8.10.0
|
||||
eslint-plugin-import: 2.25.4_sidoke6kqbkbdht6nlmwbfnany
|
||||
eslint-plugin-import: 2.25.4_eslint@8.10.0
|
||||
eslint-plugin-no-use-extend-native: 0.5.0
|
||||
eslint-plugin-node: 11.1.0_eslint@8.10.0
|
||||
eslint-plugin-prettier: 3.4.1_6pitu4b2tqihty6rv5qeiyb35m
|
||||
|
@ -5580,7 +5616,6 @@ packages:
|
|||
pkg-dir: 4.2.0
|
||||
prettier: 2.5.1
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: true
|
||||
|
@ -5602,7 +5637,7 @@ packages:
|
|||
eslint-import-resolver-typescript: 2.5.0_rnagsyfcubvpoxo2ynj23pim7u
|
||||
eslint-plugin-consistent-default-export-name: 0.0.7
|
||||
eslint-plugin-eslint-comments: 3.2.0_eslint@8.10.0
|
||||
eslint-plugin-import: 2.25.4_sidoke6kqbkbdht6nlmwbfnany
|
||||
eslint-plugin-import: 2.25.4_eslint@8.10.0
|
||||
eslint-plugin-no-use-extend-native: 0.5.0
|
||||
eslint-plugin-node: 11.1.0_eslint@8.10.0
|
||||
eslint-plugin-prettier: 3.4.1_6pitu4b2tqihty6rv5qeiyb35m
|
||||
|
@ -5612,7 +5647,6 @@ packages:
|
|||
pkg-dir: 4.2.0
|
||||
prettier: 2.5.1
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: true
|
||||
|
@ -5672,7 +5706,6 @@ packages:
|
|||
- babel-jest
|
||||
- esbuild
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/@silverhand/jest-config/0.14.0_makj2rl6gt73u7koqro542qsmm:
|
||||
resolution: {integrity: sha512-zK9wh38/RL5iinPlbcZnjEuu8VfL7lQHDXFQ6Mos+zhN3YH0nsoHD6Faq41eHhUlQ6AkVSowov4hSs28S5RlWg==}
|
||||
|
@ -7665,8 +7698,6 @@ packages:
|
|||
qs: 6.9.7
|
||||
raw-body: 2.4.3
|
||||
type-is: 1.6.18
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/bonjour-service/1.0.11:
|
||||
|
@ -7842,8 +7873,6 @@ packages:
|
|||
ssri: 8.0.1
|
||||
tar: 6.1.11
|
||||
unique-filename: 1.1.1
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
dev: true
|
||||
|
||||
/cache-content-type/1.0.1:
|
||||
|
@ -8359,8 +8388,6 @@ packages:
|
|||
on-headers: 1.0.2
|
||||
safe-buffer: 5.1.2
|
||||
vary: 1.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/concat-map/0.0.1:
|
||||
|
@ -8936,22 +8963,12 @@ packages:
|
|||
|
||||
/debug/2.6.9:
|
||||
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.0.0
|
||||
dev: true
|
||||
|
||||
/debug/3.2.7:
|
||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
|
@ -9180,8 +9197,6 @@ packages:
|
|||
dependencies:
|
||||
address: 1.1.2
|
||||
debug: 2.6.9
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/detect-port/1.3.0:
|
||||
|
@ -9191,8 +9206,6 @@ packages:
|
|||
dependencies:
|
||||
address: 1.1.2
|
||||
debug: 2.6.9
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/dezalgo/1.0.3:
|
||||
|
@ -9671,8 +9684,6 @@ packages:
|
|||
dependencies:
|
||||
debug: 3.2.7
|
||||
resolve: 1.22.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-import-resolver-typescript/2.5.0_rnagsyfcubvpoxo2ynj23pim7u:
|
||||
|
@ -9684,7 +9695,7 @@ packages:
|
|||
dependencies:
|
||||
debug: 4.3.3
|
||||
eslint: 8.10.0
|
||||
eslint-plugin-import: 2.25.4_sidoke6kqbkbdht6nlmwbfnany
|
||||
eslint-plugin-import: 2.25.4_eslint@8.10.0
|
||||
glob: 7.2.0
|
||||
is-glob: 4.0.3
|
||||
resolve: 1.22.0
|
||||
|
@ -9693,31 +9704,12 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-module-utils/2.7.3_l62aq42yiamaj3cnpuf6avthf4:
|
||||
/eslint-module-utils/2.7.3:
|
||||
resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
eslint-import-resolver-node: '*'
|
||||
eslint-import-resolver-typescript: '*'
|
||||
eslint-import-resolver-webpack: '*'
|
||||
peerDependenciesMeta:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
eslint-import-resolver-node:
|
||||
optional: true
|
||||
eslint-import-resolver-typescript:
|
||||
optional: true
|
||||
eslint-import-resolver-webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.14.0_fo4uz55zgcu432252zy2gvpvcu
|
||||
debug: 3.2.7
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
eslint-import-resolver-typescript: 2.5.0_rnagsyfcubvpoxo2ynj23pim7u
|
||||
find-up: 2.1.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-consistent-default-export-name/0.0.7:
|
||||
|
@ -9752,24 +9744,19 @@ packages:
|
|||
ignore: 5.2.0
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-import/2.25.4_sidoke6kqbkbdht6nlmwbfnany:
|
||||
/eslint-plugin-import/2.25.4_eslint@8.10.0:
|
||||
resolution: {integrity: sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
|
||||
peerDependenciesMeta:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.14.0_fo4uz55zgcu432252zy2gvpvcu
|
||||
array-includes: 3.1.4
|
||||
array.prototype.flat: 1.2.5
|
||||
debug: 2.6.9
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.10.0
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
eslint-module-utils: 2.7.3_l62aq42yiamaj3cnpuf6avthf4
|
||||
eslint-module-utils: 2.7.3
|
||||
has: 1.0.3
|
||||
is-core-module: 2.8.1
|
||||
is-glob: 4.0.3
|
||||
|
@ -9777,10 +9764,6 @@ packages:
|
|||
object.values: 1.1.5
|
||||
resolve: 1.22.0
|
||||
tsconfig-paths: 3.13.0
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-typescript
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-no-use-extend-native/0.5.0:
|
||||
|
@ -10172,8 +10155,6 @@ packages:
|
|||
type-is: 1.6.18
|
||||
utils-merge: 1.0.1
|
||||
vary: 1.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/extend-shallow/2.0.1:
|
||||
|
@ -10370,8 +10351,6 @@ packages:
|
|||
parseurl: 1.3.3
|
||||
statuses: 1.5.0
|
||||
unpipe: 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/find-cache-dir/3.3.2:
|
||||
|
@ -13082,7 +13061,6 @@ packages:
|
|||
import-local: 3.1.0
|
||||
npmlog: 4.1.2
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- encoding
|
||||
- supports-color
|
||||
dev: true
|
||||
|
@ -13117,7 +13095,6 @@ packages:
|
|||
npm-package-arg: 8.1.5
|
||||
npm-registry-fetch: 11.0.0
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -13131,7 +13108,6 @@ packages:
|
|||
semver: 7.3.7
|
||||
ssri: 8.0.1
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -13500,7 +13476,6 @@ packages:
|
|||
socks-proxy-agent: 5.0.1
|
||||
ssri: 8.0.1
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -13525,7 +13500,6 @@ packages:
|
|||
socks-proxy-agent: 6.1.1
|
||||
ssri: 8.0.1
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -14598,7 +14572,6 @@ packages:
|
|||
minizlib: 2.1.2
|
||||
npm-package-arg: 8.1.5
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -14615,7 +14588,6 @@ packages:
|
|||
minizlib: 2.1.2
|
||||
npm-package-arg: 8.1.5
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -15054,7 +15026,6 @@ packages:
|
|||
ssri: 8.0.1
|
||||
tar: 6.1.11
|
||||
transitivePeerDependencies:
|
||||
- bluebird
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -15447,8 +15418,6 @@ packages:
|
|||
async: 2.6.3
|
||||
debug: 3.2.7
|
||||
mkdirp: 0.5.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/postcss-calc/8.2.4_postcss@8.4.12:
|
||||
|
@ -16135,11 +16104,6 @@ packages:
|
|||
|
||||
/promise-inflight/1.0.1:
|
||||
resolution: {integrity: sha1-mEcocL8igTL8vdhoEputEsPAKeM=}
|
||||
peerDependencies:
|
||||
bluebird: '*'
|
||||
peerDependenciesMeta:
|
||||
bluebird:
|
||||
optional: true
|
||||
dev: true
|
||||
|
||||
/promise-retry/2.0.1:
|
||||
|
@ -16417,7 +16381,6 @@ packages:
|
|||
text-table: 0.2.0
|
||||
transitivePeerDependencies:
|
||||
- eslint
|
||||
- supports-color
|
||||
- typescript
|
||||
- vue-template-compiler
|
||||
- webpack
|
||||
|
@ -17512,8 +17475,6 @@ packages:
|
|||
on-finished: 2.3.0
|
||||
range-parser: 1.2.1
|
||||
statuses: 1.5.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/serialize-error/7.0.1:
|
||||
|
@ -17560,8 +17521,6 @@ packages:
|
|||
http-errors: 1.6.3
|
||||
mime-types: 2.1.35
|
||||
parseurl: 1.3.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/serve-static/1.14.2:
|
||||
|
@ -17572,8 +17531,6 @@ packages:
|
|||
escape-html: 1.0.3
|
||||
parseurl: 1.3.3
|
||||
send: 0.17.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/set-blocking/2.0.0:
|
||||
|
@ -18809,7 +18766,7 @@ packages:
|
|||
'@types/jest': 27.4.1
|
||||
bs-logger: 0.2.6
|
||||
fast-json-stable-stringify: 2.1.0
|
||||
jest: 27.5.1_ts-node@10.7.0
|
||||
jest: 27.5.1
|
||||
jest-util: 27.5.1
|
||||
json5: 2.2.1
|
||||
lodash.memoize: 4.1.2
|
||||
|
@ -18817,7 +18774,6 @@ packages:
|
|||
semver: 7.3.5
|
||||
typescript: 4.6.4
|
||||
yargs-parser: 20.2.9
|
||||
dev: true
|
||||
|
||||
/ts-jest/27.1.1_makj2rl6gt73u7koqro542qsmm:
|
||||
resolution: {integrity: sha512-Ds0VkB+cB+8g2JUmP/GKWndeZcCKrbe6jzolGrVWdqVUFByY/2KDHqxJ7yBSon7hDB1TA4PXxjfZ+JjzJisvgA==}
|
||||
|
@ -19008,6 +18964,21 @@ packages:
|
|||
typescript: 4.6.3
|
||||
dev: true
|
||||
|
||||
/tsc-watch/5.0.3_typescript@4.6.4:
|
||||
resolution: {integrity: sha512-Hz2UawwELMSLOf0xHvAFc7anLeMw62cMVXr1flYmhRuOhOyOljwmb1l/O60ZwRyy1k7N1iC1mrn1QYM2zITfuw==}
|
||||
engines: {node: '>=8.17.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
dependencies:
|
||||
cross-spawn: 7.0.3
|
||||
node-cleanup: 2.1.2
|
||||
ps-tree: 1.2.0
|
||||
string-argv: 0.1.2
|
||||
strip-ansi: 6.0.1
|
||||
typescript: 4.6.4
|
||||
dev: true
|
||||
|
||||
/tsconfig-paths/3.13.0:
|
||||
resolution: {integrity: sha512-nWuffZppoaYK0vQ1SQmkSsQzJoHA4s6uzdb2waRpD806x9yfq153AdVsWz4je2qZcW+pENrMQXbGQ3sMCkXuhw==}
|
||||
dependencies:
|
||||
|
|
Loading…
Add table
Reference in a new issue