mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
feat: mailgun connector (#4281)
* feat: mailgun connector * refactor: support png as connector logo * chore: add changesets * chore: fix error * chore: translate phrases
This commit is contained in:
parent
263ea256b9
commit
5b34338484
35 changed files with 978 additions and 144 deletions
5
.changeset/quiet-yaks-wink.md
Normal file
5
.changeset/quiet-yaks-wink.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"@logto/connector-mailgun": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
add Mailgun connector
|
5
.changeset/spicy-maps-warn.md
Normal file
5
.changeset/spicy-maps-warn.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"@logto/connector-sendgrid-email": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
improve content
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
@ -39,6 +39,8 @@
|
||||||
"stylelint",
|
"stylelint",
|
||||||
"timestamptz",
|
"timestamptz",
|
||||||
"topbar",
|
"topbar",
|
||||||
"withtyped"
|
"withtyped",
|
||||||
|
"sendgrid",
|
||||||
|
"mailgun",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ import type {
|
||||||
} from '@logto/connector-kit';
|
} from '@logto/connector-kit';
|
||||||
import { ConnectorError, ConnectorErrorCodes, ConnectorType } from '@logto/connector-kit';
|
import { ConnectorError, ConnectorErrorCodes, ConnectorType } from '@logto/connector-kit';
|
||||||
|
|
||||||
|
import { consoleLog } from '../utils.js';
|
||||||
|
|
||||||
import { notImplemented } from './consts.js';
|
import { notImplemented } from './consts.js';
|
||||||
import type { ConnectorFactory } from './types.js';
|
import type { ConnectorFactory } from './types.js';
|
||||||
|
|
||||||
|
@ -29,10 +31,18 @@ export function validateConnectorModule(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const supportedImageTypes = Object.freeze({
|
||||||
|
'.svg': 'image/svg+xml',
|
||||||
|
'.png': 'image/png',
|
||||||
|
});
|
||||||
|
|
||||||
|
const isSupportedImageType = (extension: string): extension is keyof typeof supportedImageTypes =>
|
||||||
|
Object.keys(supportedImageTypes).includes(extension);
|
||||||
|
|
||||||
export const readUrl = async (
|
export const readUrl = async (
|
||||||
url: string,
|
url: string,
|
||||||
baseUrl: string,
|
baseUrl: string,
|
||||||
type: 'text' | 'svg'
|
type: 'text' | 'image'
|
||||||
): Promise<string> => {
|
): Promise<string> => {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return url;
|
return url;
|
||||||
|
@ -46,10 +56,20 @@ export const readUrl = async (
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'svg') {
|
if (type === 'image') {
|
||||||
const data = await readFile(path.join(baseUrl, url));
|
const filePath = path.join(baseUrl, url);
|
||||||
|
const extension = path.extname(filePath);
|
||||||
|
|
||||||
return `data:image/svg+xml;base64,${data.toString('base64')}`;
|
if (!isSupportedImageType(extension)) {
|
||||||
|
consoleLog.warn(
|
||||||
|
`[readUrl] unexpected image type: ${filePath}, only support ".svg" and ".png". Falling back to empty string.`
|
||||||
|
);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await readFile(filePath);
|
||||||
|
|
||||||
|
return `data:${supportedImageTypes[extension]};base64,${data.toString('base64')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return readFile(path.join(baseUrl, url), 'utf8');
|
return readFile(path.join(baseUrl, url), 'utf8');
|
||||||
|
@ -61,8 +81,8 @@ export const parseMetadata = async (
|
||||||
): Promise<AllConnector['metadata']> => {
|
): Promise<AllConnector['metadata']> => {
|
||||||
return {
|
return {
|
||||||
...metadata,
|
...metadata,
|
||||||
logo: await readUrl(metadata.logo, packagePath, 'svg'),
|
logo: await readUrl(metadata.logo, packagePath, 'image'),
|
||||||
logoDark: metadata.logoDark && (await readUrl(metadata.logoDark, packagePath, 'svg')),
|
logoDark: metadata.logoDark && (await readUrl(metadata.logoDark, packagePath, 'image')),
|
||||||
readme: await readUrl(metadata.readme, packagePath, 'text'),
|
readme: await readUrl(metadata.readme, packagePath, 'text'),
|
||||||
configTemplate:
|
configTemplate:
|
||||||
metadata.configTemplate && (await readUrl(metadata.configTemplate, packagePath, 'text')),
|
metadata.configTemplate && (await readUrl(metadata.configTemplate, packagePath, 'text')),
|
||||||
|
|
1
packages/connectors/connector-mailgun/CHANGELOG.md
Normal file
1
packages/connectors/connector-mailgun/CHANGELOG.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# @logto/connector-mailgun
|
101
packages/connectors/connector-mailgun/README.md
Normal file
101
packages/connectors/connector-mailgun/README.md
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
# Mailgun email connector
|
||||||
|
|
||||||
|
The official Logto connector for Mailgun email service.
|
||||||
|
|
||||||
|
**Table of contents**
|
||||||
|
|
||||||
|
- [Mailgun email connector](#mailgun-email-connector)
|
||||||
|
- [Prerequisites](#prerequisites)
|
||||||
|
- [Basic configuration](#basic-configuration)
|
||||||
|
- [Deliveries](#deliveries)
|
||||||
|
- [Config object](#config-object)
|
||||||
|
- [Usage types](#usage-types)
|
||||||
|
- [Content config](#content-config)
|
||||||
|
- [Example](#example)
|
||||||
|
- [Test Mailgun email connector](#test-mailgun-email-connector)
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- A [Mailgun](https://www.mailgun.com/) account
|
||||||
|
- An API key from your Mailgun account, requires the permission to send messages (emails). See [Where Can I Find My API Key and SMTP Credentials?](https://help.mailgun.com/hc/en-us/articles/203380100-Where-Can-I-Find-My-API-Key-and-SMTP-Credentials-) for more information.
|
||||||
|
|
||||||
|
## Basic configuration
|
||||||
|
|
||||||
|
- Fill out the `domain` field with the domain you have registered in your Mailgun account. This value can be found in the **Domains** section of the Mailgun dashboard. The domain should be in the format `example.com`, without the `https://` or `http://` prefix.
|
||||||
|
- Fill out the `apiKey` field with the API key you have generated in your Mailgun account.
|
||||||
|
- Fill out the `from` field with the email address you want to send emails from. This email address must be registered in your Mailgun account. The email address should be in the format `Sender Name <sender@example.com>`.
|
||||||
|
|
||||||
|
## Deliveries
|
||||||
|
|
||||||
|
### Config object
|
||||||
|
|
||||||
|
The "Deliveries" section allows you to configure the content of the emails to be sent in different scenarios. It is a JSON key-value map where the key is the usage type and the value is an object containing the content config for the email to be sent.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"<usage-type>": {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage types
|
||||||
|
|
||||||
|
The following usage types are supported:
|
||||||
|
|
||||||
|
- `Register`: The email to be sent when a user is registering.
|
||||||
|
- `SignIn`: The email to be sent when a user is signing in.
|
||||||
|
- `ForgotPassword`: The email to be sent when a user is resetting their password.
|
||||||
|
- `Generic`: The email to be sent when a user is performing a generic action, for example, testing the email connector.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
> If the usage type is not specified in the deliveries config, the generic email will be sent. If the generic email is not specified, the connector will return an error.
|
||||||
|
|
||||||
|
### Content config
|
||||||
|
|
||||||
|
The connector supports both direct HTML content and Mailgun template. You can use one of them for each usage type.
|
||||||
|
|
||||||
|
In both subject and content, you can use the `{{code}}` placeholder to insert the verification code.
|
||||||
|
|
||||||
|
To use direct HTML content, fill out the following fields:
|
||||||
|
|
||||||
|
- `subject`: The subject of the email to be sent.
|
||||||
|
- `replyTo`: The email address to be used as the reply-to address.
|
||||||
|
- `html`: (Required) The HTML content of the email to be sent.
|
||||||
|
- `text`: The plain text version of the email to be sent.
|
||||||
|
|
||||||
|
To use Mailgun template, fill out the following fields:
|
||||||
|
|
||||||
|
- `subject`: The subject of the email to be sent.
|
||||||
|
- `replyTo`: The email address to be used as the reply-to address.
|
||||||
|
- `template`: (Required) The name of the Mailgun template to be used.
|
||||||
|
- `variables`: The variables to be passed to the Mailgun template. Should be a JSON key-value map since it will be stringified before sending to Mailgun. Note there's no need to include the `code` variable since it will be automatically added by the connector.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
The following is an example of the deliveries config:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Register": {
|
||||||
|
"subject": "{{code}} is your verification code",
|
||||||
|
"replyTo": "Foo <foo@bar.com>",
|
||||||
|
"html": "<h1>Welcome to Logto</h1><p>Your verification code is {{code}}.</p>",
|
||||||
|
"text": "Welcome to Logto. Your verification code is {{code}}."
|
||||||
|
},
|
||||||
|
"SignIn": {
|
||||||
|
"subject": "Welcome back to Logto",
|
||||||
|
"replyTo": "Foo <foo@bar.com>",
|
||||||
|
"template": "logto-sign-in",
|
||||||
|
"variables": {
|
||||||
|
"bar": "baz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Mailgun email connector
|
||||||
|
|
||||||
|
You can type in an email address and click on "Send" to see whether the settings can work before "Save and Done".
|
||||||
|
|
||||||
|
That's it. Don't forget to [Enable connector in sign-in experience](https://docs.logto.io/docs/tutorials/get-started/passwordless-sign-in-by-adding-connectors#enable-sms-or-email-passwordless-sign-in)
|
BIN
packages/connectors/connector-mailgun/logo.png
Normal file
BIN
packages/connectors/connector-mailgun/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
51
packages/connectors/connector-mailgun/package.json
Normal file
51
packages/connectors/connector-mailgun/package.json
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "@logto/connector-mailgun",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Mailgun connector for Logto.",
|
||||||
|
"author": "Silverhand Inc. <contact@silverhand.io>",
|
||||||
|
"dependencies": {
|
||||||
|
"@logto/connector-kit": "workspace:^1.1.0"
|
||||||
|
},
|
||||||
|
"main": "./lib/index.js",
|
||||||
|
"module": "./lib/index.js",
|
||||||
|
"exports": "./lib/index.js",
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"type": "module",
|
||||||
|
"files": [
|
||||||
|
"lib",
|
||||||
|
"docs",
|
||||||
|
"logo.svg",
|
||||||
|
"logo-dark.svg"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"precommit": "lint-staged",
|
||||||
|
"build:test": "rm -rf lib/ && tsc -p tsconfig.test.json --sourcemap",
|
||||||
|
"build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c",
|
||||||
|
"dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput --incremental",
|
||||||
|
"lint": "eslint --ext .ts src",
|
||||||
|
"lint:report": "pnpm lint --format json --output-file report.json",
|
||||||
|
"test:only": "NODE_OPTIONS=--experimental-vm-modules jest",
|
||||||
|
"test": "pnpm build:test && pnpm test:only",
|
||||||
|
"test:ci": "pnpm test:only --silent --coverage",
|
||||||
|
"prepublishOnly": "pnpm build"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.12.0"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": "@silverhand",
|
||||||
|
"settings": {
|
||||||
|
"import/core-modules": [
|
||||||
|
"@silverhand/essentials",
|
||||||
|
"got",
|
||||||
|
"nock",
|
||||||
|
"snakecase-keys",
|
||||||
|
"zod"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"prettier": "@silverhand/eslint-config/.prettierrc",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
66
packages/connectors/connector-mailgun/src/constant.ts
Normal file
66
packages/connectors/connector-mailgun/src/constant.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import type { ConnectorMetadata } from '@logto/connector-kit';
|
||||||
|
import { ConnectorConfigFormItemType } from '@logto/connector-kit';
|
||||||
|
|
||||||
|
export const endpoint = 'https://api.sendgrid.com/v3/mail/send';
|
||||||
|
|
||||||
|
export const defaultMetadata: ConnectorMetadata = {
|
||||||
|
id: 'mailgun-email',
|
||||||
|
target: 'mailgun-email',
|
||||||
|
platform: null,
|
||||||
|
name: {
|
||||||
|
en: 'Mailgun',
|
||||||
|
},
|
||||||
|
logo: './logo.png',
|
||||||
|
logoDark: null,
|
||||||
|
description: {
|
||||||
|
en: 'Mailgun is an email delivery service for sending, receiving, and tracking emails.',
|
||||||
|
},
|
||||||
|
readme: './README.md',
|
||||||
|
formItems: [
|
||||||
|
{
|
||||||
|
key: 'domain',
|
||||||
|
label: 'Domain',
|
||||||
|
type: ConnectorConfigFormItemType.Text,
|
||||||
|
required: true,
|
||||||
|
placeholder: 'https://your-mailgun-domain.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'apiKey',
|
||||||
|
label: 'API Key',
|
||||||
|
type: ConnectorConfigFormItemType.Text,
|
||||||
|
required: true,
|
||||||
|
placeholder: '<your-mailgun-api-key>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'from',
|
||||||
|
label: 'Email address to send from',
|
||||||
|
type: ConnectorConfigFormItemType.Text,
|
||||||
|
required: true,
|
||||||
|
placeholder: 'Sender Name <foo@example.com>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'deliveries',
|
||||||
|
label: 'Deliveries',
|
||||||
|
type: ConnectorConfigFormItemType.Json,
|
||||||
|
required: true,
|
||||||
|
defaultValue: {
|
||||||
|
SignIn: {
|
||||||
|
subject: 'Logto sign-in template {{code}}',
|
||||||
|
html: 'Your Logto sign-in verification code is {{code}}. The code will remain active for 10 minutes.',
|
||||||
|
},
|
||||||
|
Register: {
|
||||||
|
subject: 'Logto sign-up template {{code}}',
|
||||||
|
html: 'Your Logto sign-up verification code is {{code}}. The code will remain active for 10 minutes.',
|
||||||
|
},
|
||||||
|
ForgotPassword: {
|
||||||
|
subject: 'Logto reset password template {{code}}',
|
||||||
|
html: 'Your Logto reset password verification code is {{code}}. The code will remain active for 10 minutes.',
|
||||||
|
},
|
||||||
|
Generic: {
|
||||||
|
subject: 'Logto generic template {{code}}',
|
||||||
|
html: 'Your Logto generic verification code is {{code}}. The code will remain active for 10 minutes.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
190
packages/connectors/connector-mailgun/src/index.test.ts
Normal file
190
packages/connectors/connector-mailgun/src/index.test.ts
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
import nock from 'nock';
|
||||||
|
|
||||||
|
import { VerificationCodeType } from '@logto/connector-kit';
|
||||||
|
|
||||||
|
import createMailgunConnector from './index.js';
|
||||||
|
import { type MailgunConfig } from './types.js';
|
||||||
|
|
||||||
|
const { jest } = import.meta;
|
||||||
|
|
||||||
|
const getConfig = jest.fn();
|
||||||
|
|
||||||
|
const domain = 'example.com';
|
||||||
|
const apiKey = 'apiKey';
|
||||||
|
const connector = await createMailgunConnector({
|
||||||
|
getConfig,
|
||||||
|
});
|
||||||
|
const baseConfig: Partial<MailgunConfig> = {
|
||||||
|
domain: 'example.com',
|
||||||
|
apiKey: 'apiKey',
|
||||||
|
from: 'foo@example.com',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nock helper to assert request auth and body.
|
||||||
|
*
|
||||||
|
* @param expectation - The expected request body.
|
||||||
|
*/
|
||||||
|
const nockMessages = (expectation: Record<string, string | string[] | undefined>) =>
|
||||||
|
nock('https://api.mailgun.net')
|
||||||
|
.post(`/v3/${domain}/messages`)
|
||||||
|
.basicAuth({ user: 'api', pass: apiKey })
|
||||||
|
.reply((_, body, callback) => {
|
||||||
|
const params = new URLSearchParams(body);
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(expectation)) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
expect(value).toEqual(params.getAll(key));
|
||||||
|
} else {
|
||||||
|
expect(params.get(key)).toBe(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, [200, 'OK']);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Maligun connector', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
nock.cleanAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send email with raw data', async () => {
|
||||||
|
nockMessages({
|
||||||
|
from: baseConfig.from,
|
||||||
|
to: 'bar@example.com',
|
||||||
|
subject: 'Verification code is 123456',
|
||||||
|
html: '<p>Your verification code is 123456</p>',
|
||||||
|
'h:Reply-To': 'baz@example.com',
|
||||||
|
});
|
||||||
|
|
||||||
|
getConfig.mockResolvedValue({
|
||||||
|
...baseConfig,
|
||||||
|
deliveries: {
|
||||||
|
[VerificationCodeType.Generic]: {
|
||||||
|
subject: 'Verification code is {{code}}',
|
||||||
|
html: '<p>Your verification code is {{code}}</p>',
|
||||||
|
replyTo: 'baz@example.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await connector.sendMessage({
|
||||||
|
to: 'bar@example.com',
|
||||||
|
type: VerificationCodeType.Generic,
|
||||||
|
payload: { code: '123456' },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send email with template', async () => {
|
||||||
|
nockMessages({
|
||||||
|
from: 'foo@example.com',
|
||||||
|
to: 'bar@example.com',
|
||||||
|
subject: 'Verification code is 123456',
|
||||||
|
template: 'template',
|
||||||
|
'h:X-Mailgun-Variables': JSON.stringify({ foo: 'bar', code: '123456' }),
|
||||||
|
});
|
||||||
|
|
||||||
|
getConfig.mockResolvedValue({
|
||||||
|
...baseConfig,
|
||||||
|
deliveries: {
|
||||||
|
[VerificationCodeType.Generic]: {
|
||||||
|
template: 'template',
|
||||||
|
variables: { foo: 'bar' },
|
||||||
|
subject: 'Verification code is {{code}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await connector.sendMessage({
|
||||||
|
to: 'bar@example.com',
|
||||||
|
type: VerificationCodeType.Generic,
|
||||||
|
payload: {
|
||||||
|
code: '123456',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fall back to generic template if type not found', async () => {
|
||||||
|
nockMessages({
|
||||||
|
from: 'foo@example.com',
|
||||||
|
to: 'bar@example.com',
|
||||||
|
subject: 'Verification code is 123456',
|
||||||
|
template: 'template',
|
||||||
|
'h:X-Mailgun-Variables': JSON.stringify({ foo: 'bar', code: '123456' }),
|
||||||
|
});
|
||||||
|
|
||||||
|
getConfig.mockResolvedValue({
|
||||||
|
...baseConfig,
|
||||||
|
deliveries: {
|
||||||
|
[VerificationCodeType.Generic]: {
|
||||||
|
template: 'template',
|
||||||
|
variables: { foo: 'bar' },
|
||||||
|
subject: 'Verification code is {{code}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await connector.sendMessage({
|
||||||
|
to: 'bar@example.com',
|
||||||
|
type: VerificationCodeType.ForgotPassword,
|
||||||
|
payload: {
|
||||||
|
code: '123456',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw error if template not found or type not supported', async () => {
|
||||||
|
getConfig.mockResolvedValue({
|
||||||
|
...baseConfig,
|
||||||
|
deliveries: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
connector.sendMessage({
|
||||||
|
to: '',
|
||||||
|
type: VerificationCodeType.Generic,
|
||||||
|
payload: {
|
||||||
|
code: '123456',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).rejects.toThrowErrorMatchingInlineSnapshot('"ConnectorError: template_not_found"');
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
connector.sendMessage({
|
||||||
|
to: '',
|
||||||
|
// @ts-expect-error Invalid type
|
||||||
|
type: 'foo',
|
||||||
|
payload: {
|
||||||
|
code: '123456',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).rejects.toThrowErrorMatchingInlineSnapshot('"ConnectorError: template_not_supported"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw error if mailgun returns error', async () => {
|
||||||
|
getConfig.mockResolvedValue({
|
||||||
|
...baseConfig,
|
||||||
|
deliveries: {
|
||||||
|
[VerificationCodeType.Generic]: {
|
||||||
|
template: 'template',
|
||||||
|
variables: { foo: 'bar' },
|
||||||
|
subject: 'Verification code is {{code}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
nock('https://api.mailgun.net').post(`/v3/${domain}/messages`).reply(400, { message: 'error' });
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
connector.sendMessage({
|
||||||
|
to: '',
|
||||||
|
type: VerificationCodeType.Generic,
|
||||||
|
payload: {
|
||||||
|
code: '123456',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||||
|
'"ConnectorError: {"statusCode":400,"body":"{\\"message\\":\\"error\\"}"}"'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
102
packages/connectors/connector-mailgun/src/index.ts
Normal file
102
packages/connectors/connector-mailgun/src/index.ts
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
import { got, HTTPError } from 'got';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
GetConnectorConfig,
|
||||||
|
SendMessageFunction,
|
||||||
|
CreateConnector,
|
||||||
|
EmailConnector,
|
||||||
|
} from '@logto/connector-kit';
|
||||||
|
import {
|
||||||
|
ConnectorError,
|
||||||
|
ConnectorErrorCodes,
|
||||||
|
ConnectorType,
|
||||||
|
validateConfig,
|
||||||
|
VerificationCodeType,
|
||||||
|
} from '@logto/connector-kit';
|
||||||
|
|
||||||
|
import { defaultMetadata } from './constant.js';
|
||||||
|
import {
|
||||||
|
type DeliveryConfig,
|
||||||
|
mailgunConfigGuard,
|
||||||
|
supportTemplateGuard,
|
||||||
|
type MailgunConfig,
|
||||||
|
} from './types.js';
|
||||||
|
|
||||||
|
const removeUndefinedKeys = (object: Record<string, unknown>) =>
|
||||||
|
Object.fromEntries(Object.entries(object).filter(([, value]) => value !== undefined));
|
||||||
|
|
||||||
|
const getDataFromDeliveryConfig = (
|
||||||
|
{ subject, replyTo, ...rest }: DeliveryConfig,
|
||||||
|
code: string
|
||||||
|
): Record<string, string | undefined> => {
|
||||||
|
const commonData = {
|
||||||
|
subject: subject?.replaceAll('{{code}}', code),
|
||||||
|
'h:Reply-To': replyTo,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ('template' in rest) {
|
||||||
|
return {
|
||||||
|
...commonData,
|
||||||
|
template: rest.template,
|
||||||
|
'h:X-Mailgun-Variables': JSON.stringify({ ...rest.variables, code }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...commonData,
|
||||||
|
html: rest.html.replaceAll('{{code}}', code),
|
||||||
|
text: rest.text?.replaceAll('{{code}}', code),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendMessage = (getConfig: GetConnectorConfig): SendMessageFunction => {
|
||||||
|
return async ({ to, type: typeInput, payload: { code } }, inputConfig) => {
|
||||||
|
const config = inputConfig ?? (await getConfig(defaultMetadata.id));
|
||||||
|
validateConfig<MailgunConfig>(config, mailgunConfigGuard);
|
||||||
|
|
||||||
|
const { domain, apiKey, from, deliveries } = config;
|
||||||
|
const type = supportTemplateGuard.safeParse(typeInput);
|
||||||
|
|
||||||
|
if (!type.success) {
|
||||||
|
throw new ConnectorError(ConnectorErrorCodes.TemplateNotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
const template = deliveries[type.data] ?? deliveries[VerificationCodeType.Generic];
|
||||||
|
|
||||||
|
if (!template) {
|
||||||
|
throw new ConnectorError(ConnectorErrorCodes.TemplateNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await got.post(`https://api.mailgun.net/v3/${domain}/messages`, {
|
||||||
|
username: 'api',
|
||||||
|
password: apiKey,
|
||||||
|
form: {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
...removeUndefinedKeys(getDataFromDeliveryConfig(template, code)),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof HTTPError) {
|
||||||
|
const {
|
||||||
|
response: { body, statusCode },
|
||||||
|
} = error;
|
||||||
|
|
||||||
|
throw new ConnectorError(ConnectorErrorCodes.General, { statusCode, body });
|
||||||
|
}
|
||||||
|
throw new ConnectorError(ConnectorErrorCodes.General, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const createSendGridMailConnector: CreateConnector<EmailConnector> = async ({ getConfig }) => {
|
||||||
|
return {
|
||||||
|
metadata: defaultMetadata,
|
||||||
|
type: ConnectorType.Email,
|
||||||
|
configGuard: mailgunConfigGuard,
|
||||||
|
sendMessage: sendMessage(getConfig),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createSendGridMailConnector;
|
65
packages/connectors/connector-mailgun/src/type.test.ts
Normal file
65
packages/connectors/connector-mailgun/src/type.test.ts
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import { VerificationCodeType } from '@logto/connector-kit';
|
||||||
|
|
||||||
|
import { mailgunConfigGuard } from './types.js';
|
||||||
|
|
||||||
|
describe('Mailgun config guard', () => {
|
||||||
|
it('should pass with valid config', () => {
|
||||||
|
const validConfig = {
|
||||||
|
domain: 'example.com',
|
||||||
|
apiKey: 'key',
|
||||||
|
from: 'from',
|
||||||
|
deliveries: {
|
||||||
|
[VerificationCodeType.SignIn]: {
|
||||||
|
html: 'html',
|
||||||
|
subject: 'subject',
|
||||||
|
},
|
||||||
|
[VerificationCodeType.Register]: {
|
||||||
|
template: 'template',
|
||||||
|
variables: {},
|
||||||
|
subject: 'subject',
|
||||||
|
},
|
||||||
|
[VerificationCodeType.ForgotPassword]: {
|
||||||
|
html: 'html',
|
||||||
|
text: 'text',
|
||||||
|
subject: 'subject',
|
||||||
|
},
|
||||||
|
[VerificationCodeType.Generic]: {
|
||||||
|
template: 'template',
|
||||||
|
variables: {},
|
||||||
|
subject: 'subject',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(() => mailgunConfigGuard.parse(validConfig)).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow partial template config', () => {
|
||||||
|
const validConfig = {
|
||||||
|
domain: 'example.com',
|
||||||
|
apiKey: 'key',
|
||||||
|
from: 'from',
|
||||||
|
deliveries: {
|
||||||
|
[VerificationCodeType.SignIn]: {
|
||||||
|
html: 'html',
|
||||||
|
subject: 'subject',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(() => mailgunConfigGuard.parse(validConfig)).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail with invalid config', () => {
|
||||||
|
const invalidConfig = {
|
||||||
|
domain: 'example.com',
|
||||||
|
apiKey: 'key',
|
||||||
|
from: 'from',
|
||||||
|
deliveries: {
|
||||||
|
[VerificationCodeType.ForgotPassword]: {
|
||||||
|
text: 'text',
|
||||||
|
subject: 'subject',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(() => mailgunConfigGuard.parse(invalidConfig)).toThrow();
|
||||||
|
});
|
||||||
|
});
|
76
packages/connectors/connector-mailgun/src/types.ts
Normal file
76
packages/connectors/connector-mailgun/src/types.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { VerificationCodeType } from '@logto/connector-kit';
|
||||||
|
|
||||||
|
export const supportTemplateGuard = z.enum([
|
||||||
|
VerificationCodeType.SignIn,
|
||||||
|
VerificationCodeType.Register,
|
||||||
|
VerificationCodeType.ForgotPassword,
|
||||||
|
VerificationCodeType.Generic,
|
||||||
|
]);
|
||||||
|
|
||||||
|
type SupportTemplate = z.infer<typeof supportTemplateGuard>;
|
||||||
|
|
||||||
|
type CommonEmailConfig = {
|
||||||
|
/** Subject of the message. */
|
||||||
|
subject?: string;
|
||||||
|
/** The email address for recipients to reply to. */
|
||||||
|
replyTo?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The data to send a regular message (email). */
|
||||||
|
type RawEmailConfig = CommonEmailConfig & {
|
||||||
|
/** HTML version of the message. */
|
||||||
|
html: string;
|
||||||
|
/** Text version of the message. */
|
||||||
|
text?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The data to send a template message (email). */
|
||||||
|
type TemplateEmailConfig = CommonEmailConfig & {
|
||||||
|
/** The template name. */
|
||||||
|
template: string;
|
||||||
|
/** The template variables. */
|
||||||
|
variables?: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Config object fot a specific template type. */
|
||||||
|
export type DeliveryConfig = RawEmailConfig | TemplateEmailConfig;
|
||||||
|
|
||||||
|
const templateConfigGuard = z.union([
|
||||||
|
z.object({
|
||||||
|
html: z.string(),
|
||||||
|
text: z.string().optional(),
|
||||||
|
subject: z.string().optional(),
|
||||||
|
replyTo: z.string().optional(),
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
template: z.string(),
|
||||||
|
variables: z.record(z.unknown()).optional(),
|
||||||
|
subject: z.string().optional(),
|
||||||
|
replyTo: z.string().optional(),
|
||||||
|
}),
|
||||||
|
]) satisfies z.ZodType<DeliveryConfig>;
|
||||||
|
|
||||||
|
export type MailgunConfig = {
|
||||||
|
/** Mailgun domain. */
|
||||||
|
domain: string;
|
||||||
|
/** Mailgun API key. */
|
||||||
|
apiKey: string;
|
||||||
|
/** The sender of the email, in the form `Sender Name <me@samples.mailgun.org>`. */
|
||||||
|
from: string;
|
||||||
|
/**
|
||||||
|
* The template config object for each template type, while the key is the template type
|
||||||
|
* and the value is the config object.
|
||||||
|
*/
|
||||||
|
deliveries: Partial<Record<SupportTemplate, DeliveryConfig>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mailgunConfigGuard = z.object({
|
||||||
|
domain: z.string(),
|
||||||
|
apiKey: z.string(),
|
||||||
|
from: z.string(),
|
||||||
|
// Although the type it's expected, this guard should infer required keys. Looks like a mis-implemented in zod.
|
||||||
|
// See https://github.com/colinhacks/zod/issues/2623
|
||||||
|
deliveries: z.record(supportTemplateGuard, templateConfigGuard),
|
||||||
|
}) satisfies z.ZodType<MailgunConfig>;
|
|
@ -1,10 +1,10 @@
|
||||||
# SendGrid mail connector
|
# SendGrid email connector
|
||||||
|
|
||||||
The official Logto connector for SendGrid email service.
|
The official Logto connector for SendGrid email service.
|
||||||
|
|
||||||
**Table of contents**
|
**Table of contents**
|
||||||
|
|
||||||
- [SendGrid mail connector](#sendgrid-mail-connector)
|
- [SendGrid email connector](#sendgrid-email-connector)
|
||||||
- [Get started](#get-started)
|
- [Get started](#get-started)
|
||||||
- [Register SendGrid account](#register-sendgrid-account)
|
- [Register SendGrid account](#register-sendgrid-account)
|
||||||
- [Verify senders](#verify-senders)
|
- [Verify senders](#verify-senders)
|
||||||
|
|
|
@ -8,10 +8,8 @@ export const defaultMetadata: ConnectorMetadata = {
|
||||||
target: 'sendgrid-mail',
|
target: 'sendgrid-mail',
|
||||||
platform: null,
|
platform: null,
|
||||||
name: {
|
name: {
|
||||||
en: 'SendGrid Mail Service',
|
en: 'SendGrid Email',
|
||||||
'zh-CN': 'SendGrid 邮件服务',
|
'zh-CN': 'SendGrid 邮件',
|
||||||
'tr-TR': 'SendGrid EMail Servisi',
|
|
||||||
ko: 'SendGrid 메일 서비스',
|
|
||||||
},
|
},
|
||||||
logo: './logo.svg',
|
logo: './logo.svg',
|
||||||
logoDark: null,
|
logoDark: null,
|
||||||
|
@ -28,21 +26,21 @@ export const defaultMetadata: ConnectorMetadata = {
|
||||||
label: 'API Key',
|
label: 'API Key',
|
||||||
type: ConnectorConfigFormItemType.Text,
|
type: ConnectorConfigFormItemType.Text,
|
||||||
required: true,
|
required: true,
|
||||||
placeholder: '<api-key>',
|
placeholder: '<your-sendgrid-api-key>',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'fromEmail',
|
key: 'fromEmail',
|
||||||
label: 'From Email',
|
label: 'From Email',
|
||||||
type: ConnectorConfigFormItemType.Text,
|
type: ConnectorConfigFormItemType.Text,
|
||||||
required: true,
|
required: true,
|
||||||
placeholder: '<from-Email>',
|
placeholder: 'foo@example.com',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'fromName',
|
key: 'fromName',
|
||||||
label: 'From Name',
|
label: 'From Name',
|
||||||
type: ConnectorConfigFormItemType.Text,
|
type: ConnectorConfigFormItemType.Text,
|
||||||
required: false,
|
required: false,
|
||||||
placeholder: '<from-name>',
|
placeholder: 'Logto',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'templates',
|
key: 'templates',
|
||||||
|
|
|
@ -15,14 +15,14 @@ import {
|
||||||
} from '@logto/connector-kit';
|
} from '@logto/connector-kit';
|
||||||
|
|
||||||
import { defaultMetadata, endpoint } from './constant.js';
|
import { defaultMetadata, endpoint } from './constant.js';
|
||||||
|
import { sendGridMailConfigGuard } from './types.js';
|
||||||
import type {
|
import type {
|
||||||
SendGridMailConfig,
|
|
||||||
EmailData,
|
EmailData,
|
||||||
Personalization,
|
Personalization,
|
||||||
Content,
|
Content,
|
||||||
PublicParameters,
|
PublicParameters,
|
||||||
|
SendGridMailConfig,
|
||||||
} from './types.js';
|
} from './types.js';
|
||||||
import { sendGridMailConfigGuard } from './types.js';
|
|
||||||
|
|
||||||
const sendMessage =
|
const sendMessage =
|
||||||
(getConfig: GetConnectorConfig): SendMessageFunction =>
|
(getConfig: GetConnectorConfig): SendMessageFunction =>
|
||||||
|
@ -87,7 +87,7 @@ const sendMessage =
|
||||||
throw new ConnectorError(ConnectorErrorCodes.General, rawBody);
|
throw new ConnectorError(ConnectorErrorCodes.General, rawBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw error;
|
throw new ConnectorError(ConnectorErrorCodes.General, error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,13 @@ export default class RequestError extends Error {
|
||||||
expose = true,
|
expose = true,
|
||||||
...interpolation
|
...interpolation
|
||||||
} = typeof input === 'string' ? { code: input } : input;
|
} = typeof input === 'string' ? { code: input } : input;
|
||||||
const message = i18next.t<string, LogtoErrorI18nKey>(`errors:${code}`, interpolation);
|
const message = i18next.t<string, LogtoErrorI18nKey>(`errors:${code}`, {
|
||||||
|
...interpolation,
|
||||||
|
interpolation: {
|
||||||
|
// Disable i18next escape value since it's for API response, we can show HTML tags.
|
||||||
|
escapeValue: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
super(message);
|
super(message);
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ export default function koaConnectorErrorHandler<StateT, ContextT>(): Middleware
|
||||||
const { code, data } = error;
|
const { code, data } = error;
|
||||||
|
|
||||||
const errorDescriptionGuard = z.object({ errorDescription: z.string() });
|
const errorDescriptionGuard = z.object({ errorDescription: z.string() });
|
||||||
const message = trySafe(() => errorDescriptionGuard.parse(data))?.errorDescription;
|
const message =
|
||||||
|
trySafe(() => errorDescriptionGuard.parse(data))?.errorDescription ?? JSON.stringify(data);
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case ConnectorErrorCodes.InvalidMetadata:
|
case ConnectorErrorCodes.InvalidMetadata:
|
||||||
|
|
|
@ -12,6 +12,7 @@ const connector = {
|
||||||
invalid_response: 'Die Antwort des Connectors ist ungültig.',
|
invalid_response: 'Die Antwort des Connectors ist ungültig.',
|
||||||
template_not_found:
|
template_not_found:
|
||||||
'Die richtige Vorlage in der Connector-Konfiguration konnte nicht gefunden werden.',
|
'Die richtige Vorlage in der Connector-Konfiguration konnte nicht gefunden werden.',
|
||||||
|
template_not_supported: 'Der Connector unterstützt diesen Vorlagentyp nicht.',
|
||||||
rate_limit_exceeded: 'Auslöser-Rate-Limit. Bitte versuchen Sie es später erneut.',
|
rate_limit_exceeded: 'Auslöser-Rate-Limit. Bitte versuchen Sie es später erneut.',
|
||||||
not_implemented: '{{method}}: wurde noch nicht implementiert.',
|
not_implemented: '{{method}}: wurde noch nicht implementiert.',
|
||||||
social_invalid_access_token: 'Der Access Token des Connectors ist ungültig.',
|
social_invalid_access_token: 'Der Access Token des Connectors ist ungültig.',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: "The connector's config is invalid.",
|
invalid_config: "The connector's config is invalid.",
|
||||||
invalid_response: "The connector's response is invalid.",
|
invalid_response: "The connector's response is invalid.",
|
||||||
template_not_found: 'Unable to find correct template in connector config.',
|
template_not_found: 'Unable to find correct template in connector config.',
|
||||||
|
template_not_supported: 'The connector does not support this template type.',
|
||||||
rate_limit_exceeded: 'Trigger rate limit. Please try again later.',
|
rate_limit_exceeded: 'Trigger rate limit. Please try again later.',
|
||||||
not_implemented: '{{method}}: has not been implemented yet.',
|
not_implemented: '{{method}}: has not been implemented yet.',
|
||||||
social_invalid_access_token: "The connector's access token is invalid.",
|
social_invalid_access_token: "The connector's access token is invalid.",
|
||||||
|
|
|
@ -11,6 +11,7 @@ const connector = {
|
||||||
invalid_response: 'La respuesta del conector es inválida.',
|
invalid_response: 'La respuesta del conector es inválida.',
|
||||||
template_not_found:
|
template_not_found:
|
||||||
'No se puede encontrar la plantilla correcta en la configuración del conector.',
|
'No se puede encontrar la plantilla correcta en la configuración del conector.',
|
||||||
|
template_not_supported: 'El conector no admite este tipo de plantilla.',
|
||||||
rate_limit_exceeded: 'Límite de frecuencia activado. Por favor, inténtalo de nuevo más tarde.',
|
rate_limit_exceeded: 'Límite de frecuencia activado. Por favor, inténtalo de nuevo más tarde.',
|
||||||
not_implemented: '{{method}}: aún no se ha implementado.',
|
not_implemented: '{{method}}: aún no se ha implementado.',
|
||||||
social_invalid_access_token: 'El token de acceso del conector es inválido.',
|
social_invalid_access_token: 'El token de acceso del conector es inválido.',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: "La configuration du connecteur n'est pas valide.",
|
invalid_config: "La configuration du connecteur n'est pas valide.",
|
||||||
invalid_response: "La réponse du connecteur n'est pas valide.",
|
invalid_response: "La réponse du connecteur n'est pas valide.",
|
||||||
template_not_found: 'Impossible de trouver le bon modèle dans la configuration du connecteur.',
|
template_not_found: 'Impossible de trouver le bon modèle dans la configuration du connecteur.',
|
||||||
|
template_not_supported: 'Le connecteur ne prend pas en charge ce type de modèle.',
|
||||||
rate_limit_exceeded: 'Limite de taux déclenchée. Veuillez réessayer plus tard.',
|
rate_limit_exceeded: 'Limite de taux déclenchée. Veuillez réessayer plus tard.',
|
||||||
not_implemented: "{{method}} : n'a pas encore été mis en œuvre.",
|
not_implemented: "{{method}} : n'a pas encore été mis en œuvre.",
|
||||||
social_invalid_access_token: "Le jeton d'accès du connecteur n'est pas valide.",
|
social_invalid_access_token: "Le jeton d'accès du connecteur n'est pas valide.",
|
||||||
|
|
|
@ -11,6 +11,7 @@ const connector = {
|
||||||
invalid_response: 'La risposta del connettore non è valida.',
|
invalid_response: 'La risposta del connettore non è valida.',
|
||||||
template_not_found:
|
template_not_found:
|
||||||
'Impossibile trovare il modello corretto nella configurazione del connettore.',
|
'Impossibile trovare il modello corretto nella configurazione del connettore.',
|
||||||
|
template_not_supported: 'Il connettore non supporta questo tipo di modello.',
|
||||||
rate_limit_exceeded: 'Limite di frequenza attivata. Riprova più tardi.',
|
rate_limit_exceeded: 'Limite di frequenza attivata. Riprova più tardi.',
|
||||||
not_implemented: '{{method}}: non è stato ancora implementato.',
|
not_implemented: '{{method}}: non è stato ancora implementato.',
|
||||||
social_invalid_access_token: 'Il token di accesso del connettore non è valido.',
|
social_invalid_access_token: 'Il token di accesso del connettore non è valido.',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: 'コネクタの設定が無効です。',
|
invalid_config: 'コネクタの設定が無効です。',
|
||||||
invalid_response: 'コネクタのレスポンスが無効です。',
|
invalid_response: 'コネクタのレスポンスが無効です。',
|
||||||
template_not_found: 'コネクタ構成から正しいテンプレートを見つけることができませんでした。',
|
template_not_found: 'コネクタ構成から正しいテンプレートを見つけることができませんでした。',
|
||||||
|
template_not_supported: 'コネクタはこのテンプレートタイプをサポートしていません。',
|
||||||
rate_limit_exceeded: 'トリガーレート制限。後でもう一度お試しください。',
|
rate_limit_exceeded: 'トリガーレート制限。後でもう一度お試しください。',
|
||||||
not_implemented: '{{method}}:まだ実装されていません。',
|
not_implemented: '{{method}}:まだ実装されていません。',
|
||||||
social_invalid_access_token: 'コネクタのアクセストークンが無効です。',
|
social_invalid_access_token: 'コネクタのアクセストークンが無効です。',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: '연동 설정이 유효하지 않아요.',
|
invalid_config: '연동 설정이 유효하지 않아요.',
|
||||||
invalid_response: '연동 응답이 유효하지 않아요.',
|
invalid_response: '연동 응답이 유효하지 않아요.',
|
||||||
template_not_found: '연동 예제 설정을 찾을 수 없어요.',
|
template_not_found: '연동 예제 설정을 찾을 수 없어요.',
|
||||||
|
template_not_supported: '연동이 이 템플릿 타입을 지원하지 않아요.',
|
||||||
rate_limit_exceeded: '트리거 주기 제한. 나중에 다시 시도하세요.',
|
rate_limit_exceeded: '트리거 주기 제한. 나중에 다시 시도하세요.',
|
||||||
not_implemented: '{{method}}은 아직 구현되지 않았어요.',
|
not_implemented: '{{method}}은 아직 구현되지 않았어요.',
|
||||||
social_invalid_access_token: '연동 서비스의 Access 토큰이 유효하지 않아요.',
|
social_invalid_access_token: '연동 서비스의 Access 토큰이 유효하지 않아요.',
|
||||||
|
|
|
@ -11,6 +11,7 @@ const connector = {
|
||||||
invalid_config: 'Konfiguracja łącznika jest nieprawidłowa.',
|
invalid_config: 'Konfiguracja łącznika jest nieprawidłowa.',
|
||||||
invalid_response: 'Odpowiedź łącznika jest nieprawidłowa.',
|
invalid_response: 'Odpowiedź łącznika jest nieprawidłowa.',
|
||||||
template_not_found: 'Nie można znaleźć poprawnego szablonu w konfiguracji łącznika.',
|
template_not_found: 'Nie można znaleźć poprawnego szablonu w konfiguracji łącznika.',
|
||||||
|
template_not_supported: 'Łącznik nie obsługuje tego typu szablonu.',
|
||||||
rate_limit_exceeded: 'Ograniczenie szybkości wywołań. Spróbuj ponownie później.',
|
rate_limit_exceeded: 'Ograniczenie szybkości wywołań. Spróbuj ponownie później.',
|
||||||
not_implemented: '{{method}}: jeszcze nie zaimplementowano.',
|
not_implemented: '{{method}}: jeszcze nie zaimplementowano.',
|
||||||
social_invalid_access_token: 'Token dostępu łącznika jest nieprawidłowy.',
|
social_invalid_access_token: 'Token dostępu łącznika jest nieprawidłowy.',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: 'A configuração do conector é inválida.',
|
invalid_config: 'A configuração do conector é inválida.',
|
||||||
invalid_response: 'A resposta do conector é inválida.',
|
invalid_response: 'A resposta do conector é inválida.',
|
||||||
template_not_found: 'Não foi possível encontrar o modelo correto na configuração do conector.',
|
template_not_found: 'Não foi possível encontrar o modelo correto na configuração do conector.',
|
||||||
|
template_not_supported: 'O conector não suporta esse tipo de modelo.',
|
||||||
rate_limit_exceeded: 'Limite de taxa de acionamento. Tente novamente mais tarde.',
|
rate_limit_exceeded: 'Limite de taxa de acionamento. Tente novamente mais tarde.',
|
||||||
not_implemented: '{{method}}: ainda não foi implementado.',
|
not_implemented: '{{method}}: ainda não foi implementado.',
|
||||||
social_invalid_access_token: 'O token de acesso do conector é inválido.',
|
social_invalid_access_token: 'O token de acesso do conector é inválido.',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: 'A configuração do conector é inválida.',
|
invalid_config: 'A configuração do conector é inválida.',
|
||||||
invalid_response: 'A resposta do conector é inválida.',
|
invalid_response: 'A resposta do conector é inválida.',
|
||||||
template_not_found: 'Não foi possível encontrar o modelo correto na configuração do conector.',
|
template_not_found: 'Não foi possível encontrar o modelo correto na configuração do conector.',
|
||||||
|
template_not_supported: 'O conector não suporta este tipo de modelo.',
|
||||||
rate_limit_exceeded: 'Limite de taxa de ativação. Por favor, tente novamente mais tarde.',
|
rate_limit_exceeded: 'Limite de taxa de ativação. Por favor, tente novamente mais tarde.',
|
||||||
not_implemented: '{{method}}: ainda não foi implementado.',
|
not_implemented: '{{method}}: ainda não foi implementado.',
|
||||||
social_invalid_access_token: 'O token de acesso do conector é inválido.',
|
social_invalid_access_token: 'O token de acesso do conector é inválido.',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: 'Конфигурация коннектора недействительна.',
|
invalid_config: 'Конфигурация коннектора недействительна.',
|
||||||
invalid_response: 'Ответ коннектора недействителен.',
|
invalid_response: 'Ответ коннектора недействителен.',
|
||||||
template_not_found: 'Невозможно найти правильный шаблон в конфигурации коннектора.',
|
template_not_found: 'Невозможно найти правильный шаблон в конфигурации коннектора.',
|
||||||
|
template_not_supported: 'Коннектор не поддерживает этот тип шаблона.',
|
||||||
rate_limit_exceeded: 'Превышен лимит запросов. Пожалуйста, попробуйте позже.',
|
rate_limit_exceeded: 'Превышен лимит запросов. Пожалуйста, попробуйте позже.',
|
||||||
not_implemented: '{{method}}: еще не реализован.',
|
not_implemented: '{{method}}: еще не реализован.',
|
||||||
social_invalid_access_token: 'Токен доступа коннектора недействителен.',
|
social_invalid_access_token: 'Токен доступа коннектора недействителен.',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: 'Bağlayıcının ayarları geçersiz.',
|
invalid_config: 'Bağlayıcının ayarları geçersiz.',
|
||||||
invalid_response: 'Bağlayıcının yanıtı geçersiz.',
|
invalid_response: 'Bağlayıcının yanıtı geçersiz.',
|
||||||
template_not_found: 'Bağlayıcı yapılandırmasında doğru şablon bulunamıyor.',
|
template_not_found: 'Bağlayıcı yapılandırmasında doğru şablon bulunamıyor.',
|
||||||
|
template_not_supported: 'Bağlayıcı bu şablon türünü desteklemiyor.',
|
||||||
rate_limit_exceeded: 'Tetikleyici oran sınırına ulaşıldı. Lütfen daha sonra tekrar deneyin.',
|
rate_limit_exceeded: 'Tetikleyici oran sınırına ulaşıldı. Lütfen daha sonra tekrar deneyin.',
|
||||||
not_implemented: '{{method}}: henüz uygulanmadı.',
|
not_implemented: '{{method}}: henüz uygulanmadı.',
|
||||||
social_invalid_access_token: 'Bağlayıcının erişim tokenı geçersiz.',
|
social_invalid_access_token: 'Bağlayıcının erişim tokenı geçersiz.',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: '连接器配置错误',
|
invalid_config: '连接器配置错误',
|
||||||
invalid_response: '连接器错误响应',
|
invalid_response: '连接器错误响应',
|
||||||
template_not_found: '无法从连接器配置中找到对应的模板',
|
template_not_found: '无法从连接器配置中找到对应的模板',
|
||||||
|
template_not_supported: '连接器不支持此模板类型。',
|
||||||
rate_limit_exceeded: '触发速率限制。请稍后再试。',
|
rate_limit_exceeded: '触发速率限制。请稍后再试。',
|
||||||
not_implemented: '方法 {{method}} 尚未实现',
|
not_implemented: '方法 {{method}} 尚未实现',
|
||||||
social_invalid_access_token: '当前连接器的 access_token 无效',
|
social_invalid_access_token: '当前连接器的 access_token 无效',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: '連接器配置錯誤',
|
invalid_config: '連接器配置錯誤',
|
||||||
invalid_response: '連接器錯誤響應',
|
invalid_response: '連接器錯誤響應',
|
||||||
template_not_found: '無法從連接器配置中找到對應的模板',
|
template_not_found: '無法從連接器配置中找到對應的模板',
|
||||||
|
template_not_supported: '連接器不支援此模板類型。',
|
||||||
rate_limit_exceeded: '觸發速率限制。請稍後再試。',
|
rate_limit_exceeded: '觸發速率限制。請稍後再試。',
|
||||||
not_implemented: '方法 {{method}} 尚未實現',
|
not_implemented: '方法 {{method}} 尚未實現',
|
||||||
social_invalid_access_token: '當前連接器的 access_token 無效',
|
social_invalid_access_token: '當前連接器的 access_token 無效',
|
||||||
|
|
|
@ -10,6 +10,7 @@ const connector = {
|
||||||
invalid_config: '連接器配置錯誤',
|
invalid_config: '連接器配置錯誤',
|
||||||
invalid_response: '連接器錯誤響應',
|
invalid_response: '連接器錯誤響應',
|
||||||
template_not_found: '無法從連接器配置中找到對應的模板',
|
template_not_found: '無法從連接器配置中找到對應的模板',
|
||||||
|
template_not_supported: '連接器不支援此模板類型',
|
||||||
rate_limit_exceeded: '觸發速率限制。請稍後再試。',
|
rate_limit_exceeded: '觸發速率限制。請稍後再試。',
|
||||||
not_implemented: '方法 {{method}} 尚未實現',
|
not_implemented: '方法 {{method}} 尚未實現',
|
||||||
social_invalid_access_token: '當前連接器的 access_token 無效',
|
social_invalid_access_token: '當前連接器的 access_token 無效',
|
||||||
|
|
|
@ -48,7 +48,10 @@ export enum ConnectorErrorCodes {
|
||||||
InsufficientRequestParameters = 'insufficient_request_parameters',
|
InsufficientRequestParameters = 'insufficient_request_parameters',
|
||||||
InvalidConfig = 'invalid_config',
|
InvalidConfig = 'invalid_config',
|
||||||
InvalidResponse = 'invalid_response',
|
InvalidResponse = 'invalid_response',
|
||||||
|
/** The template is not found for the given type. */
|
||||||
TemplateNotFound = 'template_not_found',
|
TemplateNotFound = 'template_not_found',
|
||||||
|
/** The template type is not supported by the connector. */
|
||||||
|
TemplateNotSupported = 'template_not_supported',
|
||||||
RateLimitExceeded = 'rate_limit_exceeded',
|
RateLimitExceeded = 'rate_limit_exceeded',
|
||||||
NotImplemented = 'not_implemented',
|
NotImplemented = 'not_implemented',
|
||||||
SocialAuthCodeInvalid = 'social_auth_code_invalid',
|
SocialAuthCodeInvalid = 'social_auth_code_invalid',
|
||||||
|
@ -62,7 +65,7 @@ export class ConnectorError extends Error {
|
||||||
public data: unknown;
|
public data: unknown;
|
||||||
|
|
||||||
constructor(code: ConnectorErrorCodes, data?: unknown) {
|
constructor(code: ConnectorErrorCodes, data?: unknown) {
|
||||||
const message = typeof data === 'string' ? data : 'Connector error occurred.';
|
const message = `ConnectorError: ${data ? JSON.stringify(data) : code}`;
|
||||||
super(message);
|
super(message);
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.data = typeof data === 'string' ? { message: data } : data;
|
this.data = typeof data === 'string' ? { message: data } : data;
|
||||||
|
@ -233,6 +236,19 @@ export const emailServiceBrandingGuard = z
|
||||||
|
|
||||||
export type EmailServiceBranding = z.infer<typeof emailServiceBrandingGuard>;
|
export type EmailServiceBranding = z.infer<typeof emailServiceBrandingGuard>;
|
||||||
|
|
||||||
|
export type SendMessagePayload = {
|
||||||
|
to: string;
|
||||||
|
type: VerificationCodeType;
|
||||||
|
payload: {
|
||||||
|
/**
|
||||||
|
* The dynamic verification code to send.
|
||||||
|
*
|
||||||
|
* @example '123456'
|
||||||
|
*/
|
||||||
|
code: string;
|
||||||
|
} & EmailServiceBranding;
|
||||||
|
};
|
||||||
|
|
||||||
export const sendMessagePayloadGuard = z.object({
|
export const sendMessagePayloadGuard = z.object({
|
||||||
to: z.string(),
|
to: z.string(),
|
||||||
type: verificationCodeTypeGuard,
|
type: verificationCodeTypeGuard,
|
||||||
|
@ -241,9 +257,7 @@ export const sendMessagePayloadGuard = z.object({
|
||||||
code: z.string(),
|
code: z.string(),
|
||||||
})
|
})
|
||||||
.merge(emailServiceBrandingGuard),
|
.merge(emailServiceBrandingGuard),
|
||||||
});
|
}) satisfies z.ZodType<SendMessagePayload>;
|
||||||
|
|
||||||
export type SendMessagePayload = z.infer<typeof sendMessagePayloadGuard>;
|
|
||||||
|
|
||||||
export type SendMessageFunction = (data: SendMessagePayload, config?: unknown) => Promise<unknown>;
|
export type SendMessageFunction = (data: SendMessagePayload, config?: unknown) => Promise<unknown>;
|
||||||
|
|
||||||
|
|
354
pnpm-lock.yaml
354
pnpm-lock.yaml
|
@ -1534,6 +1534,85 @@ importers:
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.0.2
|
version: 5.0.2
|
||||||
|
|
||||||
|
packages/connectors/connector-mailgun:
|
||||||
|
dependencies:
|
||||||
|
'@logto/connector-kit':
|
||||||
|
specifier: workspace:^1.1.0
|
||||||
|
version: link:../../toolkit/connector-kit
|
||||||
|
'@silverhand/essentials':
|
||||||
|
specifier: ^2.5.0
|
||||||
|
version: 2.7.0
|
||||||
|
got:
|
||||||
|
specifier: ^13.0.0
|
||||||
|
version: 13.0.0
|
||||||
|
snakecase-keys:
|
||||||
|
specifier: ^5.4.4
|
||||||
|
version: 5.4.4
|
||||||
|
zod:
|
||||||
|
specifier: ^3.20.2
|
||||||
|
version: 3.20.2
|
||||||
|
devDependencies:
|
||||||
|
'@jest/types':
|
||||||
|
specifier: ^29.5.0
|
||||||
|
version: 29.5.0
|
||||||
|
'@rollup/plugin-commonjs':
|
||||||
|
specifier: ^25.0.0
|
||||||
|
version: 25.0.0(rollup@3.8.0)
|
||||||
|
'@rollup/plugin-json':
|
||||||
|
specifier: ^6.0.0
|
||||||
|
version: 6.0.0(rollup@3.8.0)
|
||||||
|
'@rollup/plugin-node-resolve':
|
||||||
|
specifier: ^15.0.1
|
||||||
|
version: 15.0.1(rollup@3.8.0)
|
||||||
|
'@rollup/plugin-typescript':
|
||||||
|
specifier: ^11.0.0
|
||||||
|
version: 11.0.0(rollup@3.8.0)(typescript@5.0.2)
|
||||||
|
'@silverhand/eslint-config':
|
||||||
|
specifier: 4.0.1
|
||||||
|
version: 4.0.1(eslint@8.44.0)(prettier@3.0.0)(typescript@5.0.2)
|
||||||
|
'@silverhand/ts-config':
|
||||||
|
specifier: 4.0.0
|
||||||
|
version: 4.0.0(typescript@5.0.2)
|
||||||
|
'@types/jest':
|
||||||
|
specifier: ^29.4.0
|
||||||
|
version: 29.4.0
|
||||||
|
'@types/node':
|
||||||
|
specifier: ^18.11.18
|
||||||
|
version: 18.11.18
|
||||||
|
'@types/supertest':
|
||||||
|
specifier: ^2.0.11
|
||||||
|
version: 2.0.11
|
||||||
|
eslint:
|
||||||
|
specifier: ^8.44.0
|
||||||
|
version: 8.44.0
|
||||||
|
jest:
|
||||||
|
specifier: ^29.5.0
|
||||||
|
version: 29.5.0(@types/node@18.11.18)
|
||||||
|
jest-matcher-specific-error:
|
||||||
|
specifier: ^1.0.0
|
||||||
|
version: 1.0.0
|
||||||
|
lint-staged:
|
||||||
|
specifier: ^13.0.0
|
||||||
|
version: 13.0.0
|
||||||
|
nock:
|
||||||
|
specifier: ^13.2.2
|
||||||
|
version: 13.3.1
|
||||||
|
prettier:
|
||||||
|
specifier: ^3.0.0
|
||||||
|
version: 3.0.0
|
||||||
|
rollup:
|
||||||
|
specifier: ^3.8.0
|
||||||
|
version: 3.8.0
|
||||||
|
rollup-plugin-summary:
|
||||||
|
specifier: ^2.0.0
|
||||||
|
version: 2.0.0(rollup@3.8.0)
|
||||||
|
supertest:
|
||||||
|
specifier: ^6.2.2
|
||||||
|
version: 6.2.2
|
||||||
|
typescript:
|
||||||
|
specifier: ^5.0.0
|
||||||
|
version: 5.0.2
|
||||||
|
|
||||||
packages/connectors/connector-mock-email:
|
packages/connectors/connector-mock-email:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@logto/connector-kit':
|
'@logto/connector-kit':
|
||||||
|
@ -2906,7 +2985,7 @@ importers:
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
jest:
|
jest:
|
||||||
specifier: ^29.5.0
|
specifier: ^29.5.0
|
||||||
version: 29.5.0(@types/node@20.4.2)(ts-node@10.9.1)
|
version: 29.5.0(@types/node@18.11.18)(ts-node@10.9.1)
|
||||||
jest-environment-jsdom:
|
jest-environment-jsdom:
|
||||||
specifier: ^29.0.0
|
specifier: ^29.0.0
|
||||||
version: 29.2.2
|
version: 29.2.2
|
||||||
|
@ -2966,7 +3045,7 @@ importers:
|
||||||
version: 2.19.3(react@18.2.0)
|
version: 2.19.3(react@18.2.0)
|
||||||
react-dnd:
|
react-dnd:
|
||||||
specifier: ^16.0.0
|
specifier: ^16.0.0
|
||||||
version: 16.0.0(@types/node@20.4.2)(@types/react@18.0.31)(react@18.2.0)
|
version: 16.0.0(@types/node@18.11.18)(@types/react@18.0.31)(react@18.2.0)
|
||||||
react-dnd-html5-backend:
|
react-dnd-html5-backend:
|
||||||
specifier: ^16.0.0
|
specifier: ^16.0.0
|
||||||
version: 16.0.0
|
version: 16.0.0
|
||||||
|
@ -3933,7 +4012,7 @@ importers:
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
jest:
|
jest:
|
||||||
specifier: ^29.5.0
|
specifier: ^29.5.0
|
||||||
version: 29.5.0(@types/node@20.4.2)(ts-node@10.9.1)
|
version: 29.5.0(@types/node@18.11.18)(ts-node@10.9.1)
|
||||||
jest-environment-jsdom:
|
jest-environment-jsdom:
|
||||||
specifier: ^29.0.0
|
specifier: ^29.0.0
|
||||||
version: 29.2.2
|
version: 29.2.2
|
||||||
|
@ -6528,15 +6607,15 @@ packages:
|
||||||
'@commitlint/execute-rule': 17.4.0
|
'@commitlint/execute-rule': 17.4.0
|
||||||
'@commitlint/resolve-extends': 17.4.4
|
'@commitlint/resolve-extends': 17.4.4
|
||||||
'@commitlint/types': 17.4.4
|
'@commitlint/types': 17.4.4
|
||||||
'@types/node': 20.4.2
|
'@types/node': 18.11.18
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cosmiconfig: 8.2.0
|
cosmiconfig: 8.2.0
|
||||||
cosmiconfig-typescript-loader: 4.3.0(@types/node@20.4.2)(cosmiconfig@8.2.0)(ts-node@10.9.1)(typescript@5.0.2)
|
cosmiconfig-typescript-loader: 4.3.0(@types/node@18.11.18)(cosmiconfig@8.2.0)(ts-node@10.9.1)(typescript@5.0.2)
|
||||||
lodash.isplainobject: 4.0.6
|
lodash.isplainobject: 4.0.6
|
||||||
lodash.merge: 4.6.2
|
lodash.merge: 4.6.2
|
||||||
lodash.uniq: 4.5.0
|
lodash.uniq: 4.5.0
|
||||||
resolve-from: 5.0.0
|
resolve-from: 5.0.0
|
||||||
ts-node: 10.9.1(@types/node@20.4.2)(typescript@5.0.2)
|
ts-node: 10.9.1(@types/node@18.11.18)(typescript@5.0.2)
|
||||||
typescript: 5.0.2
|
typescript: 5.0.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@swc/core'
|
- '@swc/core'
|
||||||
|
@ -6794,6 +6873,48 @@ packages:
|
||||||
slash: 3.0.0
|
slash: 3.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@jest/core@29.5.0:
|
||||||
|
resolution: {integrity: sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==}
|
||||||
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
node-notifier:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@jest/console': 29.5.0
|
||||||
|
'@jest/reporters': 29.5.0
|
||||||
|
'@jest/test-result': 29.5.0
|
||||||
|
'@jest/transform': 29.5.0
|
||||||
|
'@jest/types': 29.5.0
|
||||||
|
'@types/node': 18.11.18
|
||||||
|
ansi-escapes: 4.3.2
|
||||||
|
chalk: 4.1.2
|
||||||
|
ci-info: 3.8.0
|
||||||
|
exit: 0.1.2
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
jest-changed-files: 29.5.0
|
||||||
|
jest-config: 29.5.0(@types/node@18.11.18)
|
||||||
|
jest-haste-map: 29.5.0
|
||||||
|
jest-message-util: 29.5.0
|
||||||
|
jest-regex-util: 29.4.3
|
||||||
|
jest-resolve: 29.5.0
|
||||||
|
jest-resolve-dependencies: 29.5.0
|
||||||
|
jest-runner: 29.5.0
|
||||||
|
jest-runtime: 29.5.0
|
||||||
|
jest-snapshot: 29.5.0
|
||||||
|
jest-util: 29.5.0
|
||||||
|
jest-validate: 29.5.0
|
||||||
|
jest-watcher: 29.5.0
|
||||||
|
micromatch: 4.0.5
|
||||||
|
pretty-format: 29.5.0
|
||||||
|
slash: 3.0.0
|
||||||
|
strip-ansi: 6.0.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
- ts-node
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@jest/core@29.5.0(ts-node@10.9.1):
|
/@jest/core@29.5.0(ts-node@10.9.1):
|
||||||
resolution: {integrity: sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==}
|
resolution: {integrity: sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
@ -7251,7 +7372,7 @@ packages:
|
||||||
/@logto/js@2.1.1:
|
/@logto/js@2.1.1:
|
||||||
resolution: {integrity: sha512-PHikheavVK+l4ivgtzi14p184hEPgXjqQEAom1Gme1MZoopx+WlwxvHSEQBsmyvVqRtI0oiojhoU5tgYi1FKJw==}
|
resolution: {integrity: sha512-PHikheavVK+l4ivgtzi14p184hEPgXjqQEAom1Gme1MZoopx+WlwxvHSEQBsmyvVqRtI0oiojhoU5tgYi1FKJw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@silverhand/essentials': 2.6.2
|
'@silverhand/essentials': 2.7.0
|
||||||
camelcase-keys: 7.0.2
|
camelcase-keys: 7.0.2
|
||||||
jose: 4.14.2
|
jose: 4.14.2
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -7260,7 +7381,7 @@ packages:
|
||||||
resolution: {integrity: sha512-joSzzAqaRKeEquRenoFrIXXkNxkJci5zSkk4afywz1P8tTcTysnV4eXaBmwXNpmDfQdtHBwRdSACZPLgeF8JiQ==}
|
resolution: {integrity: sha512-joSzzAqaRKeEquRenoFrIXXkNxkJci5zSkk4afywz1P8tTcTysnV4eXaBmwXNpmDfQdtHBwRdSACZPLgeF8JiQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@logto/client': 2.1.0
|
'@logto/client': 2.1.0
|
||||||
'@silverhand/essentials': 2.6.2
|
'@silverhand/essentials': 2.7.0
|
||||||
js-base64: 3.7.5
|
js-base64: 3.7.5
|
||||||
node-fetch: 2.6.7
|
node-fetch: 2.6.7
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -7273,7 +7394,7 @@ packages:
|
||||||
react: '>=16.8.0 || ^18.0.0'
|
react: '>=16.8.0 || ^18.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
'@logto/browser': 2.1.0
|
'@logto/browser': 2.1.0
|
||||||
'@silverhand/essentials': 2.6.2
|
'@silverhand/essentials': 2.7.0
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -8867,11 +8988,6 @@ packages:
|
||||||
resolution: {integrity: sha512-8GgVFAmbo6S0EgsjYXH4aH8a69O7SzEtPFPDpVZmJuGEt8e3ODVx0F2V4rXyC3/SzFbcb2md2gRbA+Z6aTad6g==}
|
resolution: {integrity: sha512-8GgVFAmbo6S0EgsjYXH4aH8a69O7SzEtPFPDpVZmJuGEt8e3ODVx0F2V4rXyC3/SzFbcb2md2gRbA+Z6aTad6g==}
|
||||||
engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^7}
|
engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^7}
|
||||||
|
|
||||||
/@silverhand/essentials@2.6.2:
|
|
||||||
resolution: {integrity: sha512-1b5u2BGEa14V3o8XzaE7eL+nuwmQe8c1wqSMcGvq+KAusPPZo9tV4glbfF16Xi/ohv37vUpBGJ2DNf4CfuxBLw==}
|
|
||||||
engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^8.0.0}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@silverhand/essentials@2.7.0:
|
/@silverhand/essentials@2.7.0:
|
||||||
resolution: {integrity: sha512-F5Qo5ZNnERUURK/9F1ZIi4FBDM22aeD59Zv0VtkgIhUL9tYK9svA2Jz88NNdYBwqCPrh8ExZlpFNi+pNmXKNlQ==}
|
resolution: {integrity: sha512-F5Qo5ZNnERUURK/9F1ZIi4FBDM22aeD59Zv0VtkgIhUL9tYK9svA2Jz88NNdYBwqCPrh8ExZlpFNi+pNmXKNlQ==}
|
||||||
engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^8.0.0}
|
engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^8.0.0}
|
||||||
|
@ -9602,10 +9718,6 @@ packages:
|
||||||
/@types/node@18.11.18:
|
/@types/node@18.11.18:
|
||||||
resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==}
|
resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==}
|
||||||
|
|
||||||
/@types/node@20.4.2:
|
|
||||||
resolution: {integrity: sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/nodemailer@6.4.7:
|
/@types/nodemailer@6.4.7:
|
||||||
resolution: {integrity: sha512-f5qCBGAn/f0qtRcd4SEn88c8Fp3Swct1731X4ryPKqS61/A3LmmzN8zaEz7hneJvpjFbUUgY7lru/B/7ODTazg==}
|
resolution: {integrity: sha512-f5qCBGAn/f0qtRcd4SEn88c8Fp3Swct1731X4ryPKqS61/A3LmmzN8zaEz7hneJvpjFbUUgY7lru/B/7ODTazg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -11144,7 +11256,7 @@ packages:
|
||||||
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/cosmiconfig-typescript-loader@4.3.0(@types/node@20.4.2)(cosmiconfig@8.2.0)(ts-node@10.9.1)(typescript@5.0.2):
|
/cosmiconfig-typescript-loader@4.3.0(@types/node@18.11.18)(cosmiconfig@8.2.0)(ts-node@10.9.1)(typescript@5.0.2):
|
||||||
resolution: {integrity: sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==}
|
resolution: {integrity: sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==}
|
||||||
engines: {node: '>=12', npm: '>=6'}
|
engines: {node: '>=12', npm: '>=6'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -11153,9 +11265,9 @@ packages:
|
||||||
ts-node: '>=10'
|
ts-node: '>=10'
|
||||||
typescript: '>=3'
|
typescript: '>=3'
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.4.2
|
'@types/node': 18.11.18
|
||||||
cosmiconfig: 8.2.0
|
cosmiconfig: 8.2.0
|
||||||
ts-node: 10.9.1(@types/node@20.4.2)(typescript@5.0.2)
|
ts-node: 10.9.1(@types/node@18.11.18)(typescript@5.0.2)
|
||||||
typescript: 5.0.2
|
typescript: 5.0.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -11452,6 +11564,17 @@ packages:
|
||||||
/dayjs@1.11.6:
|
/dayjs@1.11.6:
|
||||||
resolution: {integrity: sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==}
|
resolution: {integrity: sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==}
|
||||||
|
|
||||||
|
/debug@3.2.7:
|
||||||
|
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||||
|
peerDependencies:
|
||||||
|
supports-color: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
supports-color:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
ms: 2.1.3
|
||||||
|
dev: true
|
||||||
|
|
||||||
/debug@3.2.7(supports-color@5.5.0):
|
/debug@3.2.7(supports-color@5.5.0):
|
||||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -12003,9 +12126,9 @@ packages:
|
||||||
/eslint-import-resolver-node@0.3.7:
|
/eslint-import-resolver-node@0.3.7:
|
||||||
resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==}
|
resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7(supports-color@5.5.0)
|
debug: 3.2.7
|
||||||
is-core-module: 2.11.0
|
is-core-module: 2.12.1
|
||||||
resolve: 1.22.1
|
resolve: 1.22.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -12024,7 +12147,7 @@ packages:
|
||||||
eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.61.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.44.0)
|
eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.61.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.44.0)
|
||||||
get-tsconfig: 4.5.0
|
get-tsconfig: 4.5.0
|
||||||
globby: 13.1.3
|
globby: 13.1.3
|
||||||
is-core-module: 2.11.0
|
is-core-module: 2.12.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
synckit: 0.8.5
|
synckit: 0.8.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -12056,7 +12179,7 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@5.0.2)
|
'@typescript-eslint/parser': 5.61.0(eslint@8.44.0)(typescript@5.0.2)
|
||||||
debug: 3.2.7(supports-color@5.5.0)
|
debug: 3.2.7
|
||||||
eslint: 8.44.0
|
eslint: 8.44.0
|
||||||
eslint-import-resolver-node: 0.3.7
|
eslint-import-resolver-node: 0.3.7
|
||||||
eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.61.0)(eslint-plugin-import@2.27.5)(eslint@8.44.0)
|
eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.61.0)(eslint-plugin-import@2.27.5)(eslint@8.44.0)
|
||||||
|
@ -12108,18 +12231,18 @@ packages:
|
||||||
array-includes: 3.1.6
|
array-includes: 3.1.6
|
||||||
array.prototype.flat: 1.3.1
|
array.prototype.flat: 1.3.1
|
||||||
array.prototype.flatmap: 1.3.1
|
array.prototype.flatmap: 1.3.1
|
||||||
debug: 3.2.7(supports-color@5.5.0)
|
debug: 3.2.7
|
||||||
doctrine: 2.1.0
|
doctrine: 2.1.0
|
||||||
eslint: 8.44.0
|
eslint: 8.44.0
|
||||||
eslint-import-resolver-node: 0.3.7
|
eslint-import-resolver-node: 0.3.7
|
||||||
eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.61.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.44.0)
|
eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.61.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.44.0)
|
||||||
has: 1.0.3
|
has: 1.0.3
|
||||||
is-core-module: 2.11.0
|
is-core-module: 2.12.1
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
object.values: 1.1.6
|
object.values: 1.1.6
|
||||||
resolve: 1.22.1
|
resolve: 1.22.2
|
||||||
semver: 6.3.0
|
semver: 6.3.1
|
||||||
tsconfig-paths: 3.14.1
|
tsconfig-paths: 3.14.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- eslint-import-resolver-typescript
|
- eslint-import-resolver-typescript
|
||||||
|
@ -12173,8 +12296,8 @@ packages:
|
||||||
eslint-utils: 2.1.0
|
eslint-utils: 2.1.0
|
||||||
ignore: 5.2.4
|
ignore: 5.2.4
|
||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
resolve: 1.22.1
|
resolve: 1.22.2
|
||||||
semver: 6.3.0
|
semver: 6.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-prettier@5.0.0-alpha.2(eslint-config-prettier@8.8.0)(eslint@8.44.0)(prettier@3.0.0):
|
/eslint-plugin-prettier@5.0.0-alpha.2(eslint-config-prettier@8.8.0)(eslint@8.44.0)(prettier@3.0.0):
|
||||||
|
@ -13801,12 +13924,6 @@ packages:
|
||||||
ci-info: 3.8.0
|
ci-info: 3.8.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/is-core-module@2.11.0:
|
|
||||||
resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
|
|
||||||
dependencies:
|
|
||||||
has: 1.0.3
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/is-core-module@2.12.1:
|
/is-core-module@2.12.1:
|
||||||
resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==}
|
resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -14150,6 +14267,34 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/jest-cli@29.5.0(@types/node@18.11.18):
|
||||||
|
resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==}
|
||||||
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
node-notifier:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@jest/core': 29.5.0
|
||||||
|
'@jest/test-result': 29.5.0
|
||||||
|
'@jest/types': 29.5.0
|
||||||
|
chalk: 4.1.2
|
||||||
|
exit: 0.1.2
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
import-local: 3.1.0
|
||||||
|
jest-config: 29.5.0(@types/node@18.11.18)
|
||||||
|
jest-util: 29.5.0
|
||||||
|
jest-validate: 29.5.0
|
||||||
|
prompts: 2.4.2
|
||||||
|
yargs: 17.7.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/node'
|
||||||
|
- supports-color
|
||||||
|
- ts-node
|
||||||
|
dev: true
|
||||||
|
|
||||||
/jest-cli@29.5.0(@types/node@18.11.18)(ts-node@10.9.1):
|
/jest-cli@29.5.0(@types/node@18.11.18)(ts-node@10.9.1):
|
||||||
resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==}
|
resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
@ -14178,32 +14323,43 @@ packages:
|
||||||
- ts-node
|
- ts-node
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/jest-cli@29.5.0(@types/node@20.4.2)(ts-node@10.9.1):
|
/jest-config@29.5.0(@types/node@18.11.18):
|
||||||
resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==}
|
resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
hasBin: true
|
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
|
'@types/node': '*'
|
||||||
|
ts-node: '>=9.0.0'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
node-notifier:
|
'@types/node':
|
||||||
|
optional: true
|
||||||
|
ts-node:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/core': 29.5.0(ts-node@10.9.1)
|
'@babel/core': 7.20.2
|
||||||
'@jest/test-result': 29.5.0
|
'@jest/test-sequencer': 29.5.0
|
||||||
'@jest/types': 29.5.0
|
'@jest/types': 29.5.0
|
||||||
|
'@types/node': 18.11.18
|
||||||
|
babel-jest: 29.5.0(@babel/core@7.20.2)
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
exit: 0.1.2
|
ci-info: 3.8.0
|
||||||
|
deepmerge: 4.3.1
|
||||||
|
glob: 7.2.3
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
import-local: 3.1.0
|
jest-circus: 29.5.0
|
||||||
jest-config: 29.5.0(@types/node@20.4.2)(ts-node@10.9.1)
|
jest-environment-node: 29.5.0
|
||||||
|
jest-get-type: 29.4.3
|
||||||
|
jest-regex-util: 29.4.3
|
||||||
|
jest-resolve: 29.5.0
|
||||||
|
jest-runner: 29.5.0
|
||||||
jest-util: 29.5.0
|
jest-util: 29.5.0
|
||||||
jest-validate: 29.5.0
|
jest-validate: 29.5.0
|
||||||
prompts: 2.4.2
|
micromatch: 4.0.5
|
||||||
yargs: 17.7.2
|
parse-json: 5.2.0
|
||||||
|
pretty-format: 29.5.0
|
||||||
|
slash: 3.0.0
|
||||||
|
strip-json-comments: 3.1.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
|
||||||
- supports-color
|
- supports-color
|
||||||
- ts-node
|
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/jest-config@29.5.0(@types/node@18.11.18)(ts-node@10.9.1):
|
/jest-config@29.5.0(@types/node@18.11.18)(ts-node@10.9.1):
|
||||||
|
@ -14241,47 +14397,7 @@ packages:
|
||||||
pretty-format: 29.5.0
|
pretty-format: 29.5.0
|
||||||
slash: 3.0.0
|
slash: 3.0.0
|
||||||
strip-json-comments: 3.1.1
|
strip-json-comments: 3.1.1
|
||||||
ts-node: 10.9.1(@types/node@20.4.2)(typescript@5.0.2)
|
ts-node: 10.9.1(@types/node@18.11.18)(typescript@5.0.2)
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/jest-config@29.5.0(@types/node@20.4.2)(ts-node@10.9.1):
|
|
||||||
resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==}
|
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
|
||||||
peerDependencies:
|
|
||||||
'@types/node': '*'
|
|
||||||
ts-node: '>=9.0.0'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
'@types/node':
|
|
||||||
optional: true
|
|
||||||
ts-node:
|
|
||||||
optional: true
|
|
||||||
dependencies:
|
|
||||||
'@babel/core': 7.20.2
|
|
||||||
'@jest/test-sequencer': 29.5.0
|
|
||||||
'@jest/types': 29.5.0
|
|
||||||
'@types/node': 20.4.2
|
|
||||||
babel-jest: 29.5.0(@babel/core@7.20.2)
|
|
||||||
chalk: 4.1.2
|
|
||||||
ci-info: 3.8.0
|
|
||||||
deepmerge: 4.3.1
|
|
||||||
glob: 7.2.3
|
|
||||||
graceful-fs: 4.2.11
|
|
||||||
jest-circus: 29.5.0
|
|
||||||
jest-environment-node: 29.5.0
|
|
||||||
jest-get-type: 29.4.3
|
|
||||||
jest-regex-util: 29.4.3
|
|
||||||
jest-resolve: 29.5.0
|
|
||||||
jest-runner: 29.5.0
|
|
||||||
jest-util: 29.5.0
|
|
||||||
jest-validate: 29.5.0
|
|
||||||
micromatch: 4.0.5
|
|
||||||
parse-json: 5.2.0
|
|
||||||
pretty-format: 29.5.0
|
|
||||||
slash: 3.0.0
|
|
||||||
strip-json-comments: 3.1.1
|
|
||||||
ts-node: 10.9.1(@types/node@20.4.2)(typescript@5.0.2)
|
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -14640,7 +14756,7 @@ packages:
|
||||||
jest: ^28.1.0 || ^29.1.2
|
jest: ^28.1.0 || ^29.1.2
|
||||||
react: ^17.0.0 || ^18.0.0
|
react: ^17.0.0 || ^18.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
jest: 29.5.0(@types/node@20.4.2)(ts-node@10.9.1)
|
jest: 29.5.0(@types/node@18.11.18)(ts-node@10.9.1)
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -14704,6 +14820,26 @@ packages:
|
||||||
supports-color: 8.1.1
|
supports-color: 8.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/jest@29.5.0(@types/node@18.11.18):
|
||||||
|
resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==}
|
||||||
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
node-notifier:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@jest/core': 29.5.0
|
||||||
|
'@jest/types': 29.5.0
|
||||||
|
import-local: 3.1.0
|
||||||
|
jest-cli: 29.5.0(@types/node@18.11.18)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/node'
|
||||||
|
- supports-color
|
||||||
|
- ts-node
|
||||||
|
dev: true
|
||||||
|
|
||||||
/jest@29.5.0(@types/node@18.11.18)(ts-node@10.9.1):
|
/jest@29.5.0(@types/node@18.11.18)(ts-node@10.9.1):
|
||||||
resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==}
|
resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
@ -14724,26 +14860,6 @@ packages:
|
||||||
- ts-node
|
- ts-node
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/jest@29.5.0(@types/node@20.4.2)(ts-node@10.9.1):
|
|
||||||
resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==}
|
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
|
||||||
hasBin: true
|
|
||||||
peerDependencies:
|
|
||||||
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
|
|
||||||
peerDependenciesMeta:
|
|
||||||
node-notifier:
|
|
||||||
optional: true
|
|
||||||
dependencies:
|
|
||||||
'@jest/core': 29.5.0(ts-node@10.9.1)
|
|
||||||
'@jest/types': 29.5.0
|
|
||||||
import-local: 3.1.0
|
|
||||||
jest-cli: 29.5.0(@types/node@20.4.2)(ts-node@10.9.1)
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- '@types/node'
|
|
||||||
- supports-color
|
|
||||||
- ts-node
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/joi@17.7.0:
|
/joi@17.7.0:
|
||||||
resolution: {integrity: sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==}
|
resolution: {integrity: sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -15538,7 +15654,7 @@ packages:
|
||||||
resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
|
resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.4.14
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/make-dir@3.1.0:
|
/make-dir@3.1.0:
|
||||||
|
@ -17732,7 +17848,7 @@ packages:
|
||||||
dnd-core: 16.0.0
|
dnd-core: 16.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/react-dnd@16.0.0(@types/node@20.4.2)(@types/react@18.0.31)(react@18.2.0):
|
/react-dnd@16.0.0(@types/node@18.11.18)(@types/react@18.0.31)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-RCoeWRWhuwSoqdLaJV8N/weARLyXqsf43OC3QiBWPORIIGGovF/EqI8ckf14ca3bl6oZNI/igtxX49+IDmNDeQ==}
|
resolution: {integrity: sha512-RCoeWRWhuwSoqdLaJV8N/weARLyXqsf43OC3QiBWPORIIGGovF/EqI8ckf14ca3bl6oZNI/igtxX49+IDmNDeQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/hoist-non-react-statics': '>= 3.3.1'
|
'@types/hoist-non-react-statics': '>= 3.3.1'
|
||||||
|
@ -17749,7 +17865,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@react-dnd/invariant': 4.0.0
|
'@react-dnd/invariant': 4.0.0
|
||||||
'@react-dnd/shallowequal': 4.0.0
|
'@react-dnd/shallowequal': 4.0.0
|
||||||
'@types/node': 20.4.2
|
'@types/node': 18.11.18
|
||||||
'@types/react': 18.0.31
|
'@types/react': 18.0.31
|
||||||
dnd-core: 16.0.0
|
dnd-core: 16.0.0
|
||||||
fast-deep-equal: 3.1.3
|
fast-deep-equal: 3.1.3
|
||||||
|
@ -19819,7 +19935,7 @@ packages:
|
||||||
resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==}
|
resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/ts-node@10.9.1(@types/node@20.4.2)(typescript@5.0.2):
|
/ts-node@10.9.1(@types/node@18.11.18)(typescript@5.0.2):
|
||||||
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
|
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -19838,7 +19954,7 @@ packages:
|
||||||
'@tsconfig/node12': 1.0.11
|
'@tsconfig/node12': 1.0.11
|
||||||
'@tsconfig/node14': 1.0.3
|
'@tsconfig/node14': 1.0.3
|
||||||
'@tsconfig/node16': 1.0.4
|
'@tsconfig/node16': 1.0.4
|
||||||
'@types/node': 20.4.2
|
'@types/node': 18.11.18
|
||||||
acorn: 8.10.0
|
acorn: 8.10.0
|
||||||
acorn-walk: 8.2.0
|
acorn-walk: 8.2.0
|
||||||
arg: 4.1.3
|
arg: 4.1.3
|
||||||
|
|
Loading…
Reference in a new issue