TypeScript/Bun project scaffold

- Stack: Bun, Hono, Drizzle ORM, Zod, Handlebars, Pino
- Models: ticket, queue, transaction, scrip, template, custom_field, user, lifecycle
- Scrip engine: prepare/commit two-phase dispatch, template rendering, mock actions
- Lifecycle validator: state machine transition validation with wildcard support
- Routes: health, tickets (full CRUD + preview + transactions), queues, scrips, custom-fields, lifecycles
- Middleware: Pino logging, error handler
- Database: Drizzle ORM schema + initial migration (10 tables)
- Type-check: passes (tsc --noEmit, zero errors)
This commit is contained in:
Gjermund Høsøien Wiggen
2026-06-07 21:21:50 +02:00
parent 7be1810162
commit 1136227510
35 changed files with 2595 additions and 0 deletions

62
src/scrip/actions.ts Normal file
View File

@@ -0,0 +1,62 @@
export interface ActionExecutor {
execute(payload: ActionPayload): { success: boolean; message: string };
}
export interface ActionPayload {
scripId: string;
scripName: string;
actionType: string;
actionConfig: Record<string, unknown>;
recipients?: string[];
subject?: string;
body?: string;
url?: string;
method?: string;
headers?: Record<string, string>;
field_id?: string;
value?: string;
}
export class SendEmail implements ActionExecutor {
execute(payload: ActionPayload): { success: boolean; message: string } {
console.log('[SendEmail] Would send email:', {
subject: payload.subject ?? payload.actionConfig['subject'],
body: payload.body ?? payload.actionConfig['body'],
recipients: payload.recipients ?? payload.actionConfig['recipients'],
});
return { success: true, message: `Email queued: "${payload.subject ?? 'No subject'}"` };
}
}
export class Webhook implements ActionExecutor {
execute(payload: ActionPayload): { success: boolean; message: string } {
console.log('[Webhook] Would fire webhook:', {
url: payload.url ?? payload.actionConfig['url'],
method: payload.method ?? payload.actionConfig['method'] ?? 'POST',
headers: payload.headers ?? payload.actionConfig['headers'],
body: payload.body ?? payload.actionConfig['body'],
});
return { success: true, message: `Webhook fired: ${payload.url ?? 'unknown URL'}` };
}
}
export class SetCustomField implements ActionExecutor {
execute(payload: ActionPayload): { success: boolean; message: string } {
const fieldId = payload.field_id ?? String(payload.actionConfig['field_id'] ?? '');
const value = payload.value ?? String(payload.actionConfig['value'] ?? '');
console.log('[SetCustomField] Would set:', { field_id: fieldId, value });
return { success: true, message: `Custom field ${fieldId} set to "${value}"` };
}
}
const actionRegistry: Record<string, ActionExecutor> = {
SendEmail: new SendEmail(),
Webhook: new Webhook(),
SetCustomField: new SetCustomField(),
};
export function getActionExecutor(type: string): ActionExecutor | null {
return actionRegistry[type] ?? null;
}
export { actionRegistry };