0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

fix(connector,phrases): cloud sms/email connectors error message (#3699)

This commit is contained in:
Darcy Ye 2023-04-19 11:07:45 +08:00 committed by GitHub
parent 8a07ef9fbd
commit 3e5b8dd796
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 99 additions and 35 deletions

View file

@ -74,7 +74,10 @@ const sendMessage =
assert(
typeof rawBody === 'string',
new ConnectorError(ConnectorErrorCodes.InvalidResponse)
new ConnectorError(
ConnectorErrorCodes.InvalidResponse,
`Invalid response raw body type: ${typeof rawBody}`
)
);
errorHandler(rawBody);

View file

@ -41,7 +41,10 @@ const sendMessage =
assert(
template,
new ConnectorError(ConnectorErrorCodes.TemplateNotFound, `Cannot find template!`)
new ConnectorError(
ConnectorErrorCodes.TemplateNotFound,
`Cannot find template for type: ${type}`
)
);
try {
@ -56,37 +59,49 @@ const sendMessage =
accessKeySecret
);
const { body: rawBody } = httpResponse;
const { Code, Message, ...rest } = parseResponseString(httpResponse.body);
const { Code, Message, ...rest } = parseResponseString(rawBody);
assert(
Code === 'OK',
new ConnectorError(
/**
* See https://help.aliyun.com/document_detail/101347.html for more details.
* Some errors (like rate limit) can be addressed by end users.
*/
Code === 'isv.BUSINESS_LIMIT_CONTROL'
? ConnectorErrorCodes.RateLimitExceeded
: ConnectorErrorCodes.General,
{
errorDescription: Message,
Code,
...rest,
}
)
);
if (Code !== 'OK') {
return { Code, Message, ...rest };
} catch (error: unknown) {
if (error instanceof HTTPError) {
const {
response: { body: rawBody },
} = error;
assert(
typeof rawBody === 'string',
new ConnectorError(
ConnectorErrorCodes.InvalidResponse,
`Invalid response raw body type: ${typeof rawBody}`
)
);
const { Message, ...rest } = parseResponseString(rawBody);
throw new ConnectorError(ConnectorErrorCodes.General, {
errorDescription: Message,
Code,
...rest,
});
}
return httpResponse;
} catch (error: unknown) {
if (!(error instanceof HTTPError)) {
throw error;
}
const {
response: { body: rawBody },
} = error;
assert(typeof rawBody === 'string', new ConnectorError(ConnectorErrorCodes.InvalidResponse));
const { Code, Message, ...rest } = parseResponseString(rawBody);
throw new ConnectorError(ConnectorErrorCodes.General, {
errorDescription: Message,
Code,
...rest,
});
throw error;
}
};

View file

@ -1,6 +1,6 @@
import { assert } from '@silverhand/essentials';
import type { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2';
import type { SESv2Client, SendEmailCommand, SendEmailCommandOutput } from '@aws-sdk/client-sesv2';
import { SESv2ServiceException } from '@aws-sdk/client-sesv2';
import type {
CreateConnector,
@ -42,18 +42,19 @@ const sendMessage =
const command: SendEmailCommand = makeCommand(config, emailContent, to);
try {
const response = await client.send(command);
const response: SendEmailCommandOutput = await client.send(command);
if (response.$metadata.httpStatusCode !== 200) {
throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, { response });
}
assert(
response.$metadata.httpStatusCode === 200,
new ConnectorError(ConnectorErrorCodes.InvalidResponse, response)
);
return response.MessageId;
} catch (error: unknown) {
if (error instanceof SESv2ServiceException) {
const { message } = error;
throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, message);
throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, error.message);
}
throw error;
}
};

View file

@ -75,9 +75,13 @@ const sendMessage =
const {
response: { body: rawBody },
} = error;
assert(
typeof rawBody === 'string',
new ConnectorError(ConnectorErrorCodes.InvalidResponse)
new ConnectorError(
ConnectorErrorCodes.InvalidResponse,
`Invalid response raw body type: ${typeof rawBody}`
)
);
throw new ConnectorError(ConnectorErrorCodes.General, rawBody);

View file

@ -60,7 +60,10 @@ const sendMessage =
} = error;
assert(
typeof rawBody === 'string',
new ConnectorError(ConnectorErrorCodes.InvalidResponse)
new ConnectorError(
ConnectorErrorCodes.InvalidResponse,
`Invalid response raw body type: ${typeof rawBody}`
)
);
throw new ConnectorError(ConnectorErrorCodes.General, rawBody);

View file

@ -187,6 +187,24 @@ describe('koaConnectorErrorHandler middleware', () => {
);
});
it('Rate Limit Exceeded', async () => {
const message = 'Mock Rate Limit Exceeded';
const error = new ConnectorError(ConnectorErrorCodes.RateLimitExceeded, message);
next.mockImplementationOnce(() => {
throw error;
});
await expect(koaConnectorErrorHandler()(ctx, next)).rejects.toMatchError(
new RequestError(
{
code: 'connector.rate_limit_exceeded',
status: 429,
},
{ message }
)
);
});
it('General connector errors with string type messages', async () => {
const message = 'Mock General connector errors';
const error = new ConnectorError(ConnectorErrorCodes.General, message);

View file

@ -52,6 +52,10 @@ export default function koaConnectorErrorHandler<StateT, ContextT>(): Middleware
throw new RequestError({ code: `connector.${code}`, status: 501 }, data);
}
case ConnectorErrorCodes.RateLimitExceeded: {
throw new RequestError({ code: `connector.${code}`, status: 429 }, data);
}
default: {
throw new RequestError(
{

View file

@ -12,6 +12,7 @@ const connector = {
invalid_response: 'Die Antwort des Connectors ist ungültig.',
template_not_found:
'Die richtige Vorlage in der Connector-Konfiguration konnte nicht gefunden werden.',
rate_limit_exceeded: 'Auslöser-Rate-Limit. Bitte versuchen Sie es später erneut.',
not_implemented: '{{method}}: wurde noch nicht implementiert.',
social_invalid_access_token: 'Der Access Token des Connectors ist ungültig.',
invalid_auth_code: 'Der Authentifizierungscode des Connectors ist ungültig.',
@ -38,5 +39,4 @@ const connector = {
cannot_overwrite_metadata_for_non_standard_connector:
"Die 'Metadaten' dieses Connectors können nicht überschrieben werden.",
};
export default connector;

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: "The connector's config is invalid.",
invalid_response: "The connector's response is invalid.",
template_not_found: 'Unable to find correct template in connector config.',
rate_limit_exceeded: 'Trigger rate limit. Please try again later.',
not_implemented: '{{method}}: has not been implemented yet.',
social_invalid_access_token: "The connector's access token is invalid.",
invalid_auth_code: "The connector's auth code is invalid.",

View file

@ -11,6 +11,7 @@ const connector = {
invalid_response: 'La respuesta del conector es inválida.',
template_not_found:
'No se puede encontrar la plantilla correcta en la configuración del conector.',
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.',
social_invalid_access_token: 'El token de acceso del conector es inválido.',
invalid_auth_code: 'El código de autenticación del conector es inválido.',

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: "La configuration 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.',
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.",
social_invalid_access_token: "Le jeton d'accès du connecteur n'est pas valide.",
invalid_auth_code: "Le code d'authentification du connecteur n'est pas valide.",

View file

@ -11,6 +11,7 @@ const connector = {
invalid_response: 'La risposta del connettore non è valida.',
template_not_found:
'Impossibile trovare il modello corretto nella configurazione del connettore.',
rate_limit_exceeded: 'Limite di frequenza attivata. Riprova più tardi.',
not_implemented: '{{method}}: non è stato ancora implementato.',
social_invalid_access_token: 'Il token di accesso del connettore non è valido.',
invalid_auth_code: 'Il codice di autenticazione del connettore non è valido.',

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: 'コネクタの設定が無効です。',
invalid_response: 'コネクタのレスポンスが無効です。',
template_not_found: 'コネクタ構成から正しいテンプレートを見つけることができませんでした。',
rate_limit_exceeded: 'トリガーレート制限。後でもう一度お試しください。',
not_implemented: '{{method}}:まだ実装されていません。',
social_invalid_access_token: 'コネクタのアクセストークンが無効です。',
invalid_auth_code: 'コネクタの認証コードが無効です。',

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: '연동 설정이 유효하지 않아요.',
invalid_response: '연동 응답이 유효하지 않아요.',
template_not_found: '연동 예제 설정을 찾을 수 없어요.',
rate_limit_exceeded: '트리거 주기 제한. 나중에 다시 시도하세요.',
not_implemented: '{{method}}은 아직 구현되지 않았어요.',
social_invalid_access_token: '연동 서비스의 Access 토큰이 유효하지 않아요.',
invalid_auth_code: '연동 서비스의 Auth 코드가 유효하지 않아요.',

View file

@ -11,6 +11,7 @@ const connector = {
invalid_config: 'Konfiguracja łącznika jest nieprawidłowa.',
invalid_response: 'Odpowiedź łącznika jest nieprawidłowa.',
template_not_found: 'Nie można znaleźć poprawnego szablonu w konfiguracji łącznika.',
rate_limit_exceeded: 'Ograniczenie szybkości wywołań. Spróbuj ponownie później.',
not_implemented: '{{method}}: jeszcze nie zaimplementowano.',
social_invalid_access_token: 'Token dostępu łącznika jest nieprawidłowy.',
invalid_auth_code: 'Kod autoryzacji łącznika jest nieprawidłowy.',

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: 'A configuração 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.',
rate_limit_exceeded: 'Limite de taxa de acionamento. Tente novamente mais tarde.',
not_implemented: '{{method}}: ainda não foi implementado.',
social_invalid_access_token: 'O token de acesso do conector é inválido.',
invalid_auth_code: 'O código de autenticação do conector é inválido.',

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: 'A configuração 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.',
rate_limit_exceeded: 'Limite de taxa de ativação. Por favor, tente novamente mais tarde.',
not_implemented: '{{method}}: ainda não foi implementado.',
social_invalid_access_token: 'O token de acesso do conector é inválido.',
invalid_auth_code: 'O código de autenticação do conector é inválido.',

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: 'Конфигурация коннектора недействительна.',
invalid_response: 'Ответ коннектора недействителен.',
template_not_found: 'Невозможно найти правильный шаблон в конфигурации коннектора.',
rate_limit_exceeded: 'Превышен лимит запросов. Пожалуйста, попробуйте позже.',
not_implemented: '{{method}}: еще не реализован.',
social_invalid_access_token: 'Токен доступа коннектора недействителен.',
invalid_auth_code: 'Код аутентификации коннектора недействителен.',
@ -34,4 +35,5 @@ const connector = {
cannot_overwrite_metadata_for_non_standard_connector:
'Метаданные этого коннектора не могут быть перезаписаны.',
};
export default connector;

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: 'Bağlayıcının ayarları 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.',
rate_limit_exceeded: 'Tetikleyici oran sınırına ulaşıldı. Lütfen daha sonra tekrar deneyin.',
not_implemented: '{{method}}: henüz uygulanmadı.',
social_invalid_access_token: 'Bağlayıcının erişim tokenı geçersiz.',
invalid_auth_code: 'Bağlayıcının yetki kodu geçersiz.',

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: '连接器配置错误',
invalid_response: '连接器错误响应',
template_not_found: '无法从连接器配置中找到对应的模板',
rate_limit_exceeded: '触发速率限制。请稍后再试。',
not_implemented: '方法 {{method}} 尚未实现',
social_invalid_access_token: '当前连接器的 access_token 无效',
invalid_auth_code: '当前连接器的授权码无效',

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: '連接器配置錯誤',
invalid_response: '連接器錯誤響應',
template_not_found: '無法從連接器配置中找到對應的模板',
rate_limit_exceeded: '觸發速率限制。請稍後再試。',
not_implemented: '方法 {{method}} 尚未實現',
social_invalid_access_token: '當前連接器的 access_token 無效',
invalid_auth_code: '當前連接器的授權碼無效',

View file

@ -10,6 +10,7 @@ const connector = {
invalid_config: '連接器配置錯誤',
invalid_response: '連接器錯誤響應',
template_not_found: '無法從連接器配置中找到對應的模板',
rate_limit_exceeded: '觸發速率限制。請稍後再試。',
not_implemented: '方法 {{method}} 尚未實現',
social_invalid_access_token: '當前連接器的 access_token 無效',
invalid_auth_code: '當前連接器的授權碼無效',

View file

@ -49,6 +49,7 @@ export enum ConnectorErrorCodes {
InvalidConfig = 'invalid_config',
InvalidResponse = 'invalid_response',
TemplateNotFound = 'template_not_found',
RateLimitExceeded = 'rate_limit_exceeded',
NotImplemented = 'not_implemented',
SocialAuthCodeInvalid = 'social_auth_code_invalid',
SocialAccessTokenInvalid = 'social_invalid_access_token',