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:
@@ -1,13 +1,13 @@
|
||||
/**
|
||||
* Pluggable storage backend (Phase 6a — see docs/berth-recommender-and-pdf-plan.md §4.7a).
|
||||
* Pluggable storage backend (Phase 6a - see docs/berth-recommender-and-pdf-plan.md §4.7a).
|
||||
*
|
||||
* The CRM stores files (per-berth PDFs, brochures, GDPR exports, etc.) through a
|
||||
* single `StorageBackend` abstraction. The deployment chooses between an
|
||||
* S3-compatible store (MinIO / AWS S3 / Backblaze B2 / Cloudflare R2 / Wasabi /
|
||||
* Tigris) and a local filesystem at runtime via `system_settings.storage_backend`.
|
||||
*
|
||||
* Callers should always import from this barrel — never from `s3.ts` or
|
||||
* `filesystem.ts` directly — so the factory wiring stays the single source of
|
||||
* Callers should always import from this barrel - never from `s3.ts` or
|
||||
* `filesystem.ts` directly - so the factory wiring stays the single source of
|
||||
* truth.
|
||||
*/
|
||||
|
||||
@@ -24,7 +24,7 @@ export type StorageBackendName = 's3' | 'filesystem';
|
||||
|
||||
export interface PutOpts {
|
||||
contentType: string;
|
||||
/** Optional pre-computed sha256 hex — if absent, the backend computes one. */
|
||||
/** Optional pre-computed sha256 hex - if absent, the backend computes one. */
|
||||
sha256?: string;
|
||||
/** Bytes (for streams that don't expose .length); used for capacity pre-flight. */
|
||||
sizeBytes?: number;
|
||||
@@ -43,7 +43,7 @@ export interface PresignOpts {
|
||||
* verifier asserts the storage key starts with `${portSlug}/` when
|
||||
* present. S3 backend ignores this field (presigned S3 URLs carry
|
||||
* their own signature scope). Pass it whenever the issuer is in a
|
||||
* port-scoped request — `generateStorageKey()` already prefixes the
|
||||
* port-scoped request - `generateStorageKey()` already prefixes the
|
||||
* slug, so this is the matching enforcement.
|
||||
*/
|
||||
portSlug?: string;
|
||||
@@ -63,7 +63,7 @@ export interface StorageBackend {
|
||||
/** Existence + size check without reading the full body. Returns null when missing. */
|
||||
head(key: string): Promise<{ sizeBytes: number; contentType: string } | null>;
|
||||
|
||||
/** Delete. Idempotent — missing keys must not throw. */
|
||||
/** Delete. Idempotent - missing keys must not throw. */
|
||||
delete(key: string): Promise<void>;
|
||||
|
||||
/** Generate a short-lived URL the browser can PUT to. */
|
||||
@@ -129,7 +129,7 @@ async function readGlobalSetting<T = unknown>(key: string): Promise<T | null> {
|
||||
async function loadStorageConfig(): Promise<StorageConfigSnapshot> {
|
||||
// Each setting key is a separate row. We read them in parallel.
|
||||
// `storage_s3_access_key_encrypted` is the modern home for the S3 access
|
||||
// key (fixes audit S-23 — was previously stored plaintext at
|
||||
// key (fixes audit S-23 - was previously stored plaintext at
|
||||
// `storage_s3_access_key`). We still read the legacy plaintext key for
|
||||
// backward compat, but the encrypted form wins when both are present.
|
||||
const keys = [
|
||||
@@ -205,7 +205,7 @@ async function loadStorageConfig(): Promise<StorageConfigSnapshot> {
|
||||
* this comparison is a defense-in-depth backstop rather than the primary
|
||||
* invalidation path. If you ever change `loadStorageConfig` to read
|
||||
* additional sensitive material, make sure the rotation flow keeps
|
||||
* resetting the cache — relying on fingerprint diff alone means the old
|
||||
* resetting the cache - relying on fingerprint diff alone means the old
|
||||
* client is held in memory until the next mismatch.
|
||||
*/
|
||||
function fingerprint(cfg: StorageConfigSnapshot): string {
|
||||
@@ -250,13 +250,13 @@ async function buildBackend(cfg: StorageConfigSnapshot): Promise<StorageBackend>
|
||||
// ─── url helpers ────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Convenience wrapper that returns just the presigned download URL — the most
|
||||
* Convenience wrapper that returns just the presigned download URL - the most
|
||||
* common need at call sites that don't track expiry. Mirrors the legacy
|
||||
* `getPresignedUrl(key)` helper in `@/lib/minio` but routes through the
|
||||
* active backend so filesystem-mode deployments work too.
|
||||
*
|
||||
* storage-pathing-auditor H2: when `portSlug` is not passed explicitly,
|
||||
* we attempt to infer it from the key's first path segment — every
|
||||
* we attempt to infer it from the key's first path segment - every
|
||||
* storage key minted via `buildStoragePath(slug, …)` starts with the
|
||||
* slug, so the inference is correct for the overwhelming majority of
|
||||
* callers. This engages the filesystem-proxy port-binding token (`p`)
|
||||
@@ -287,7 +287,7 @@ export async function presignDownloadUrl(
|
||||
* A slug is conservatively defined as kebab/alphanumeric (the same
|
||||
* shape `createPortSchema` enforces). Non-matching first segments
|
||||
* include UUID-only keys like the legacy `berths/{id}/uploads/...`
|
||||
* shape — those are still served but skip the binding gate.
|
||||
* shape - those are still served but skip the binding gate.
|
||||
*/
|
||||
function inferPortSlugFromKey(key: string): string | undefined {
|
||||
const slash = key.indexOf('/');
|
||||
|
||||
Reference in New Issue
Block a user