0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-06 20:40:08 -05:00

refactor(schemas): update hook schema (#3788)

This commit is contained in:
Xiao Yijun 2023-05-09 09:25:45 +08:00 committed by GitHub
parent 1066e5c707
commit 8fc5b78def
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 133 additions and 29 deletions

View file

@ -21,8 +21,12 @@ const url = 'https://logto.gg';
const hook: Hook = { const hook: Hook = {
tenantId: 'bar', tenantId: 'bar',
id: 'foo', id: 'foo',
name: 'hook_name',
event: HookEvent.PostSignIn, event: HookEvent.PostSignIn,
config: { headers: { bar: 'baz' }, url, retries: 3 }, events: [HookEvent.PostSignIn],
signingKey: 'signing_key',
enabled: true,
config: { headers: { bar: 'baz' }, url },
createdAt: Date.now() / 1000, createdAt: Date.now() / 1000,
}; };

View file

@ -78,7 +78,7 @@ export const createHookLibrary = (queries: Queries) => {
} satisfies Omit<HookEventPayload, 'hookId'>; } satisfies Omit<HookEventPayload, 'hookId'>;
await Promise.all( await Promise.all(
rows.map(async ({ config: { url, headers, retries }, id }) => { rows.map(async ({ config: { url, headers }, id }) => {
consoleLog.info(`\tTriggering hook ${id} due to ${hookEvent} event`); consoleLog.info(`\tTriggering hook ${id} due to ${hookEvent} event`);
const json: HookEventPayload = { hookId: id, ...payload }; const json: HookEventPayload = { hookId: id, ...payload };
const logEntry = new LogEntry(`TriggerHook.${hookEvent}`); const logEntry = new LogEntry(`TriggerHook.${hookEvent}`);
@ -90,7 +90,7 @@ export const createHookLibrary = (queries: Queries) => {
.post(url, { .post(url, {
headers: { 'user-agent': 'Logto (https://logto.io)', ...headers }, headers: { 'user-agent': 'Logto (https://logto.io)', ...headers },
json, json,
retry: { limit: retries }, retry: { limit: 3 },
timeout: { request: 10_000 }, timeout: { request: 10_000 },
}) })
.then(async (response) => { .then(async (response) => {

View file

@ -13,7 +13,6 @@ const createPayload = (event: HookEvent, url = 'not_work_url'): Partial<Hook> =>
config: { config: {
url, url,
headers: { foo: 'bar' }, headers: { foo: 'bar' },
retries: 3,
}, },
}); });

View file

@ -0,0 +1,105 @@
import { generateStandardId } from '@logto/shared';
import { sql } from 'slonik';
import type { AlterationScript } from '../lib/types/alteration.js';
enum HookEvent {
PostRegister = 'PostRegister',
PostSignIn = 'PostSignIn',
PostResetPassword = 'PostResetPassword',
}
type HookConfig = {
url: string;
headers?: Record<string, string>;
retries?: number;
};
type Hook = {
tenantId: string;
id: string;
name: string;
event: HookEvent | null;
events: HookEvent[];
config: HookConfig;
signingKey: string;
enabled: boolean;
createdAt: number;
};
const alteration: AlterationScript = {
up: async (pool) => {
await pool.query(sql`
alter table hooks
add column name varchar(256) not null default '',
add column events jsonb not null default '[]'::jsonb,
add column signing_key varchar(64) not null default '',
add column enabled boolean not null default true,
alter column event drop not null;
drop index hooks__event;
`);
},
down: async (pool) => {
await pool.query(sql`
delete from hooks where enabled = false;
`);
const { rows: hooks } = await pool.query<Hook>(sql`
select * from hooks;
`);
/* eslint-disable no-await-in-loop */
for (const { id, tenantId, events, config } of hooks) {
const { retries, ...rest } = config;
const updatedConfig = {
...rest,
retries: retries ?? 3,
};
if (events.length === 0) {
await pool.query(sql`
update hooks
set config = ${JSON.stringify(updatedConfig)}
where id = ${id} and tenant_id = ${tenantId};
`);
continue;
}
for (const [index, event] of events.entries()) {
if (index === 0) {
await pool.query(sql`
update hooks
set event = ${event},
config = ${JSON.stringify(updatedConfig)}
where id = ${id} and tenant_id = ${tenantId};
`);
continue;
}
// Create new hook when there are multiple events
const hookId = generateStandardId();
await pool.query(sql`
insert into hooks (id, tenant_id, event, config)
values (${hookId}, ${tenantId}, ${event}, ${JSON.stringify(updatedConfig)});
`);
}
}
/* eslint-enable no-await-in-loop */
await pool.query(sql`
alter table hooks
alter column event set not null,
drop column name,
drop column events,
drop column signing_key,
drop column enabled;
create index hooks__event on hooks (tenant_id, event);
`);
},
};
export default alteration;

View file

@ -200,23 +200,17 @@ export enum HookEvent {
export const hookEventGuard: z.ZodType<HookEvent> = z.nativeEnum(HookEvent); export const hookEventGuard: z.ZodType<HookEvent> = z.nativeEnum(HookEvent);
export type HookConfig = { export const hookEventsGuard = hookEventGuard.array();
export type HookEvents = z.infer<typeof hookEventsGuard>;
export const hookConfigGuard = z.object({
/** We don't need `type` since v1 only has web hook */ /** We don't need `type` since v1 only has web hook */
// type: 'web'; // type: 'web';
/** Method fixed to `POST` */ /** Method fixed to `POST` */
url: string;
/** Additional headers that attach to the request */
headers?: Record<string, string>;
/**
* Retry times when hook response status >= 500.
*
* Must be less than or equal to `3`. Use `0` to disable retry.
**/
retries: number;
};
export const hookConfigGuard: z.ZodType<HookConfig> = z.object({
url: z.string(), url: z.string(),
/** Additional headers that attach to the request */
headers: z.record(z.string()).optional(), headers: z.record(z.string()).optional(),
retries: z.number().gte(0).lte(3),
}); });
export type HookConfig = z.infer<typeof hookConfigGuard>;

View file

@ -2,12 +2,14 @@ create table hooks (
tenant_id varchar(21) not null tenant_id varchar(21) not null
references tenants (id) on update cascade on delete cascade, references tenants (id) on update cascade on delete cascade,
id varchar(21) not null, id varchar(21) not null,
event varchar(128) /* @use HookEvent */ not null, name varchar(256) not null default '',
event varchar(128) /* @use HookEvent */,
events jsonb /* @use HookEvents */ not null default '[]'::jsonb,
config jsonb /* @use HookConfig */ not null, config jsonb /* @use HookConfig */ not null,
signing_key varchar(64) not null default '',
enabled boolean not null default true,
created_at timestamptz not null default(now()), created_at timestamptz not null default(now()),
primary key (id) primary key (id)
); );
create index hooks__id on hooks (tenant_id, id); create index hooks__id on hooks (tenant_id, id);
create index hooks__event on hooks (tenant_id, event);