chore(autonomous-session): consolidate uncommitted work from prior session

Bundles the prior autonomous-session output that was sitting unstaged:

- Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances)
- country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that
  never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk
  after the per-subpath dynamic-import approach silently failed in webpack)
- Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index,
  redirects (ocr to ai, reports to dashboard, invitations to users),
  docs/admin-ia-proposal.md
- Per-template email tester (registry + endpoint + UI on Email admin page)
- Cancel-document mode picker (delete-from-Documenso vs keep-for-audit)
- Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers
- Customize-widgets per-region sortables at xl+ (charts/rails/feed); single
  flat sortable below xl when the layout stacks; per-viewport saved orders
- Audit doc updates capturing each shipped item
- Lint fixes: react-compiler immutability in DonutChart (reduce instead of
  let-reassign), set-state-in-effect disables in CountryFlag and
  UploadForSigning preview-bytes effect, unused 'confirm' destructures in
  interest contract + reservation tabs, unescaped apostrophe in test-template
  card copy
This commit is contained in:
2026-05-23 00:52:59 +02:00
parent 43719b49e9
commit 221ae5784e
749 changed files with 7440 additions and 3118 deletions

View File

@@ -21,7 +21,7 @@ export async function resolvePortIdFromSlug(slug: string): Promise<string | null
if (!inFlightPortsLookup) {
inFlightPortsLookup = (async () => {
try {
// A17: use /me/ports works for every authenticated user.
// A17: use /me/ports - works for every authenticated user.
// The prior code hit /admin/ports which is super-admin-gated, so
// sales-reps/viewers fired a wasteful 400 on every page load.
const res = await fetch('/api/v1/me/ports', { credentials: 'include' });
@@ -46,7 +46,7 @@ export async function resolvePortIdFromSlug(slug: string): Promise<string | null
* Client-side fetch wrapper that attaches the `X-Port-Id` header to
* every request.
*
* multi-port-auditor C1: the URL slug is authoritative Zustand
* multi-port-auditor C1: the URL slug is authoritative - Zustand
* is a cache that lags by one render after `PortProvider`'s reconcile
* effect commits. The previous Zustand-first lookup caused first-load
* queries on a freshly-navigated port to fire with the PRIOR port's
@@ -65,7 +65,7 @@ export async function apiFetch<T = unknown>(url: string, opts: ApiFetchOptions =
}
}
// Fall back to the Zustand cache when the URL didn't yield a port
// Fall back to the Zustand cache when the URL didn't yield a port -
// e.g. global routes (/dashboard) where the rep hasn't picked a port
// yet but a previous session set one.
if (!portId) {
@@ -147,7 +147,7 @@ export async function apiFetch<T = unknown>(url: string, opts: ApiFetchOptions =
* `/admin/errors/<requestId>`
*
* Mutations should use the `toastError(err)` helper rather than reading
* these fields directly that keeps the toast format consistent.
* these fields directly - that keeps the toast format consistent.
*/
export class ApiError extends Error {
status: number;

View File

@@ -156,7 +156,7 @@ export function withAuth<TParams extends RouteParams = Record<string, string>>(
// 3. Resolve port context. Port id comes from the X-Port-Id
// header (set by the client after port selection), falling
// back to the user's default port preference. NEVER from the
// request body SECURITY-GUIDELINES.md §2.1.
// request body - SECURITY-GUIDELINES.md §2.1.
const portIdFromHeader = req.headers.get('X-Port-Id');
const portId =
portIdFromHeader ??
@@ -283,7 +283,7 @@ export function withAuth<TParams extends RouteParams = Record<string, string>>(
/**
* Throws ForbiddenError when the caller is not a super-admin. Use inside
* route handlers (after withAuth) for endpoints that mutate global, cross-
* tenant state global roles, cross-port migrations, system jobs.
* tenant state - global roles, cross-port migrations, system jobs.
*
* Logs the denied attempt to the audit trail (mirrors withPermission).
*/
@@ -393,8 +393,8 @@ export function withRateLimit(name: RateLimiterName, handler: RouteHandler): Rou
// ─── withPublicContext ───────────────────────────────────────────────────────
/**
* Wraps a public (unauthenticated) route webhooks, health checks,
* public APIs so it runs inside the same `runWithRequestContext` ALS
* Wraps a public (unauthenticated) route - webhooks, health checks,
* public APIs - so it runs inside the same `runWithRequestContext` ALS
* frame that `withAuth` installs for authenticated routes. Without this
* frame, `captureErrorEvent`, `getRequestId`, and the logger's request-id
* mixin silently no-op for these endpoints, leaving webhook failures
@@ -403,7 +403,7 @@ export function withRateLimit(name: RateLimiterName, handler: RouteHandler): Rou
* Top-level errors thrown by the handler are forwarded to
* `captureErrorEvent` (so they surface in admin/errors) and re-raised
* so Next's runtime can return a 500. Webhook handlers that prefer to
* always-return-200 can catch internally this wrapper only catches the
* always-return-200 can catch internally - this wrapper only catches the
* uncaught path.
*/
export function withPublicContext(

View File

@@ -24,7 +24,7 @@ export function parseQuery<T extends ZodSchema>(req: NextRequest, schema: T): z.
* H-14: tolerates empty request bodies (content-length 0 or req.json()
* throwing on an empty stream) by substituting `{}` so DELETE/PATCH
* routes whose schemas have all-optional fields don't crash with a
* 500 the schema's own optionality decides whether the empty object
* 500 - the schema's own optionality decides whether the empty object
* is a valid input.
*/
export async function parseBody<T extends ZodSchema>(
@@ -53,7 +53,7 @@ export function clientIp(req: NextRequest): string {
/**
* Wraps an unauthenticated route handler with a per-IP (or per-key) rate
* limit. Used for portal/auth endpoints that have no session yet the
* limit. Used for portal/auth endpoints that have no session yet - the
* `withRateLimit` helper in api/helpers.ts is keyed on `ctx.userId` and
* cannot apply here.
*

View File

@@ -5,7 +5,7 @@ import { toast } from 'sonner';
import { ApiError } from '@/lib/api/client';
/**
* Build a multi-line string suitable for an inline form banner the
* Build a multi-line string suitable for an inline form banner - the
* primary message followed by `Error code:` / `Reference ID:` lines when
* the error is an ApiError. Use from admin forms that want to keep
* their inline error UX instead of switching to a toast.