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

Merge pull request #5521 from logto-io/gao-allow-unknown-keys-in-message-payload

refactor: allow unknown keys in send message payload
This commit is contained in:
Gao Sun 2024-03-19 10:49:52 +08:00 committed by GitHub
commit 23bc5cdc8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 35 additions and 14 deletions

View file

@ -0,0 +1,5 @@
---
"@logto/connector-kit": patch
---
allow unknown properties in send message payload

View file

@ -21,6 +21,7 @@ import {
ZodUnion, ZodUnion,
ZodUnknown, ZodUnknown,
ZodDefault, ZodDefault,
ZodIntersection,
} from 'zod'; } from 'zod';
import RequestError from '#src/errors/RequestError/index.js'; import RequestError from '#src/errors/RequestError/index.js';
@ -279,5 +280,11 @@ export const zodTypeToSwagger = (
}; };
} }
if (config instanceof ZodIntersection) {
return {
allOf: [zodTypeToSwagger(config._def.left), zodTypeToSwagger(config._def.right)],
};
}
throw new RequestError('swagger.invalid_zod_type', config); throw new RequestError('swagger.invalid_zod_type', config);
}; };

View file

@ -59,15 +59,25 @@ describe('replaceSendMessageHandlebars', () => {
); );
}); });
it('should replace handlebars with empty string if payload does not contain the key', () => { it('should not replace handlebars if payload does not contain the key', () => {
const template = 'Your verification code is {{code}}'; const template = 'Your verification code is {{code}}';
const payload = {}; const payload = {};
expect(replaceSendMessageHandlebars(template, payload)).toEqual('Your verification code is '); expect(replaceSendMessageHandlebars(template, payload)).toEqual(
'Your verification code is {{code}}'
);
}); });
it('should ignore handlebars that are not in the predefined list for both template and payload', () => { it('should replace all handlebars even they are not in the predefined list for payload', () => {
const template = 'Your verification code is {{code}} and {{foo}}'; const template = 'Your verification code is {{code}} and {{foo}}';
const payload = { code: '123456', foo: 'bar' }; const payload = { code: '123456', foo: 'bar' };
expect(replaceSendMessageHandlebars(template, payload)).toEqual(
'Your verification code is 123456 and bar'
);
});
it('should ignore handlebars that are not in the payload', () => {
const template = 'Your verification code is {{code}} and {{foo}}';
const payload = { code: '123456' };
expect(replaceSendMessageHandlebars(template, payload)).toEqual( expect(replaceSendMessageHandlebars(template, payload)).toEqual(
'Your verification code is 123456 and {{foo}}' 'Your verification code is 123456 and {{foo}}'
); );

View file

@ -3,7 +3,6 @@ import type { ZodType, ZodTypeDef } from 'zod';
import { import {
ConnectorError, ConnectorError,
ConnectorErrorCodes, ConnectorErrorCodes,
sendMessagePayloadKeys,
type SendMessagePayload, type SendMessagePayload,
ConnectorType, ConnectorType,
} from './types/index.js'; } from './types/index.js';
@ -96,7 +95,7 @@ export const replaceSendMessageHandlebars = (
template: string, template: string,
payload: SendMessagePayload payload: SendMessagePayload
): string => { ): string => {
return sendMessagePayloadKeys.reduce( return Object.keys(payload).reduce(
(accumulator, key) => (accumulator, key) =>
accumulator.replaceAll(new RegExp(`{{\\s*${key}\\s*}}`, 'g'), payload[key] ?? ''), accumulator.replaceAll(new RegExp(`{{\\s*${key}\\s*}}`, 'g'), payload[key] ?? ''),
template template

View file

@ -32,6 +32,7 @@ export enum TemplateType {
export const templateTypeGuard = z.nativeEnum(TemplateType); export const templateTypeGuard = z.nativeEnum(TemplateType);
/** The payload for sending email or sms. */
export type SendMessagePayload = { export type SendMessagePayload = {
/** /**
* The dynamic verification code to send. It will replace the `{{code}}` handlebars in the * The dynamic verification code to send. It will replace the `{{code}}` handlebars in the
@ -44,16 +45,15 @@ export type SendMessagePayload = {
* @example 'https://example.com' * @example 'https://example.com'
*/ */
link?: string; link?: string;
}; } & Record<string, string>;
export const sendMessagePayloadKeys = ['code', 'link'] as const satisfies Array< /** The guard for {@link SendMessagePayload}. */
keyof SendMessagePayload export const sendMessagePayloadGuard = z
>; .object({
code: z.string().optional(),
export const sendMessagePayloadGuard = z.object({ link: z.string().optional(),
code: z.string().optional(), })
link: z.string().optional(), .and(z.record(z.string())) satisfies z.ZodType<SendMessagePayload>;
}) satisfies z.ZodType<SendMessagePayload>;
export const urlRegEx = export const urlRegEx =
/(https?:\/\/)?(?:www\.)?[\w#%+.:=@~-]{1,256}\.[\d()A-Za-z]{1,6}\b[\w#%&()+./:=?@~-]*/; /(https?:\/\/)?(?:www\.)?[\w#%+.:=@~-]{1,256}\.[\d()A-Za-z]{1,6}\b[\w#%&()+./:=?@~-]*/;