diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 8bf9e12..6359c7e 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -18,12 +18,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup Biome - uses: biomejs/setup-biome@v2 - with: - version: 2.4.12 - name: Run Biome - run: biome ci . + run: npx --yes @biomejs/biome@2.4.12 ci . # Catches: # - lockfile drift (pnpm install --frozen-lockfile fails when diff --git a/.nvmrc b/.nvmrc index 1a2f5bd..a45fd52 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -lts/* \ No newline at end of file +24 diff --git a/Dockerfile b/Dockerfile index 70904ac..ec5a54a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ # which is NOT the case for Cloudflare Workers Builds. Turbo's remote # cache, by contrast, IS preserved, so we get a true "skip pnpm install # when the lockfile hasn't changed" path on every deploy. -FROM node:22-slim AS builder +FROM node:24-slim AS builder WORKDIR /app @@ -140,7 +140,7 @@ ENV TURBO_TOKEN="" \ # ── Stage 3: Production runner ─────────────────────────────────────────── -FROM node:22-slim AS runner +FROM node:24-slim AS runner WORKDIR /app diff --git a/app/api/shop/[orderId]/select-timeslot/route.ts b/app/api/shop/[orderId]/select-timeslot/route.ts index 1aef2da..01fa7cd 100644 --- a/app/api/shop/[orderId]/select-timeslot/route.ts +++ b/app/api/shop/[orderId]/select-timeslot/route.ts @@ -12,6 +12,8 @@ type RouteContext = { params: Promise<{ orderId: string }> }; * Customer selects (or changes) a pickup timeslot. * - PAID → AWAITING_PICKUP (first selection) * - AWAITING_PICKUP → AWAITING_PICKUP (re-selection / change) + * - PRINTED → PRINTED (change after the order has been printed; status is + * preserved so the admin still sees it as printed) * * Enforces capacity limits and includes pickup instructions in the response. * Triggers order confirmation email with pickup details and instructions. @@ -57,10 +59,14 @@ export async function POST(request: NextRequest, context: RouteContext) { return NextResponse.json({ error: "Order not found." }, { status: 404 }); } - if (order.status !== "PAID" && order.status !== "AWAITING_PICKUP") { + if ( + order.status !== "PAID" && + order.status !== "AWAITING_PICKUP" && + order.status !== "PRINTED" + ) { return NextResponse.json( { - error: `Cannot select timeslot for order in ${order.status} status. Order must be PAID or AWAITING_PICKUP.`, + error: `Cannot select timeslot for order in ${order.status} status. Order must be PAID, AWAITING_PICKUP, or PRINTED.`, }, { status: 400 }, ); @@ -93,7 +99,10 @@ export async function POST(request: NextRequest, context: RouteContext) { ); } - const isChangingTimeslot = order.status === "AWAITING_PICKUP"; + // An order is "changing" its timeslot (rather than selecting for the + // first time) whenever it already has one — i.e. any status past PAID. + const isChangingTimeslot = + order.status === "AWAITING_PICKUP" || order.status === "PRINTED"; const previousTimeslotId = isChangingTimeslot ? typeof order.pickupTimeslot === "object" && order.pickupTimeslot ? (order.pickupTimeslot as { id: string }).id diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index b209ca7..be32995 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -135,7 +135,7 @@ if [ "$#" -gt 0 ]; then # # We read grep's output into the positional params via a NUL-safe loop # (`grep -rlZ` + `read -d ''`) so paths with spaces/newlines are handled - # correctly. GNU coreutils in the node:22-slim runtime supports `grep -rlZ` + # correctly. GNU coreutils in the node:24-slim runtime supports `grep -rlZ` # and `read -d`; local validation must use GNU tools (see the CMD note above). # # Best-effort throughout: any non-zero exit is captured into `swap_status` diff --git a/package.json b/package.json index 4fb54a2..8f6f331 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "wrangler": "^4.83.0" }, "engines": { - "node": ">=20", + "node": ">=24", "pnpm": "^10.0.0" }, "//cloudflare-workarounds": "jose is an explicit dep because payload uses it for JWT but pnpm doesn't hoist it. canvas is overridden with a local stub because pdfjs-dist optionally requires it (native addon) which breaks the build. See shims/canvas/index.js for details.", diff --git a/scripts/docker-build-step.sh b/scripts/docker-build-step.sh index 9c083fd..06586c4 100644 --- a/scripts/docker-build-step.sh +++ b/scripts/docker-build-step.sh @@ -18,7 +18,7 @@ # falling back to a plain `next build`. # # Kept as a standalone POSIX shell script (sh, not bash) so it runs cleanly -# inside node:22-slim without requiring extra packages. +# inside node:24-slim without requiring extra packages. set -eu