2023-03-24 21:08:36 +00:00
|
|
|
import { InputMessage, OutputMessage, Policy } from './types.ts';
|
2023-03-24 19:36:11 +00:00
|
|
|
|
2023-03-25 01:17:51 +00:00
|
|
|
/** A policy function with opts to run it with. Used by the pipeline. */
|
2023-03-25 03:33:12 +00:00
|
|
|
type PolicyTuple<P extends Policy = Policy> = [policy: P, opts?: InferPolicyOpts<P>];
|
|
|
|
/** Infer opts from the policy. */
|
|
|
|
type InferPolicyOpts<P> = P extends Policy<infer Opts> ? Opts : never;
|
2023-03-25 00:55:58 +00:00
|
|
|
|
2023-03-25 13:24:47 +00:00
|
|
|
/** Helper type for proper type inference of PolicyTuples. */
|
2023-03-25 01:06:03 +00:00
|
|
|
// https://stackoverflow.com/a/75806165
|
|
|
|
// https://stackoverflow.com/a/54608401
|
2023-03-25 13:24:47 +00:00
|
|
|
type Policies<T extends any[]> = {
|
2023-03-25 01:17:51 +00:00
|
|
|
[K in keyof T]: PolicyTuple<T[K]> | Policy<T[K]>;
|
|
|
|
};
|
2023-03-25 00:55:58 +00:00
|
|
|
|
2023-03-30 19:18:18 +00:00
|
|
|
/**
|
|
|
|
* Processes messages through multiple policies.
|
|
|
|
*
|
|
|
|
* If any policy returns a `reject` or `shadowReject` action, the pipeline will stop and return the rejected message.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```ts
|
|
|
|
* const result = await pipeline(msg, [
|
|
|
|
* noopPolicy,
|
|
|
|
* [filterPolicy, { kinds: [0, 1, 3, 5, 7, 1984, 9734, 9735, 10002] }],
|
|
|
|
* [keywordPolicy, ['https://t.me/']],
|
|
|
|
* [regexPolicy, /(🟠|🔥|😳)ChtaGPT/i],
|
|
|
|
* [pubkeyBanPolicy, ['e810fafa1e89cdf80cced8e013938e87e21b699b24c8570537be92aec4b12c18']],
|
|
|
|
* [hellthreadPolicy, { limit: 100 }],
|
|
|
|
* [rateLimitPolicy, { whitelist: ['127.0.0.1'] }],
|
|
|
|
* [antiDuplicationPolicy, { ttl: 60000, minLength: 50 }],
|
|
|
|
* ]);
|
|
|
|
* ```
|
|
|
|
*/
|
2023-03-25 13:24:47 +00:00
|
|
|
async function pipeline<T extends unknown[]>(msg: InputMessage, policies: [...Policies<T>]): Promise<OutputMessage> {
|
|
|
|
for (const item of policies as (Policy | PolicyTuple)[]) {
|
2023-03-25 01:06:03 +00:00
|
|
|
const [policy, opts] = toTuple(item);
|
2023-03-25 00:55:58 +00:00
|
|
|
const result = await policy(msg, opts);
|
2023-03-24 21:08:36 +00:00
|
|
|
if (result.action !== 'accept') {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
id: msg.event.id,
|
|
|
|
action: 'accept',
|
|
|
|
msg: '',
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-03-25 01:06:03 +00:00
|
|
|
/** Coerce item into a tuple if it isn't already. */
|
2023-03-25 03:33:12 +00:00
|
|
|
function toTuple<P extends Policy>(item: PolicyTuple<P> | P): PolicyTuple<P> {
|
2023-03-25 01:06:03 +00:00
|
|
|
return typeof item === 'function' ? [item] : item;
|
|
|
|
}
|
|
|
|
|
2023-03-24 21:08:36 +00:00
|
|
|
export default pipeline;
|
2023-03-25 01:27:07 +00:00
|
|
|
|
|
|
|
export type { PolicyTuple };
|