strfry-policies/src/pipeline.ts

40 lines
1.3 KiB
TypeScript
Raw Normal View History

import { InputMessage, OutputMessage, Policy } from './types.ts';
2023-03-24 14:36:11 -05:00
2023-03-24 20:17:51 -05:00
/** A policy function with opts to run it with. Used by the pipeline. */
2023-03-24 22:33:12 -05: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-24 19:55:58 -05:00
2023-03-24 20:17:51 -05:00
/** Helper type for proper type inference of PolicyTuples in the pipeline. */
2023-03-24 20:06:03 -05:00
// https://stackoverflow.com/a/75806165
// https://stackoverflow.com/a/54608401
2023-03-24 20:23:38 -05:00
type PolicySpread<T extends any[]> = {
2023-03-24 20:17:51 -05:00
[K in keyof T]: PolicyTuple<T[K]> | Policy<T[K]>;
};
2023-03-24 19:55:58 -05:00
/** Processes messages through multiple policies, bailing early on rejection. */
2023-03-24 20:23:38 -05:00
async function pipeline<T extends any[]>(msg: InputMessage, policies: [...PolicySpread<T>]): Promise<OutputMessage> {
2023-03-24 20:06:03 -05:00
for (const item of policies) {
const [policy, opts] = toTuple(item);
2023-03-24 19:55:58 -05:00
const result = await policy(msg, opts);
if (result.action !== 'accept') {
return result;
}
}
return {
id: msg.event.id,
action: 'accept',
msg: '',
};
}
2023-03-24 20:06:03 -05:00
/** Coerce item into a tuple if it isn't already. */
2023-03-24 22:33:12 -05:00
function toTuple<P extends Policy>(item: PolicyTuple<P> | P): PolicyTuple<P> {
2023-03-24 20:06:03 -05:00
return typeof item === 'function' ? [item] : item;
}
export default pipeline;
2023-03-24 20:27:07 -05:00
export type { PolicyTuple };