@claritylabs/cl-sdk 3.0.31 → 3.0.33
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 +147 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +147 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2957,6 +2957,15 @@ function moneyValue(value) {
|
|
|
2957
2957
|
if (/^\d{1,3}(?:,\d{3})*(?:\.\d{2})?$/.test(clean)) return `$${clean}`;
|
|
2958
2958
|
return clean;
|
|
2959
2959
|
}
|
|
2960
|
+
function premiumValue(value) {
|
|
2961
|
+
const clean = cleanValue(value);
|
|
2962
|
+
if (!clean) return void 0;
|
|
2963
|
+
if (/\$[A-Z0-9]/i.test(clean)) return clean;
|
|
2964
|
+
if (/\b(?:CAD|USD)\b/i.test(clean) && /(?:\d|X{2,})/i.test(clean)) return clean;
|
|
2965
|
+
if (/^\d{1,3}(?:,\d{3})+\.\d{2}$/.test(clean) || /^\d+\.\d{2}$/.test(clean)) return `$${clean}`;
|
|
2966
|
+
if (/^X{2,}(?:,X{3})*(?:\.X{2})$/i.test(clean)) return clean;
|
|
2967
|
+
return void 0;
|
|
2968
|
+
}
|
|
2960
2969
|
function nodeText(node) {
|
|
2961
2970
|
return normalizeWhitespace3([
|
|
2962
2971
|
node.title,
|
|
@@ -2972,6 +2981,14 @@ function valueFromNode(node, value, confidence = "medium") {
|
|
|
2972
2981
|
sourceSpanIds: node.sourceSpanIds
|
|
2973
2982
|
};
|
|
2974
2983
|
}
|
|
2984
|
+
function valueFromNodes(nodes, value, confidence = "medium", normalizedValue) {
|
|
2985
|
+
return {
|
|
2986
|
+
value,
|
|
2987
|
+
...normalizedValue ? { normalizedValue } : {},
|
|
2988
|
+
confidence,
|
|
2989
|
+
...sourceIds(nodes)
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2975
2992
|
function firstMatch(nodes, patterns) {
|
|
2976
2993
|
for (const node of nodes) {
|
|
2977
2994
|
const text = nodeText(node);
|
|
@@ -3038,27 +3055,96 @@ function firstCleanMatch(nodes, patterns, clean) {
|
|
|
3038
3055
|
function cleanNamedInsured(value) {
|
|
3039
3056
|
const clean = cleanValue(value.replace(/\bborn\s+on\b.*$/i, "").replace(/\bage\s+nearest\b.*$/i, "").replace(/\bbeneficiary\b.*$/i, ""));
|
|
3040
3057
|
if (!clean || clean.length > 160) return void 0;
|
|
3058
|
+
if (!/[A-Za-z0-9]/.test(clean)) return void 0;
|
|
3041
3059
|
if (/^(person|persons)\b/i.test(clean)) return void 0;
|
|
3060
|
+
if (/^(insurance amount|benefit amount|policy number|policy date|owner|beneficiary|premium|coverage|risk classification)\b/i.test(clean)) {
|
|
3061
|
+
return void 0;
|
|
3062
|
+
}
|
|
3042
3063
|
if (/\b(table of contents|policy wording|provided solely|convenience|not to be construed|actual policy issued)\b/i.test(clean)) {
|
|
3043
3064
|
return void 0;
|
|
3044
3065
|
}
|
|
3045
3066
|
return clean;
|
|
3046
3067
|
}
|
|
3068
|
+
var PARTY_LABEL_PATTERNS = {
|
|
3069
|
+
namedInsured: /^(?:item\s*\d+[.)]?\s*)?(?:named insured(?:\s+and\s+address)?|insured name)$/i,
|
|
3070
|
+
insurer: /^(?:carrier|insurer|security)$/i,
|
|
3071
|
+
broker: /^(?:broker(?:\s+of\s+record)?|producer|agent)$/i
|
|
3072
|
+
};
|
|
3073
|
+
function partyLabelKind(value) {
|
|
3074
|
+
const clean = cleanValue(value.replace(/^\s*column\s+\d+\s*:\s*/i, ""));
|
|
3075
|
+
if (!clean) return void 0;
|
|
3076
|
+
if (PARTY_LABEL_PATTERNS.namedInsured.test(clean)) return "namedInsured";
|
|
3077
|
+
if (PARTY_LABEL_PATTERNS.insurer.test(clean)) return "insurer";
|
|
3078
|
+
if (PARTY_LABEL_PATTERNS.broker.test(clean)) return "broker";
|
|
3079
|
+
return void 0;
|
|
3080
|
+
}
|
|
3081
|
+
function isRejectedPartyValue(value) {
|
|
3082
|
+
const clean = normalizeWhitespace3(value);
|
|
3083
|
+
return /^(?:and address|of record|insurer|carrier|security|broker|producer|agent|the|a|an|is|are|was|were|agrees?|means?|includes?|shall|will)\b/i.test(clean);
|
|
3084
|
+
}
|
|
3085
|
+
function identityWithoutAddress(value) {
|
|
3086
|
+
const clean = cleanValue(value.replace(/\b(?:phone|tel|telephone|email|e-mail)\b.*$/i, "").replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b.*$/i, ""));
|
|
3087
|
+
if (!clean) return void 0;
|
|
3088
|
+
const beforeStreet = clean.match(/^(.+?)\s+\d{1,6}\s+[A-Za-z0-9.'-]+(?:\s+[A-Za-z0-9.'-]+){0,5}\s+(?:street|st\.?|avenue|ave\.?|road|rd\.?|drive|dr\.?|lane|ln\.?|boulevard|blvd\.?|suite|ste\.?|floor|fl\.?|way|court|ct\.?)\b/i)?.[1];
|
|
3089
|
+
const beforeCityState = clean.match(/^(.+?)\s+[A-Z][A-Za-z.'-]+(?:\s+[A-Z][A-Za-z.'-]+)*,\s*[A-Z]{2}\s+\d{5}(?:-\d{4})?\b/)?.[1];
|
|
3090
|
+
return cleanValue(beforeStreet ?? beforeCityState ?? clean);
|
|
3091
|
+
}
|
|
3092
|
+
function cleanPartyIdentity(value, clean) {
|
|
3093
|
+
const raw = cleanValue(value);
|
|
3094
|
+
if (!raw || isRejectedPartyValue(raw)) return void 0;
|
|
3095
|
+
const identity = identityWithoutAddress(raw);
|
|
3096
|
+
const cleaned = identity ? clean(identity) : void 0;
|
|
3097
|
+
if (!cleaned || isRejectedPartyValue(cleaned)) return void 0;
|
|
3098
|
+
return {
|
|
3099
|
+
value: cleaned,
|
|
3100
|
+
...cleaned !== raw ? { normalizedValue: cleaned } : {}
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
3103
|
+
function partyFromTableRows(nodes, wanted, clean) {
|
|
3104
|
+
const children = childMap(nodes);
|
|
3105
|
+
for (const row of compactFactNodes(nodes).filter((node) => node.kind === "table_row")) {
|
|
3106
|
+
const cells = cellRows(row, children);
|
|
3107
|
+
for (const [index, cell] of cells.entries()) {
|
|
3108
|
+
const labelKind = partyLabelKind(cell.value) ?? partyLabelKind(cell.label);
|
|
3109
|
+
if (labelKind !== wanted) continue;
|
|
3110
|
+
const valueCell = cells.slice(index + 1).find((candidate) => !partyLabelKind(candidate.value) && !partyLabelKind(candidate.label));
|
|
3111
|
+
if (!valueCell) continue;
|
|
3112
|
+
const cleaned = cleanPartyIdentity(valueCell.value, clean);
|
|
3113
|
+
if (cleaned) return valueFromNodes([row, valueCell.node], cleaned.value, "high", cleaned.normalizedValue);
|
|
3114
|
+
}
|
|
3115
|
+
const parts = normalizeWhitespace3(row.textExcerpt ?? row.description ?? nodeText(row)).split(/\s+\|\s+|\t/).map(cleanValue).filter((part) => Boolean(part));
|
|
3116
|
+
for (const [index, part] of parts.entries()) {
|
|
3117
|
+
const labelKind = partyLabelKind(part);
|
|
3118
|
+
if (labelKind !== wanted) continue;
|
|
3119
|
+
const cleaned = cleanPartyIdentity(parts[index + 1] ?? "", clean);
|
|
3120
|
+
if (cleaned) return valueFromNodes([row], cleaned.value, "high", cleaned.normalizedValue);
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
return void 0;
|
|
3124
|
+
}
|
|
3047
3125
|
function namedInsuredFromNodes(nodes) {
|
|
3048
|
-
return firstCleanMatch(nodes, [
|
|
3049
|
-
/\b(?:named insured|insured name
|
|
3126
|
+
return partyFromTableRows(nodes, "namedInsured", cleanNamedInsured) ?? firstCleanMatch(nodes, [
|
|
3127
|
+
/\b(?:named insured|insured name)\s*:?\s*(.+?)(?=\s+(?:insurance amount|benefit amount|policy number|policy date|owner|beneficiary|premium|coverage|risk classification|date this)\b|[|;\n]|$)/i,
|
|
3128
|
+
/\b(?:insured persons?|insured person)\s*:\s*(.+?)(?=\s+(?:insurance amount|benefit amount|policy number|policy date|owner|beneficiary|premium|coverage|risk classification|date this)\b|[|;\n]|$)/i,
|
|
3050
3129
|
/\b(?:applicant|policyholder)\s*:?\s*(.+?)(?=\s+(?:coverage|policy number|insurer|carrier|premium|effective|expiration)\b|[|;\n]|$)/i
|
|
3051
3130
|
], cleanNamedInsured);
|
|
3052
3131
|
}
|
|
3053
3132
|
function cleanInsurer(value) {
|
|
3054
3133
|
const clean = cleanValue(value);
|
|
3055
3134
|
if (!clean || clean.length > 140) return void 0;
|
|
3056
|
-
if (/^(mean|means|we|us|our)\b/i.test(clean)) return void 0;
|
|
3135
|
+
if (/^(mean|means|we|us|our|the|a|an|agrees?|shall|will)\b/i.test(clean)) return void 0;
|
|
3057
3136
|
if (/\b(table of contents|policy wording|provided solely|convenience)\b/i.test(clean)) return void 0;
|
|
3058
3137
|
const known = clean.match(/\b(Sun Life Assurance Company of Canada|Manulife|The Manufacturers Life Insurance Company)\b/i)?.[1];
|
|
3059
3138
|
return known ?? clean;
|
|
3060
3139
|
}
|
|
3061
3140
|
function insurerFromNodes(nodes) {
|
|
3141
|
+
const tableValue = partyFromTableRows(nodes, "insurer", cleanInsurer);
|
|
3142
|
+
if (tableValue) return tableValue;
|
|
3143
|
+
for (const node of compactFactNodes(nodes)) {
|
|
3144
|
+
const text = nodeText(node);
|
|
3145
|
+
const value = cleanInsurer(text.match(/\b([A-Z][A-Za-z&.,' -]{2,120}?(?:Insurance|Assurance|Indemnity|Casualty|Underwriting|Mutual|Risk|Reinsurance)\s+Company(?:\s+of\s+[A-Z][A-Za-z .'-]+)?)\s*\(\s*the\s+["']?Insurer["']?\s*\)/i)?.[1] ?? "");
|
|
3146
|
+
if (value) return valueFromNode(node, value, "high");
|
|
3147
|
+
}
|
|
3062
3148
|
return firstCleanMatch(nodes, [
|
|
3063
3149
|
/\bunderwritten by\s+([^|;\n.]{3,160})/i,
|
|
3064
3150
|
/\b(?:insurer|carrier|company|security)\s*:?\s*([^|;\n]{3,120})/i,
|
|
@@ -3104,6 +3190,19 @@ function coverageNameFromRow(text) {
|
|
|
3104
3190
|
);
|
|
3105
3191
|
return cleanCoverageLabel(first);
|
|
3106
3192
|
}
|
|
3193
|
+
function isDeclarationLimitLabel(value) {
|
|
3194
|
+
const label = normalizeLabel(value);
|
|
3195
|
+
return /\bitem\s*\d+[.)]?\s*limits?\s+of\s+liability\b/.test(label) || /^limits?\s+of\s+liability$/.test(label) || /^policy\s+limits?$/.test(label);
|
|
3196
|
+
}
|
|
3197
|
+
function declarationCoverageNameFromRow(row, children) {
|
|
3198
|
+
const cells = cellRows(row, children);
|
|
3199
|
+
const candidates = [
|
|
3200
|
+
row.title,
|
|
3201
|
+
...cells.flatMap((cell) => [cell.label, cell.value])
|
|
3202
|
+
];
|
|
3203
|
+
if (!candidates.some(isDeclarationLimitLabel)) return void 0;
|
|
3204
|
+
return candidates.some((candidate) => /\blimits?\s+of\s+liability\b/i.test(candidate ?? "")) ? "Limits of Liability" : "Policy Limits";
|
|
3205
|
+
}
|
|
3107
3206
|
function limitFromText(text) {
|
|
3108
3207
|
return moneyValue(
|
|
3109
3208
|
text.match(/\b(?:limit|liability|aggregate|occurrence|claim)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?|\$?\d[\d,]*\s*(?:each|per|aggregate)[^|;]*)/i)?.[1] ?? text.match(/(\$\s?\d[\d,]*(?:\.\d{2})?)(?=.*\b(limit|aggregate|occurrence|claim|liability)\b)/i)?.[1]
|
|
@@ -3113,10 +3212,22 @@ function deductibleFromText(text) {
|
|
|
3113
3212
|
return moneyValue(text.match(/\b(?:deductible|retention|sir)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i)?.[1]);
|
|
3114
3213
|
}
|
|
3115
3214
|
function premiumFromText(text) {
|
|
3116
|
-
return
|
|
3215
|
+
return premiumValue(text.match(/\b(?:premium|total premium|total cost|amount due)\b(?:\s*(?:is|:|-))?\s*(\$?(?:\d[\d,]*(?:\.\d{2})?|X{2,}(?:,X{3})*(?:\.X{2})?))/i)?.[1]);
|
|
3216
|
+
}
|
|
3217
|
+
function premiumFromNodes(nodes) {
|
|
3218
|
+
for (const node of compactFactNodes(nodes)) {
|
|
3219
|
+
const value = premiumFromText(nodeText(node));
|
|
3220
|
+
if (value) return valueFromNode(node, value, "high");
|
|
3221
|
+
}
|
|
3222
|
+
return void 0;
|
|
3117
3223
|
}
|
|
3118
3224
|
function moneyAmount(value) {
|
|
3119
|
-
const
|
|
3225
|
+
const clean = cleanValue(value);
|
|
3226
|
+
if (!clean) return void 0;
|
|
3227
|
+
const currency = clean.match(/\$\s*([0-9][0-9,]*(?:\.\d+)?)/);
|
|
3228
|
+
const percent = clean.match(/\b([0-9][0-9,]*(?:\.\d+)?)\s*%/);
|
|
3229
|
+
const explicitNumeric = !/\bitem\s*\d+\b/i.test(clean) && /\b(?:limit|aggregate|claim|occurrence|loss|retention|deductible|sir|premium|amount)\b/i.test(clean) ? clean.match(/\b([0-9][0-9,]*(?:\.\d+)?)\b/) : void 0;
|
|
3230
|
+
const match = currency ?? percent ?? explicitNumeric;
|
|
3120
3231
|
if (!match) return void 0;
|
|
3121
3232
|
const amount = Number(match[1].replace(/,/g, ""));
|
|
3122
3233
|
return Number.isFinite(amount) ? amount : void 0;
|
|
@@ -3162,6 +3273,10 @@ function isValueCell(label, value) {
|
|
|
3162
3273
|
}
|
|
3163
3274
|
return /\b(limit|aggregate|retention|deductible|sir|retroactive|premium|amount)\b/.test(normalizedLabel) || moneyAmount(value) !== void 0 || /\b(full prior acts|none|included|not included|as stated)\b/.test(normalizedValue);
|
|
3164
3275
|
}
|
|
3276
|
+
function isCoverageTermLabel(value) {
|
|
3277
|
+
const label = normalizeLabel(value);
|
|
3278
|
+
return /\b(limit|aggregate|retention|deductible|sir|retroactive|premium|amount|sub[-\s]?limit)\b/.test(label);
|
|
3279
|
+
}
|
|
3165
3280
|
function isNameCell(label, value) {
|
|
3166
3281
|
const normalizedLabel = normalizeLabel(label);
|
|
3167
3282
|
const normalizedValue = normalizeLabel(value);
|
|
@@ -3263,6 +3378,16 @@ function termFromCell(params) {
|
|
|
3263
3378
|
function termsFromRow(row, children) {
|
|
3264
3379
|
const cells = cellRows(row, children);
|
|
3265
3380
|
if (cells.length > 0) {
|
|
3381
|
+
const pairedTerms = [];
|
|
3382
|
+
for (const [index, cell] of cells.entries()) {
|
|
3383
|
+
const next = cells[index + 1];
|
|
3384
|
+
if (!next) continue;
|
|
3385
|
+
if (!isCoverageTermLabel(cell.value)) continue;
|
|
3386
|
+
if (isCoverageTermLabel(next.value) && moneyAmount(next.value) === void 0) continue;
|
|
3387
|
+
const term = termFromCell({ row, cell: next.node, label: cell.value, value: next.value });
|
|
3388
|
+
if (term) pairedTerms.push(term);
|
|
3389
|
+
}
|
|
3390
|
+
if (pairedTerms.length > 0) return pairedTerms;
|
|
3266
3391
|
return cells.filter((cell) => isValueCell(cell.label, cell.value)).map((cell) => termFromCell({ row, cell: cell.node, label: cell.label, value: cell.value })).filter((term) => Boolean(term));
|
|
3267
3392
|
}
|
|
3268
3393
|
const text = normalizeWhitespace3(row.textExcerpt ?? row.description ?? nodeText(row));
|
|
@@ -3289,6 +3414,8 @@ function termsFromRow(row, children) {
|
|
|
3289
3414
|
return terms;
|
|
3290
3415
|
}
|
|
3291
3416
|
function nameFromRow(row, children) {
|
|
3417
|
+
const declarationName = declarationCoverageNameFromRow(row, children);
|
|
3418
|
+
if (declarationName) return declarationName;
|
|
3292
3419
|
const cells = cellRows(row, children);
|
|
3293
3420
|
const named = cells.find((cell) => isNameCell(cell.label, cell.value));
|
|
3294
3421
|
if (named) return cleanValue(named.value);
|
|
@@ -3466,7 +3593,7 @@ function buildParties(profile) {
|
|
|
3466
3593
|
if (profile.namedInsured) {
|
|
3467
3594
|
parties.push({
|
|
3468
3595
|
role: "named_insured",
|
|
3469
|
-
name: profile.namedInsured.value,
|
|
3596
|
+
name: profile.namedInsured.normalizedValue ?? profile.namedInsured.value,
|
|
3470
3597
|
sourceNodeIds: profile.namedInsured.sourceNodeIds,
|
|
3471
3598
|
sourceSpanIds: profile.namedInsured.sourceSpanIds
|
|
3472
3599
|
});
|
|
@@ -3474,7 +3601,7 @@ function buildParties(profile) {
|
|
|
3474
3601
|
if (profile.insurer) {
|
|
3475
3602
|
parties.push({
|
|
3476
3603
|
role: "insurer",
|
|
3477
|
-
name: profile.insurer.value,
|
|
3604
|
+
name: profile.insurer.normalizedValue ?? profile.insurer.value,
|
|
3478
3605
|
sourceNodeIds: profile.insurer.sourceNodeIds,
|
|
3479
3606
|
sourceSpanIds: profile.insurer.sourceSpanIds
|
|
3480
3607
|
});
|
|
@@ -3482,7 +3609,7 @@ function buildParties(profile) {
|
|
|
3482
3609
|
if (profile.broker) {
|
|
3483
3610
|
parties.push({
|
|
3484
3611
|
role: "broker",
|
|
3485
|
-
name: profile.broker.value,
|
|
3612
|
+
name: profile.broker.normalizedValue ?? profile.broker.value,
|
|
3486
3613
|
sourceNodeIds: profile.broker.sourceNodeIds,
|
|
3487
3614
|
sourceSpanIds: profile.broker.sourceSpanIds
|
|
3488
3615
|
});
|
|
@@ -3535,9 +3662,7 @@ function buildDeterministicOperationalProfile(params) {
|
|
|
3535
3662
|
retroactiveDate: firstMatch(nodes, [
|
|
3536
3663
|
/\bretroactive date\s*:?\s*([0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}|full prior acts|none)/i
|
|
3537
3664
|
]),
|
|
3538
|
-
premium:
|
|
3539
|
-
/\b(?:total premium|premium|total cost|amount due)\s*:?\s*(\$?\d[\d,]*(?:\.\d{2})?)/i
|
|
3540
|
-
])
|
|
3665
|
+
premium: premiumFromNodes(nodes)
|
|
3541
3666
|
};
|
|
3542
3667
|
const coverages = buildCoverages(nodes);
|
|
3543
3668
|
const coverageTypes = [...new Set(coverages.map((coverage) => coverage.name))];
|
|
@@ -10929,9 +11054,19 @@ function sourceTreeToOutline(sourceTree) {
|
|
|
10929
11054
|
});
|
|
10930
11055
|
return (byParent.get(root?.id) ?? []).map(visit);
|
|
10931
11056
|
}
|
|
11057
|
+
var NORMALIZED_COMPATIBILITY_FIELDS = /* @__PURE__ */ new Set([
|
|
11058
|
+
"policyNumber",
|
|
11059
|
+
"namedInsured",
|
|
11060
|
+
"insurer",
|
|
11061
|
+
"broker"
|
|
11062
|
+
]);
|
|
10932
11063
|
function valueOf(profile, key) {
|
|
10933
11064
|
const value = profile[key];
|
|
10934
|
-
|
|
11065
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !("value" in value)) return void 0;
|
|
11066
|
+
if (NORMALIZED_COMPATIBILITY_FIELDS.has(key) && "normalizedValue" in value && typeof value.normalizedValue === "string" && value.normalizedValue.trim()) {
|
|
11067
|
+
return value.normalizedValue;
|
|
11068
|
+
}
|
|
11069
|
+
return String(value.value);
|
|
10935
11070
|
}
|
|
10936
11071
|
function materializeDocument(params) {
|
|
10937
11072
|
const profile = params.operationalProfile;
|