Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b54bbae65 | |||
| ce9fcfb362 | |||
| 59893908e2 | |||
| 2b78fcf731 | |||
| f12ec4f8d3 | |||
| 2c928ca4d7 | |||
| af75fecb66 | |||
| 2d4df6fe1e | |||
| db10320c8f | |||
| 40a4023c65 | |||
| d598511b75 |
@@ -0,0 +1,161 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
pull_request:
|
||||
branches: [main, dev]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref:
|
||||
description: "Branch or ref to run CI against"
|
||||
required: false
|
||||
default: "main"
|
||||
|
||||
jobs:
|
||||
lint-typecheck:
|
||||
name: Lint & Typecheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: '9.15.4'
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Typecheck
|
||||
run: pnpm typecheck
|
||||
|
||||
- name: Lint
|
||||
run: pnpm lint
|
||||
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: '9.15.4'
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm test
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint-typecheck, test]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: '9.15.4'
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
docker:
|
||||
name: Build & Push Docker Images
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Generate image tag
|
||||
id: version
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||
TAG="pr-${{ github.event.pull_request.number }}-${GITHUB_SHA::7}"
|
||||
else
|
||||
TAG="$(date -u +%Y.%m.%d)-${GITHUB_SHA::7}"
|
||||
fi
|
||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
||||
echo "Image tag: $TAG"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Gitea Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: git.farh.net
|
||||
username: ${{ gitea.actor }}
|
||||
password: ${{ gitea.token }}
|
||||
|
||||
- name: Build and push API image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
target: runner
|
||||
push: true
|
||||
tags: |
|
||||
git.farh.net/groombook/api:${{ steps.version.outputs.tag }}
|
||||
${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/api:latest' || '' }}
|
||||
cache-from: type=registry,ref=git.farh.net/groombook/cache:api
|
||||
cache-to: type=registry,ref=git.farh.net/groombook/cache:api,mode=max
|
||||
|
||||
- name: Build and push Migrate image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
target: migrate
|
||||
push: true
|
||||
tags: |
|
||||
git.farh.net/groombook/migrate:${{ steps.version.outputs.tag }}
|
||||
${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/migrate:latest' || '' }}
|
||||
cache-from: type=registry,ref=git.farh.net/groombook/cache:migrate
|
||||
cache-to: type=registry,ref=git.farh.net/groombook/cache:migrate,mode=max
|
||||
|
||||
- name: Build and push Seed image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
target: seed
|
||||
push: true
|
||||
tags: |
|
||||
git.farh.net/groombook/seed:${{ steps.version.outputs.tag }}
|
||||
${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/seed:latest' || '' }}
|
||||
cache-from: type=registry,ref=git.farh.net/groombook/cache:seed
|
||||
cache-to: type=registry,ref=git.farh.net/groombook/cache:seed,mode=max
|
||||
|
||||
- name: Build and push Reset image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
target: reset
|
||||
push: true
|
||||
tags: |
|
||||
git.farh.net/groombook/reset:${{ steps.version.outputs.tag }}
|
||||
${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/reset:latest' || '' }}
|
||||
cache-from: type=registry,ref=git.farh.net/groombook/cache:reset
|
||||
cache-to: type=registry,ref=git.farh.net/groombook/cache:reset,mode=max
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -202,20 +202,20 @@ jobs:
|
||||
echo "Updating dev overlay image tags to: $TAG"
|
||||
echo "Updating migration/seed Job names with SHA: $SHORT_SHA"
|
||||
cd /tmp/infra
|
||||
DEV_KUST="apps/groombook/overlays/dev/kustomization.yaml"
|
||||
DEV_KUST="apps/overlays/dev/kustomization.yaml"
|
||||
yq -i '(.images[] | select(.name == "ghcr.io/groombook/api")).newTag = env(TAG)' "$DEV_KUST"
|
||||
yq -i '(.images[] | select(.name == "ghcr.io/groombook/migrate")).newTag = env(TAG)' "$DEV_KUST"
|
||||
yq -i '(.images[] | select(.name == "ghcr.io/groombook/seed")).newTag = env(TAG)' "$DEV_KUST"
|
||||
yq -i '(.images[] | select(.name == "ghcr.io/groombook/reset")).newTag = env(TAG)' "$DEV_KUST"
|
||||
|
||||
MIGRATE_JOB="apps/groombook/base/migrate-job.yaml"
|
||||
MIGRATE_JOB="apps/base/migrate-job.yaml"
|
||||
if [ -f "$MIGRATE_JOB" ]; then
|
||||
yq -i '.metadata.name = "migrate-schema-" + env(SHORT_SHA)' "$MIGRATE_JOB"
|
||||
yq -i '.metadata.annotations."groombook.app/deploy-version" = env(TAG)' "$MIGRATE_JOB"
|
||||
yq -i '.spec.ttlSecondsAfterFinished = (.spec.ttlSecondsAfterFinished // 86400)' "$MIGRATE_JOB"
|
||||
fi
|
||||
|
||||
SEED_JOB="apps/groombook/base/seed-job.yaml"
|
||||
SEED_JOB="apps/base/seed-job.yaml"
|
||||
if [ -f "$SEED_JOB" ]; then
|
||||
yq -i '.metadata.name = "seed-test-data-" + env(SHORT_SHA)' "$SEED_JOB"
|
||||
yq -i '.metadata.annotations."groombook.app/deploy-version" = env(TAG)' "$SEED_JOB"
|
||||
@@ -237,7 +237,7 @@ jobs:
|
||||
git config user.name "groombook-engineer[bot]"
|
||||
git config user.email "3141748+groombook-engineer[bot]@users.noreply.github.com"
|
||||
git checkout -b "chore/update-image-tags-${TAG}"
|
||||
git add apps/groombook/overlays/dev/ apps/groombook/base/migrate-job.yaml apps/groombook/base/seed-job.yaml
|
||||
git add apps/overlays/dev/ apps/base/migrate-job.yaml apps/base/seed-job.yaml
|
||||
git commit -m "chore: update image tags and migration/seed Job names to ${TAG}"
|
||||
|
||||
git push -u origin "chore/update-image-tags-${TAG}"
|
||||
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
FROM node:20-alpine AS base
|
||||
FROM node:22-alpine AS base
|
||||
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
|
||||
WORKDIR /app
|
||||
|
||||
FROM base AS deps
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||
COPY apps/api/package.json apps/api/
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
@@ -12,12 +12,12 @@ RUN mkdir -p /home/node/.cache/node/corepack
|
||||
COPY apps/api/ apps/api/
|
||||
RUN pnpm --filter @groombook/api build
|
||||
|
||||
FROM node:20-alpine AS runner
|
||||
FROM node:22-alpine AS runner
|
||||
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||
COPY --from=builder /app/apps/api/package.json apps/api/
|
||||
COPY --from=builder /app/apps/api/dist apps/api/dist
|
||||
RUN pnpm install --frozen-lockfile --prod
|
||||
|
||||
@@ -21,8 +21,8 @@ const MANAGER: StaffRow = {
|
||||
|
||||
// ─── Mutable mock state ───────────────────────────────────────────────────────
|
||||
|
||||
const CLIENT_ID = "client-uuid-extended";
|
||||
const PET_ID = "pet-uuid-extended";
|
||||
const CLIENT_ID = "550e8400-e29b-41d4-a716-446655440001";
|
||||
const PET_ID = "660e8400-e29b-41d4-a716-446655440002";
|
||||
|
||||
let petRows: Record<string, unknown>[] = [];
|
||||
let appointmentRows: Record<string, unknown>[] = [];
|
||||
@@ -134,7 +134,7 @@ function makeDeleteChainable(): unknown {
|
||||
}
|
||||
if (prop === "returning") {
|
||||
return () => {
|
||||
const row = petRows[0];
|
||||
const row = petRows[0]!;
|
||||
deletedId = row.id as string;
|
||||
return [row];
|
||||
};
|
||||
@@ -163,10 +163,10 @@ vi.mock("../db", () => {
|
||||
}),
|
||||
pets,
|
||||
appointments,
|
||||
and,
|
||||
eq,
|
||||
exists,
|
||||
or,
|
||||
and: vi.fn(),
|
||||
eq: vi.fn(),
|
||||
exists: vi.fn(),
|
||||
or: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -67,6 +67,11 @@ vi.mock("../db", () => {
|
||||
{ get: (t, p) => (p === "_name" ? "impersonationSessions" : { table: "impersonationSessions", column: p }) }
|
||||
);
|
||||
|
||||
const impersonationAuditLogs = new Proxy(
|
||||
{ _name: "impersonationAuditLogs" },
|
||||
{ get: (t, p) => (p === "_name" ? "impersonationAuditLogs" : { table: "impersonationAuditLogs", column: p }) }
|
||||
);
|
||||
|
||||
const appointments = new Proxy(
|
||||
{ _name: "appointments" },
|
||||
{ get: (t, p) => (p === "_name" ? "appointments" : { table: "appointments", column: p }) }
|
||||
@@ -99,8 +104,12 @@ vi.mock("../db", () => {
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
insert: () => ({
|
||||
values: () => ({ returning: () => [{}] }),
|
||||
}),
|
||||
}),
|
||||
impersonationSessions,
|
||||
impersonationAuditLogs,
|
||||
appointments,
|
||||
eq: vi.fn(),
|
||||
and: vi.fn(),
|
||||
|
||||
@@ -103,6 +103,11 @@ export function buildPet(overrides: Partial<PetRow> & { clientId: string }): Pet
|
||||
photoKey: null,
|
||||
photoUploadedAt: null,
|
||||
image: null,
|
||||
coatType: null,
|
||||
temperamentScore: null,
|
||||
temperamentFlags: [],
|
||||
medicalAlerts: [],
|
||||
preferredCuts: [],
|
||||
createdAt: new Date("2025-01-01T00:00:00Z"),
|
||||
updatedAt: new Date("2025-01-01T00:00:00Z"),
|
||||
};
|
||||
|
||||
@@ -94,11 +94,6 @@ function pick<T>(arr: T[]): T {
|
||||
return arr[Math.floor(rand() * arr.length)]!;
|
||||
}
|
||||
|
||||
/** Return n distinct random elements from an array. */
|
||||
function pickN<T>(arr: T[], n: number): T[] {
|
||||
const shuffled = [...arr].sort(() => rand() - 0.5);
|
||||
return shuffled.slice(0, n);
|
||||
}
|
||||
|
||||
function randInt(min: number, max: number): number {
|
||||
return Math.floor(rand() * (max - min + 1)) + min;
|
||||
@@ -1105,7 +1100,7 @@ async function seed() {
|
||||
const groomer = pick(groomers);
|
||||
const bather = bathers.length > 0 && rand() < 0.6 ? pick(bathers) : null;
|
||||
|
||||
let startTime = randDate(appointmentsBackDate, now);
|
||||
const startTime = randDate(appointmentsBackDate, now);
|
||||
startTime.setHours(randInt(8, 16), pick([0, 15, 30, 45]), 0, 0);
|
||||
const endTime = new Date(startTime.getTime() + svc.dur * 60 * 1000);
|
||||
const effectivePrice = svc.price;
|
||||
|
||||
@@ -22,7 +22,7 @@ import { searchRouter } from "./routes/search.js";
|
||||
import { getObject } from "./lib/s3.js";
|
||||
import { calendarRouter } from "./routes/calendar.js";
|
||||
import { setupRouter } from "./routes/setup.js";
|
||||
import { getDb, businessSettings, eq, staff } from "./db";
|
||||
import { getDb, businessSettings, eq, staff } from "./db/index.js";
|
||||
import { authMiddleware } from "./middleware/auth.js";
|
||||
import { resolveStaffMiddleware, requireRole, requireRoleOrSuperUser, requireSuperUser } from "./middleware/rbac.js";
|
||||
import { devRouter } from "./routes/dev.js";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { betterAuth } from "better-auth";
|
||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||
import { genericOAuth } from "better-auth/plugins";
|
||||
import { getDb, authProviderConfig, eq } from "./db";
|
||||
import { decryptSecret } from "./db";
|
||||
import { getDb, authProviderConfig, eq } from "../db/index.js";
|
||||
import { decryptSecret } from "../db/index.js";
|
||||
import { sendEmail } from "../services/email.js";
|
||||
|
||||
const BETTER_AUTH_SECRET = process.env.BETTER_AUTH_SECRET;
|
||||
@@ -97,6 +97,9 @@ export async function initAuth(): Promise<void> {
|
||||
window: 10,
|
||||
storage: "memory",
|
||||
customRules: {
|
||||
"/sign-in/social": { max: 10, window: 60 },
|
||||
"/sign-in/email": { max: 10, window: 60 },
|
||||
"/sign-up/email": { max: 5, window: 60 },
|
||||
"/get-session": false,
|
||||
},
|
||||
},
|
||||
@@ -247,6 +250,9 @@ export async function initAuth(): Promise<void> {
|
||||
window: 10,
|
||||
storage: "memory",
|
||||
customRules: {
|
||||
"/sign-in/social": { max: 10, window: 60 },
|
||||
"/sign-in/email": { max: 10, window: 60 },
|
||||
"/sign-up/email": { max: 5, window: 60 },
|
||||
"/get-session": false,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
import { getDb, impersonationAuditLogs } from "../db";
|
||||
import { getDb, impersonationAuditLogs } from "../db/index.js";
|
||||
import type { PortalEnv } from "./portalSession.js";
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
import { and, eq, getDb, impersonationSessions } from "../db";
|
||||
import { and, eq, getDb, impersonationSessions } from "../db/index.js";
|
||||
|
||||
export interface PortalEnv {
|
||||
Variables: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
import { and, eq, getDb, sql, staff } from "../db";
|
||||
import { and, eq, getDb, sql, staff } from "../db/index.js";
|
||||
|
||||
export type StaffRole = "groomer" | "receptionist" | "manager";
|
||||
export type StaffRow = typeof staff.$inferSelect;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import { Hono } from "hono";
|
||||
import { eq, getDb, staff, clients, pets, services } from "./db";
|
||||
import { eq, getDb, staff, clients, pets, services } from "../../db/index.js";
|
||||
|
||||
export const adminSeedRouter = new Hono();
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
pets,
|
||||
services,
|
||||
staff,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const appointmentGroupsRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
reminderLogs,
|
||||
services,
|
||||
staff,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import { buildConfirmationEmail, sendEmail } from "../services/email.js";
|
||||
import { notifyWaitlistForAppointment } from "../services/waitlistNotify.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { eq, getDb, authProviderConfig, encryptSecret } from "../db";
|
||||
import { eq, getDb, authProviderConfig, encryptSecret } from "../db/index.js";
|
||||
import { requireSuperUser } from "../middleware/rbac.js";
|
||||
import { reinitAuth } from "../lib/auth.js";
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
appointments,
|
||||
clients,
|
||||
pets,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import {
|
||||
generateAvailableSlots,
|
||||
BUSINESS_START_HOUR,
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
pets,
|
||||
services,
|
||||
staff,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
|
||||
export const calendarRouter = new Hono();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { and, eq, exists, getDb, or, clients, appointments } from "../db";
|
||||
import { and, eq, exists, getDb, or, clients, appointments } from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const clientsRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Hono } from "hono";
|
||||
import { getDb, staff, clients, eq, sql } from "../db";
|
||||
import { getDb, staff, clients, eq, sql } from "../db/index.js";
|
||||
|
||||
const devRouter = new Hono();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { and, desc, eq, getDb, groomingVisitLogs, appointments, or } from "../db";
|
||||
import { and, desc, eq, getDb, groomingVisitLogs, appointments, or } from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const groomingLogsRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
impersonationAuditLogs,
|
||||
clients,
|
||||
desc,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const impersonationRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
services,
|
||||
clients,
|
||||
sql,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const invoicesRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { and, eq, exists, getDb, or, pets, appointments } from "../db";
|
||||
import { and, eq, exists, getDb, or, pets, appointments } from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
import {
|
||||
getPresignedUploadUrl,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { eq, inArray } from "../db";
|
||||
import { getDb, appointments, impersonationSessions, waitlistEntries, clients, pets, services, staff, invoices, invoiceLineItems } from "../db";
|
||||
import { eq, inArray } from "../db/index.js";
|
||||
import { getDb, appointments, impersonationSessions, waitlistEntries, clients, pets, services, staff, invoices, invoiceLineItems } from "../db/index.js";
|
||||
import { validatePortalSession } from "../middleware/portalSession.js";
|
||||
import { portalAudit } from "../middleware/portalAudit.js";
|
||||
import type { PortalEnv } from "../middleware/portalSession.js";
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
invoiceTipSplits,
|
||||
services,
|
||||
staff,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
|
||||
export const reportsRouter = new Hono();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Hono } from "hono";
|
||||
import { and, eq, getDb, clients, ilike, or, pets } from "../db";
|
||||
import { and, eq, getDb, clients, ilike, or, pets } from "../db/index.js";
|
||||
|
||||
export const searchRouter = new Hono();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { eq, getDb, services } from "../db";
|
||||
import { eq, getDb, services } from "../db/index.js";
|
||||
|
||||
export const servicesRouter = new Hono();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { eq, getDb, businessSettings } from "../db";
|
||||
import { eq, getDb, businessSettings } from "../db/index.js";
|
||||
import { getPresignedUploadUrl, deleteObject, putObject, getObject } from "../lib/s3.js";
|
||||
import { requireSuperUser } from "../middleware/rbac.js";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { and, eq, getDb, sql, staff, businessSettings, authProviderConfig, encryptSecret } from "../db";
|
||||
import { and, eq, getDb, sql, staff, businessSettings, authProviderConfig, encryptSecret } from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
const RATE_LIMIT_WINDOW_MS = 60_000;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { randomBytes } from "node:crypto";
|
||||
import { and, eq, getDb, ne, staff, appointments } from "../db";
|
||||
import { and, eq, getDb, ne, staff, appointments } from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const staffRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import Stripe from "stripe";
|
||||
import { z } from "zod/v3";
|
||||
import { eq, getDb, invoices } from "../db";
|
||||
import { eq, getDb, invoices } from "../db/index.js";
|
||||
import { getStripeClient } from "../services/payment.js";
|
||||
|
||||
export const webhooksRouter = new Hono();
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
clients,
|
||||
pets,
|
||||
services,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const waitlistRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Stripe from "stripe";
|
||||
import { getDb, clients, eq, inArray, invoices } from "../db";
|
||||
import { getDb, clients, eq, inArray, invoices } from "../db/index.js";
|
||||
|
||||
let _stripe: Stripe | null | undefined;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
staff,
|
||||
reminderLogs,
|
||||
session,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import {
|
||||
buildReminderEmail,
|
||||
sendEmail,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { and, eq, getDb, waitlistEntries, clients, pets, services } from "../db";
|
||||
import { and, eq, getDb, waitlistEntries, clients, pets, services } from "../db/index.js";
|
||||
import { buildWaitlistNotificationEmail, sendEmail } from "./email.js";
|
||||
|
||||
export async function notifyWaitlistForAppointment(
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@9.15.4",
|
||||
"license": "AGPL-3.0-only"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
packages:
|
||||
- "apps/*"
|
||||
- "packages/*"
|
||||
|
||||
Reference in New Issue
Block a user