export type CircuitState = "closed" | "open" | "half-open";
export interface CircuitBreakerOptions {
failureThreshold: number;
resetTimeout: number; // ms to wait in "open" before probing
onStateChange?: (from: CircuitState, to: CircuitState) => void;
import { QueryResultRow } from 'pg';
import { pool, Queryable } from './db';
export abstract class BaseRepository<T extends QueryResultRow> {
protected abstract readonly table: string;
import { z } from "zod";
const coerceNumber = z.preprocess((v) => {
if (v === "" || v === undefined) return undefined;
if (typeof v !== "string") return v;
const n = Number(v);
import { Prisma, PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
type TxClient = Prisma.TransactionClient;
import { defineConfig, devices } from '@playwright/test';
import path from 'node:path';
export const authFile = path.join(__dirname, '.auth/user.json');
export default defineConfig({
import express, { Express, NextFunction, Request, Response } from 'express';
import { userRoutes } from './userRoutes';
function authenticate(req: Request, res: Response, next: NextFunction) {
const header = req.header('authorization');
if (!header || !header.startsWith('Bearer ')) {
export type CheckResult = { name: string; status: 'up' | 'down'; durationMs: number; error?: string };
export type Check = () => Promise<void>;
function withTimeout(fn: Check, ms: number): Promise<void> {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error(`timeout after ${ms}ms`)), ms);
FROM node:20-alpine AS base
WORKDIR /app
RUN apk add --no-cache libc6-compat
FROM base AS deps
COPY package.json package-lock.json ./
name: CI
on:
push:
branches: [main]
pull_request:
export interface PageInfo {
hasNextPage: boolean;
hasPreviousPage: boolean;
startCursor: string | null;
endCursor: string | null;
}
export const FLAG_REGISTRY = {
newDashboard: {
default: false as boolean,
description: 'Renders the redesigned dashboard shell',
},
maxUploadMb: {
import { Writable } from "node:stream";
import type { Pool } from "pg";
interface Row {
email: string;
name: string;