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,5 +1,5 @@
|
||||
/**
|
||||
* Phase 4c — Auto-detect anchor scanner.
|
||||
* Phase 4c - Auto-detect anchor scanner.
|
||||
*
|
||||
* Scans a PDF for common signing-block keywords ("Signature:", "Date:",
|
||||
* "Initials", a long run of underscores, etc.) and proposes Documenso
|
||||
@@ -12,7 +12,7 @@
|
||||
* regexes are tried in priority order so a `"Date of Signature:"`
|
||||
* anchor doesn't double-place as both DATE and SIGNATURE.
|
||||
*
|
||||
* This is intentionally pdf-content driven (text-extraction based) —
|
||||
* This is intentionally pdf-content driven (text-extraction based) -
|
||||
* the alternative (image-of-PDF + OCR) is the bigger berth-PDF parser
|
||||
* tier-3 path; we keep this lightweight so it runs in <500ms on a
|
||||
* 10-page contract.
|
||||
@@ -30,7 +30,7 @@ export interface DetectedField {
|
||||
pageY: number;
|
||||
pageWidth: number;
|
||||
pageHeight: number;
|
||||
/** 0..1 — how sure the scanner is. */
|
||||
/** 0..1 - how sure the scanner is. */
|
||||
confidence: number;
|
||||
/** Verbatim anchor that triggered the detection (display + debug). */
|
||||
anchorText: string;
|
||||
@@ -42,7 +42,7 @@ export interface DetectedField {
|
||||
|
||||
/** Anchor → field-type pattern table. Order matters: earlier patterns
|
||||
* win when two anchors overlap on the same text item (e.g. "Date of
|
||||
* Signature" matches both DATE and SIGNATURE — DATE goes first because
|
||||
* Signature" matches both DATE and SIGNATURE - DATE goes first because
|
||||
* it's the more specific pattern). */
|
||||
interface AnchorPattern {
|
||||
type: DocumensoFieldType;
|
||||
@@ -58,7 +58,7 @@ interface AnchorPattern {
|
||||
}
|
||||
|
||||
const ANCHOR_PATTERNS: AnchorPattern[] = [
|
||||
// DATE — more specific than SIGNATURE for the common "Date of
|
||||
// DATE - more specific than SIGNATURE for the common "Date of
|
||||
// Signature:" case, so listed first.
|
||||
{
|
||||
type: 'DATE',
|
||||
@@ -67,7 +67,7 @@ const ANCHOR_PATTERNS: AnchorPattern[] = [
|
||||
heightPt: 20,
|
||||
confidenceBoost: 0.2,
|
||||
},
|
||||
// INITIALS — pre-empts NAME because "Initial:" is short and unique.
|
||||
// INITIALS - pre-empts NAME because "Initial:" is short and unique.
|
||||
{
|
||||
type: 'INITIALS',
|
||||
match: /(?:^|\b)(?:initials?)[:\s_-]+/i,
|
||||
@@ -75,7 +75,7 @@ const ANCHOR_PATTERNS: AnchorPattern[] = [
|
||||
heightPt: 30,
|
||||
confidenceBoost: 0.2,
|
||||
},
|
||||
// EMAIL — explicit email anchor.
|
||||
// EMAIL - explicit email anchor.
|
||||
{
|
||||
type: 'EMAIL',
|
||||
match: /(?:^|\b)e-?mail[:\s_-]+/i,
|
||||
@@ -83,7 +83,7 @@ const ANCHOR_PATTERNS: AnchorPattern[] = [
|
||||
heightPt: 20,
|
||||
confidenceBoost: 0.2,
|
||||
},
|
||||
// NAME — printed/full name labels.
|
||||
// NAME - printed/full name labels.
|
||||
{
|
||||
type: 'NAME',
|
||||
match: /(?:^|\b)(?:printed\s*)?(?:full\s+)?name[:\s_-]+/i,
|
||||
@@ -91,7 +91,7 @@ const ANCHOR_PATTERNS: AnchorPattern[] = [
|
||||
heightPt: 20,
|
||||
confidenceBoost: 0.15,
|
||||
},
|
||||
// SIGNATURE — broadest of the signing-block patterns.
|
||||
// SIGNATURE - broadest of the signing-block patterns.
|
||||
{
|
||||
type: 'SIGNATURE',
|
||||
match: /(?:^|\b)(?:signature|sign\s*here|signed\s*by|signed\s*at)[:\s_-]+/i,
|
||||
@@ -99,7 +99,7 @@ const ANCHOR_PATTERNS: AnchorPattern[] = [
|
||||
heightPt: 30,
|
||||
confidenceBoost: 0.2,
|
||||
},
|
||||
// SIGNATURE — explicit "X" mark followed by a blank line.
|
||||
// SIGNATURE - explicit "X" mark followed by a blank line.
|
||||
{
|
||||
type: 'SIGNATURE',
|
||||
match: /X\s*_{4,}/,
|
||||
@@ -141,7 +141,7 @@ interface PdfTextItem {
|
||||
transform: number[];
|
||||
/** Item width in PDF user-space units. */
|
||||
width?: number;
|
||||
/** Item height — usually equals scaleY. */
|
||||
/** Item height - usually equals scaleY. */
|
||||
height?: number;
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ export async function detectFields(pdfBuffer: Buffer): Promise<DetectedField[]>
|
||||
for (const page of pages) {
|
||||
for (const item of page.items) {
|
||||
const lower = item.str.toLowerCase();
|
||||
// Skip if the item has no positional data — defensive against
|
||||
// Skip if the item has no positional data - defensive against
|
||||
// exotic PDF encodings.
|
||||
if (!Array.isArray(item.transform) || item.transform.length < 6) continue;
|
||||
const translateX = Number(item.transform[4]);
|
||||
@@ -187,7 +187,7 @@ export async function detectFields(pdfBuffer: Buffer): Promise<DetectedField[]>
|
||||
const fieldXPt = translateX + anchorWidthPt + 5;
|
||||
// PDF user-space origin is the lower-left; transform[5] is the
|
||||
// baseline of the text so the field's lower-left also lives
|
||||
// there. CSS/web origin is top-left — we keep the percent in
|
||||
// there. CSS/web origin is top-left - we keep the percent in
|
||||
// PDF coordinates here because Documenso accepts both (the
|
||||
// existing placeFields helper handles the conversion).
|
||||
const fieldYPt = translateY;
|
||||
@@ -197,7 +197,7 @@ export async function detectFields(pdfBuffer: Buffer): Promise<DetectedField[]>
|
||||
const pageWidth = (pattern.widthPt / page.widthPt) * 100;
|
||||
const pageHeight = (pattern.heightPt / page.heightPt) * 100;
|
||||
|
||||
// Hard-skip fields that would land off-page (defensive — a
|
||||
// Hard-skip fields that would land off-page (defensive - a
|
||||
// misparsed transform can blow up the coordinate space).
|
||||
if (pageX < 0 || pageX > 95 || pageY < 0 || pageY > 95) continue;
|
||||
if (pageWidth <= 0 || pageHeight <= 0) continue;
|
||||
@@ -215,7 +215,7 @@ export async function detectFields(pdfBuffer: Buffer): Promise<DetectedField[]>
|
||||
anchorText: item.str.trim(),
|
||||
inferredRecipientLabel: recipientLabel,
|
||||
});
|
||||
// First matching pattern wins for this item — earlier
|
||||
// First matching pattern wins for this item - earlier
|
||||
// (more-specific) patterns shadow later ones.
|
||||
break;
|
||||
}
|
||||
@@ -258,7 +258,7 @@ function inferRecipient(
|
||||
* import it dynamically so the heavy native-bindings dep only loads
|
||||
* when the detector actually runs.
|
||||
*
|
||||
* Returns an empty array if pdfjs fails to parse — the rep gets the
|
||||
* Returns an empty array if pdfjs fails to parse - the rep gets the
|
||||
* manual placement flow without an error toast.
|
||||
*/
|
||||
export async function extractPdfPages(pdfBuffer: Buffer): Promise<PdfPageView[]> {
|
||||
@@ -285,7 +285,7 @@ export async function extractPdfPages(pdfBuffer: Buffer): Promise<PdfPageView[]>
|
||||
return pages;
|
||||
} catch {
|
||||
// Image-only scans or corrupt PDFs land here. The dialog falls
|
||||
// back to manual placement — no rep-facing error needed.
|
||||
// back to manual placement - no rep-facing error needed.
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user