@claritylabs/cl-sdk 3.0.28 → 3.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3339,12 +3339,47 @@ function firstMatch(nodes, patterns) {
3339
3339
  }
3340
3340
  return void 0;
3341
3341
  }
3342
+ var POLICY_NUMBER_PATTERNS = [
3343
+ /\bpolicy\s*(?:number|no\.?|#)\s*:?\s*([A-Z0-9][A-Z0-9,.-]{4,}[A-Z0-9])/i,
3344
+ /\bpolicy\s*[:#]\s*([A-Z0-9][A-Z0-9,.-]{4,}[A-Z0-9])/i
3345
+ ];
3346
+ function policyNumberEvidenceScore(node) {
3347
+ const text = normalizeWhitespace3([node.path, nodeText(node)].filter(Boolean).join(" ")).toLowerCase();
3348
+ let score = 0;
3349
+ if (/\b(policy\s+summary|declarations?|declaration\s+page|schedule)\b/.test(text)) score += 80;
3350
+ if (/\b(plan|policy\s+date|insured\s+person|named\s+insured|insurance\s+amount|benefit\s+amount)\b/.test(text)) score += 35;
3351
+ if (node.kind === "table_row" || node.kind === "table_cell" || node.kind === "text") score += 20;
3352
+ if (node.kind === "page") score += 10;
3353
+ if (typeof node.pageStart === "number" && node.pageStart > 1 && node.pageStart <= 10) score += 20;
3354
+ if (typeof node.pageStart === "number" && node.pageStart === 1) score -= 30;
3355
+ if (/\b(notices?\s+and\s+jacket|policy\s+jacket|front\s+matter|table\s+of\s+contents)\b/.test(text)) score -= 70;
3356
+ if (node.kind === "page_group" || node.kind === "form") score -= 30;
3357
+ return score;
3358
+ }
3359
+ function policyNumberFromNodes(nodes) {
3360
+ const candidates = nodes.slice(0, 120).flatMap((node) => {
3361
+ const text = nodeText(node);
3362
+ for (const pattern of POLICY_NUMBER_PATTERNS) {
3363
+ const value = cleanValue(text.match(pattern)?.[1]);
3364
+ if (value) return [{ node, value, score: policyNumberEvidenceScore(node) }];
3365
+ }
3366
+ return [];
3367
+ }).sort(
3368
+ (left, right) => right.score - left.score || (left.node.pageStart ?? Number.MAX_SAFE_INTEGER) - (right.node.pageStart ?? Number.MAX_SAFE_INTEGER) || left.node.order - right.node.order
3369
+ );
3370
+ const candidate = candidates[0];
3371
+ return candidate ? valueFromNode(candidate.node, candidate.value, "high") : void 0;
3372
+ }
3342
3373
  function inferPolicyTypes(nodes) {
3343
3374
  const text = nodes.slice(0, 40).map(nodeText).join(" ").toLowerCase();
3344
3375
  const types = [];
3345
3376
  const add = (pattern, type) => {
3346
3377
  if (pattern.test(text) && !types.includes(type)) types.push(type);
3347
3378
  };
3379
+ add(/\b(life insurance|permanent life|term life|whole life|universal life|sun permanent life|sun par protector|manulife par|vitality\s*plus|death benefit)\b/i, "life");
3380
+ add(/\b(critical illness|critical illness insurance|covered critical illness|partial benefit payout)\b/i, "critical_illness");
3381
+ add(/\b(disability benefit|total disability|catastrophic disability|disability waiver|waiver of premium disability)\b/i, "disability");
3382
+ add(/\b(long[-\s]?term care|long term care conversion)\b/i, "long_term_care");
3348
3383
  add(/\b(cyber|network security|privacy liability|data breach)\b/i, "cyber");
3349
3384
  add(/\b(professional liability|errors?\s*&?\s*omissions|e&o)\b/i, "professional_liability");
3350
3385
  add(/\b(commercial general liability|general liability|cgl)\b/i, "general_liability");
@@ -3788,10 +3823,7 @@ function buildDeterministicOperationalProfile(params) {
3788
3823
  const partial = {
3789
3824
  documentType: inferDocumentType(nodes),
3790
3825
  policyTypes: inferPolicyTypes(nodes),
3791
- policyNumber: firstMatch(nodes, [
3792
- /\bpolicy\s*(?:number|no\.?|#)\s*:?\s*([A-Z0-9][A-Z0-9-]{4,})/i,
3793
- /\bpolicy\s*[:#]\s*([A-Z0-9][A-Z0-9-]{4,})/i
3794
- ]),
3826
+ policyNumber: policyNumberFromNodes(nodes),
3795
3827
  namedInsured: firstMatch(nodes, [
3796
3828
  /\b(?:named insured|insured name|insured)\s*:?\s*(.+?)(?=\s+(?:coverage|policy number|insurer|carrier|premium|effective|expiration)\b|[|;\n]|$)/i,
3797
3829
  /\b(?:applicant|policyholder)\s*:?\s*(.+?)(?=\s+(?:coverage|policy number|insurer|carrier|premium|effective|expiration)\b|[|;\n]|$)/i
@@ -3799,6 +3831,8 @@ function buildDeterministicOperationalProfile(params) {
3799
3831
  insurer: firstMatch(nodes, [
3800
3832
  /\b(?:insurer|carrier|company|security)\s*:?\s*([^|;\n]{3,120})/i,
3801
3833
  /\bunderwritten by\s+([^|;\n]{3,120})/i
3834
+ ]) ?? firstMatch(nodes, [
3835
+ /\b(Manulife)\b/i
3802
3836
  ]),
3803
3837
  broker: firstMatch(nodes, [
3804
3838
  /\b(?:broker|producer|agent)\s*:?\s*([^|;\n]{3,120})/i
@@ -11099,6 +11133,7 @@ Rules:
11099
11133
  - Every returned value must include sourceNodeIds or sourceSpanIds from the provided nodes.
11100
11134
  - If a value is not directly supported, omit it.
11101
11135
  - Prefer declarations, schedules, premium tables, and endorsement schedules over generic policy wording.
11136
+ - For life, critical illness, disability, and long-term care policies, keep named benefit units and benefit subconditions as operational facts even when they do not have dollar limits. Examples include death benefit, disability benefit, total disability, catastrophic disability, return of premium, waiver, and conversion options. Put subcondition details in coverages[].limits with kind "other" when they belong under a broader benefit.
11102
11137
  - Treat an endorsement as one coverage unit when it contains a schedule. Do not split an endorsement schedule into generic rows like "Aggregate Limit".
11103
11138
  - For coverage schedules, put each claim, aggregate, sublimit, retention, deductible, and retroactive date values in coverages[].limits with labels and source IDs. Keep the legacy coverages[].limit as the primary display value only.
11104
11139
  - Use coverageOrigin: "endorsement" for endorsement units and "core" for declarations/core policy coverage units.