@semiont/api-client 0.2.33-build.84 → 0.2.33-build.86

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.
@@ -1585,7 +1585,7 @@ interface paths {
1585
1585
  patch?: never;
1586
1586
  trace?: never;
1587
1587
  };
1588
- "/api/resources/token/{token}": {
1588
+ "/api/clone-tokens/{token}": {
1589
1589
  parameters: {
1590
1590
  query?: never;
1591
1591
  header?: never;
@@ -1626,7 +1626,7 @@ interface paths {
1626
1626
  patch?: never;
1627
1627
  trace?: never;
1628
1628
  };
1629
- "/api/resources/create-from-token": {
1629
+ "/api/clone-tokens/create-resource": {
1630
1630
  parameters: {
1631
1631
  query?: never;
1632
1632
  header?: never;
@@ -3451,16 +3451,43 @@ interface TextPosition {
3451
3451
  start: number;
3452
3452
  end: number;
3453
3453
  }
3454
+ type MatchQuality = 'exact' | 'normalized' | 'case-insensitive' | 'fuzzy';
3455
+ /**
3456
+ * Normalize text for comparison - handles common document editing changes
3457
+ *
3458
+ * Collapses whitespace, converts curly quotes to straight quotes,
3459
+ * and normalizes common punctuation variations.
3460
+ */
3461
+ declare function normalizeText(text: string): string;
3462
+ /**
3463
+ * Find best match for text in content using multi-strategy search
3464
+ *
3465
+ * Shared core logic used by both findTextWithContext and validateAndCorrectOffsets.
3466
+ *
3467
+ * @param content - Full text content to search within
3468
+ * @param searchText - The text to find
3469
+ * @param positionHint - Optional hint for where to search (TextPositionSelector.start)
3470
+ * @returns Match with position and quality, or null if not found
3471
+ */
3472
+ declare function findBestTextMatch(content: string, searchText: string, positionHint?: number): {
3473
+ start: number;
3474
+ end: number;
3475
+ matchQuality: MatchQuality;
3476
+ } | null;
3454
3477
  /**
3455
3478
  * Find text using exact match with optional prefix/suffix context
3456
3479
  *
3457
3480
  * When the exact text appears multiple times in the content, prefix and suffix
3458
3481
  * are used to disambiguate and find the correct occurrence.
3459
3482
  *
3483
+ * If exact text is not found, uses multi-strategy fuzzy matching (normalization,
3484
+ * case-insensitive, Levenshtein distance) to locate changed text.
3485
+ *
3460
3486
  * @param content - Full text content to search within
3461
3487
  * @param exact - The exact text to find
3462
3488
  * @param prefix - Optional text that should appear immediately before the match
3463
3489
  * @param suffix - Optional text that should appear immediately after the match
3490
+ * @param positionHint - Optional position hint (from TextPositionSelector) for fuzzy search
3464
3491
  * @returns Position of the matched text, or null if not found
3465
3492
  *
3466
3493
  * @example
@@ -3471,7 +3498,7 @@ interface TextPosition {
3471
3498
  * // Returns { start: 13, end: 20 }
3472
3499
  * ```
3473
3500
  */
3474
- declare function findTextWithContext(content: string, exact: string, prefix?: string, suffix?: string): TextPosition | null;
3501
+ declare function findTextWithContext(content: string, exact: string, prefix?: string, suffix?: string, positionHint?: number): TextPosition | null;
3475
3502
  /**
3476
3503
  * Verify that a position correctly points to the exact text
3477
3504
  * Useful for debugging and validation
@@ -3664,6 +3691,7 @@ declare function scaleSvgToNative(svg: string, displayWidth: number, displayHeig
3664
3691
  *
3665
3692
  * @see https://www.w3.org/TR/annotation-model/#text-quote-selector
3666
3693
  */
3694
+
3667
3695
  /**
3668
3696
  * Extract prefix and suffix context for TextQuoteSelector
3669
3697
  *
@@ -3699,7 +3727,7 @@ interface ValidatedAnnotation {
3699
3727
  suffix?: string;
3700
3728
  corrected: boolean;
3701
3729
  fuzzyMatched?: boolean;
3702
- matchQuality?: 'exact' | 'case-insensitive' | 'fuzzy';
3730
+ matchQuality?: MatchQuality;
3703
3731
  }
3704
3732
  /**
3705
3733
  * Validate and correct AI-provided annotation offsets with fuzzy matching tolerance
@@ -3828,4 +3856,4 @@ declare function validateData<T>(schema: {
3828
3856
  */
3829
3857
  declare function isValidEmail(email: string): boolean;
3830
3858
 
3831
- export { type $defs as $, type AccessToken as A, type BaseUrl as B, type ContentFormat as C, getExactText as D, type EntityType as E, type FragmentSelector as F, type GoogleCredential as G, getAnnotationExactText as H, getPrimarySelector as I, type JobId as J, getTextPositionSelector as K, getTextQuoteSelector as L, type Motivation as M, getSvgSelector as N, getFragmentSelector as O, validateSvgMarkup as P, extractBoundingBox as Q, type ResourceUri as R, type SearchQuery as S, type TextPositionSelector as T, type UserDID as U, type TextPosition as V, findTextWithContext as W, verifyPosition as X, type LocaleInfo as Y, LOCALES as Z, getLocaleInfo as _, type AnnotationUri as a, getLocaleNativeName as a0, getLocaleEnglishName as a1, formatLocaleDisplay as a2, getAllLocaleCodes as a3, getResourceId as a4, getPrimaryRepresentation as a5, getPrimaryMediaType as a6, getChecksum as a7, getLanguage as a8, getStorageUri as a9, type AuthCode as aA, type MCPToken as aB, email as aC, authCode as aD, googleCredential as aE, accessToken as aF, refreshToken as aG, mcpToken as aH, cloneToken as aI, jobId as aJ, userDID as aK, entityType as aL, searchQuery as aM, baseUrl as aN, resourceUri as aO, annotationUri as aP, resourceAnnotationUri as aQ, getCreator as aa, getDerivedFrom as ab, isArchived as ac, getResourceEntityTypes as ad, isDraft as ae, getNodeEncoding as af, decodeRepresentation as ag, type Point as ah, type BoundingBox as ai, createRectangleSvg as aj, createPolygonSvg as ak, createCircleSvg as al, parseSvgSelector as am, normalizeCoordinates as an, scaleSvgToNative as ao, extractContext as ap, type ValidatedAnnotation as aq, validateAndCorrectOffsets as ar, extractCharset as as, decodeWithCharset as at, type ValidationSuccess as au, type ValidationFailure as av, type ValidationResult as aw, JWTTokenSchema as ax, validateData as ay, isValidEmail as az, type Email as b, type components as c, type RefreshToken as d, type CloneToken as e, type ResourceAnnotationUri as f, type TextQuoteSelector as g, type SvgSelector as h, type Selector as i, getBodySource as j, getBodyType as k, isBodyResolved as l, getTargetSource as m, getTargetSelector as n, type operations as o, type paths as p, hasTargetSelector as q, isHighlight as r, isReference as s, isAssessment as t, isComment as u, isTag as v, type webhooks as w, getCommentText as x, isStubReference as y, isResolvedReference as z };
3859
+ export { type $defs as $, type AccessToken as A, type BaseUrl as B, type ContentFormat as C, getExactText as D, type EntityType as E, type FragmentSelector as F, type GoogleCredential as G, getAnnotationExactText as H, getPrimarySelector as I, type JobId as J, getTextPositionSelector as K, getTextQuoteSelector as L, type Motivation as M, getSvgSelector as N, getFragmentSelector as O, validateSvgMarkup as P, extractBoundingBox as Q, type ResourceUri as R, type SearchQuery as S, type TextPositionSelector as T, type UserDID as U, type TextPosition as V, type MatchQuality as W, normalizeText as X, findBestTextMatch as Y, findTextWithContext as Z, verifyPosition as _, type AnnotationUri as a, type LocaleInfo as a0, LOCALES as a1, getLocaleInfo as a2, getLocaleNativeName as a3, getLocaleEnglishName as a4, formatLocaleDisplay as a5, getAllLocaleCodes as a6, getResourceId as a7, getPrimaryRepresentation as a8, getPrimaryMediaType as a9, JWTTokenSchema as aA, validateData as aB, isValidEmail as aC, type AuthCode as aD, type MCPToken as aE, email as aF, authCode as aG, googleCredential as aH, accessToken as aI, refreshToken as aJ, mcpToken as aK, cloneToken as aL, jobId as aM, userDID as aN, entityType as aO, searchQuery as aP, baseUrl as aQ, resourceUri as aR, annotationUri as aS, resourceAnnotationUri as aT, getChecksum as aa, getLanguage as ab, getStorageUri as ac, getCreator as ad, getDerivedFrom as ae, isArchived as af, getResourceEntityTypes as ag, isDraft as ah, getNodeEncoding as ai, decodeRepresentation as aj, type Point as ak, type BoundingBox as al, createRectangleSvg as am, createPolygonSvg as an, createCircleSvg as ao, parseSvgSelector as ap, normalizeCoordinates as aq, scaleSvgToNative as ar, extractContext as as, type ValidatedAnnotation as at, validateAndCorrectOffsets as au, extractCharset as av, decodeWithCharset as aw, type ValidationSuccess as ax, type ValidationFailure as ay, type ValidationResult as az, type Email as b, type components as c, type RefreshToken as d, type CloneToken as e, type ResourceAnnotationUri as f, type TextQuoteSelector as g, type SvgSelector as h, type Selector as i, getBodySource as j, getBodyType as k, isBodyResolved as l, getTargetSource as m, getTargetSelector as n, type operations as o, type paths as p, hasTargetSelector as q, isHighlight as r, isReference as s, isAssessment as t, isComment as u, isTag as v, type webhooks as w, getCommentText as x, isStubReference as y, isResolvedReference as z };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BaseUrl, R as ResourceUri, E as EntityType, A as AccessToken, a as AnnotationUri, c as components, b as Email, p as paths, d as RefreshToken, G as GoogleCredential, C as ContentFormat, S as SearchQuery, e as CloneToken, f as ResourceAnnotationUri, M as Motivation, U as UserDID, J as JobId } from './index-vuErmLIm.js';
2
- export { $ as $defs, aA as AuthCode, ai as BoundingBox, F as FragmentSelector, ax as JWTTokenSchema, Z as LOCALES, Y as LocaleInfo, aB as MCPToken, ah as Point, i as Selector, h as SvgSelector, V as TextPosition, T as TextPositionSelector, g as TextQuoteSelector, aq as ValidatedAnnotation, av as ValidationFailure, aw as ValidationResult, au as ValidationSuccess, aF as accessToken, aP as annotationUri, aD as authCode, aN as baseUrl, aI as cloneToken, al as createCircleSvg, ak as createPolygonSvg, aj as createRectangleSvg, ag as decodeRepresentation, at as decodeWithCharset, aC as email, aL as entityType, Q as extractBoundingBox, as as extractCharset, ap as extractContext, W as findTextWithContext, a2 as formatLocaleDisplay, a3 as getAllLocaleCodes, H as getAnnotationExactText, j as getBodySource, k as getBodyType, a7 as getChecksum, x as getCommentText, aa as getCreator, ab as getDerivedFrom, D as getExactText, O as getFragmentSelector, a8 as getLanguage, a1 as getLocaleEnglishName, _ as getLocaleInfo, a0 as getLocaleNativeName, af as getNodeEncoding, a6 as getPrimaryMediaType, a5 as getPrimaryRepresentation, I as getPrimarySelector, ad as getResourceEntityTypes, a4 as getResourceId, a9 as getStorageUri, N as getSvgSelector, n as getTargetSelector, m as getTargetSource, K as getTextPositionSelector, L as getTextQuoteSelector, aE as googleCredential, q as hasTargetSelector, ac as isArchived, t as isAssessment, l as isBodyResolved, u as isComment, ae as isDraft, r as isHighlight, s as isReference, z as isResolvedReference, y as isStubReference, v as isTag, az as isValidEmail, aJ as jobId, aH as mcpToken, an as normalizeCoordinates, o as operations, am as parseSvgSelector, aG as refreshToken, aQ as resourceAnnotationUri, aO as resourceUri, ao as scaleSvgToNative, aM as searchQuery, aK as userDID, ar as validateAndCorrectOffsets, ay as validateData, P as validateSvgMarkup, X as verifyPosition, w as webhooks } from './index-vuErmLIm.js';
1
+ import { B as BaseUrl, R as ResourceUri, E as EntityType, A as AccessToken, a as AnnotationUri, c as components, b as Email, p as paths, d as RefreshToken, G as GoogleCredential, C as ContentFormat, S as SearchQuery, e as CloneToken, f as ResourceAnnotationUri, M as Motivation, U as UserDID, J as JobId } from './index-CJqmerJr.js';
2
+ export { $ as $defs, aD as AuthCode, al as BoundingBox, F as FragmentSelector, aA as JWTTokenSchema, a1 as LOCALES, a0 as LocaleInfo, aE as MCPToken, W as MatchQuality, ak as Point, i as Selector, h as SvgSelector, V as TextPosition, T as TextPositionSelector, g as TextQuoteSelector, at as ValidatedAnnotation, ay as ValidationFailure, az as ValidationResult, ax as ValidationSuccess, aI as accessToken, aS as annotationUri, aG as authCode, aQ as baseUrl, aL as cloneToken, ao as createCircleSvg, an as createPolygonSvg, am as createRectangleSvg, aj as decodeRepresentation, aw as decodeWithCharset, aF as email, aO as entityType, Q as extractBoundingBox, av as extractCharset, as as extractContext, Y as findBestTextMatch, Z as findTextWithContext, a5 as formatLocaleDisplay, a6 as getAllLocaleCodes, H as getAnnotationExactText, j as getBodySource, k as getBodyType, aa as getChecksum, x as getCommentText, ad as getCreator, ae as getDerivedFrom, D as getExactText, O as getFragmentSelector, ab as getLanguage, a4 as getLocaleEnglishName, a2 as getLocaleInfo, a3 as getLocaleNativeName, ai as getNodeEncoding, a9 as getPrimaryMediaType, a8 as getPrimaryRepresentation, I as getPrimarySelector, ag as getResourceEntityTypes, a7 as getResourceId, ac as getStorageUri, N as getSvgSelector, n as getTargetSelector, m as getTargetSource, K as getTextPositionSelector, L as getTextQuoteSelector, aH as googleCredential, q as hasTargetSelector, af as isArchived, t as isAssessment, l as isBodyResolved, u as isComment, ah as isDraft, r as isHighlight, s as isReference, z as isResolvedReference, y as isStubReference, v as isTag, aC as isValidEmail, aM as jobId, aK as mcpToken, aq as normalizeCoordinates, X as normalizeText, o as operations, ap as parseSvgSelector, aJ as refreshToken, aT as resourceAnnotationUri, aR as resourceUri, ar as scaleSvgToNative, aP as searchQuery, aN as userDID, au as validateAndCorrectOffsets, aB as validateData, P as validateSvgMarkup, _ as verifyPosition, w as webhooks } from './index-CJqmerJr.js';
3
3
 
4
4
  /**
5
5
  * TypeScript types for Server-Sent Events (SSE) streaming
@@ -878,8 +878,8 @@ declare class SemiontApiClient {
878
878
  referencedBy: any[];
879
879
  }>;
880
880
  generateCloneToken(resourceUri: ResourceUri, options?: RequestOptions): Promise<ResponseContent<paths['/resources/{id}/clone-with-token']['post']>>;
881
- getResourceByToken(token: CloneToken, options?: RequestOptions): Promise<ResponseContent<paths['/api/resources/token/{token}']['get']>>;
882
- createResourceFromToken(data: RequestContent<paths['/api/resources/create-from-token']['post']>, options?: RequestOptions): Promise<ResponseContent<paths['/api/resources/create-from-token']['post']>>;
881
+ getResourceByToken(token: CloneToken, options?: RequestOptions): Promise<ResponseContent<paths['/api/clone-tokens/{token}']['get']>>;
882
+ createResourceFromToken(data: RequestContent<paths['/api/clone-tokens/create-resource']['post']>, options?: RequestOptions): Promise<ResponseContent<paths['/api/clone-tokens/create-resource']['post']>>;
883
883
  createAnnotation(resourceUri: ResourceUri, data: RequestContent<paths['/resources/{id}/annotations']['post']>, options?: RequestOptions): Promise<ResponseContent<paths['/resources/{id}/annotations']['post']>>;
884
884
  getAnnotation(annotationUri: AnnotationUri, options?: RequestOptions): Promise<ResponseContent<paths['/annotations/{id}']['get']>>;
885
885
  getResourceAnnotation(annotationUri: ResourceAnnotationUri, options?: RequestOptions): Promise<ResponseContent<paths['/resources/{resourceId}/annotations/{annotationId}']['get']>>;
package/dist/index.js CHANGED
@@ -939,19 +939,20 @@ var SemiontApiClient = class {
939
939
  }).json();
940
940
  }
941
941
  async generateCloneToken(resourceUri2, options) {
942
- return this.http.post(`${resourceUri2}/clone-with-token`, {
942
+ const id = resourceUri2.split("/").pop();
943
+ return this.http.post(`${this.baseUrl}/resources/${id}/clone-with-token`, {
943
944
  ...options,
944
945
  auth: options?.auth
945
946
  }).json();
946
947
  }
947
948
  async getResourceByToken(token, options) {
948
- return this.http.get(`${this.baseUrl}/api/resources/token/${token}`, {
949
+ return this.http.get(`${this.baseUrl}/api/clone-tokens/${token}`, {
949
950
  ...options,
950
951
  auth: options?.auth
951
952
  }).json();
952
953
  }
953
954
  async createResourceFromToken(data, options) {
954
- return this.http.post(`${this.baseUrl}/api/resources/create-from-token`, {
955
+ return this.http.post(`${this.baseUrl}/api/clone-tokens/create-resource`, {
955
956
  json: data,
956
957
  ...options,
957
958
  auth: options?.auth
@@ -1377,7 +1378,94 @@ function extractBoundingBox(svg) {
1377
1378
  }
1378
1379
 
1379
1380
  // src/utils/fuzzy-anchor.ts
1380
- function findTextWithContext(content, exact, prefix, suffix) {
1381
+ function normalizeText(text) {
1382
+ return text.replace(/\s+/g, " ").replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"').replace(/\u2014/g, "--").replace(/\u2013/g, "-").trim();
1383
+ }
1384
+ function levenshteinDistance(str1, str2) {
1385
+ const len1 = str1.length;
1386
+ const len2 = str2.length;
1387
+ const matrix = [];
1388
+ for (let i = 0; i <= len1; i++) {
1389
+ matrix[i] = [i];
1390
+ }
1391
+ for (let j = 0; j <= len2; j++) {
1392
+ matrix[0][j] = j;
1393
+ }
1394
+ for (let i = 1; i <= len1; i++) {
1395
+ for (let j = 1; j <= len2; j++) {
1396
+ const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
1397
+ const deletion = matrix[i - 1][j] + 1;
1398
+ const insertion = matrix[i][j - 1] + 1;
1399
+ const substitution = matrix[i - 1][j - 1] + cost;
1400
+ matrix[i][j] = Math.min(deletion, insertion, substitution);
1401
+ }
1402
+ }
1403
+ return matrix[len1][len2];
1404
+ }
1405
+ function findBestTextMatch(content, searchText, positionHint) {
1406
+ const maxFuzzyDistance = Math.max(5, Math.floor(searchText.length * 0.05));
1407
+ const exactIndex = content.indexOf(searchText);
1408
+ if (exactIndex !== -1) {
1409
+ return {
1410
+ start: exactIndex,
1411
+ end: exactIndex + searchText.length,
1412
+ matchQuality: "exact"
1413
+ };
1414
+ }
1415
+ const normalizedSearch = normalizeText(searchText);
1416
+ const normalizedContent = normalizeText(content);
1417
+ const normalizedIndex = normalizedContent.indexOf(normalizedSearch);
1418
+ if (normalizedIndex !== -1) {
1419
+ let actualPos = 0;
1420
+ let normalizedPos = 0;
1421
+ while (normalizedPos < normalizedIndex && actualPos < content.length) {
1422
+ const char = content[actualPos];
1423
+ const normalizedChar = normalizeText(char);
1424
+ if (normalizedChar) {
1425
+ normalizedPos += normalizedChar.length;
1426
+ }
1427
+ actualPos++;
1428
+ }
1429
+ return {
1430
+ start: actualPos,
1431
+ end: actualPos + searchText.length,
1432
+ matchQuality: "normalized"
1433
+ };
1434
+ }
1435
+ const lowerContent = content.toLowerCase();
1436
+ const lowerSearch = searchText.toLowerCase();
1437
+ const caseInsensitiveIndex = lowerContent.indexOf(lowerSearch);
1438
+ if (caseInsensitiveIndex !== -1) {
1439
+ return {
1440
+ start: caseInsensitiveIndex,
1441
+ end: caseInsensitiveIndex + searchText.length,
1442
+ matchQuality: "case-insensitive"
1443
+ };
1444
+ }
1445
+ const windowSize = searchText.length;
1446
+ const searchRadius = Math.min(500, content.length);
1447
+ const searchStart = positionHint !== void 0 ? Math.max(0, positionHint - searchRadius) : 0;
1448
+ const searchEnd = positionHint !== void 0 ? Math.min(content.length, positionHint + searchRadius) : content.length;
1449
+ let bestMatch = null;
1450
+ for (let i = searchStart; i <= searchEnd - windowSize; i++) {
1451
+ const candidate = content.substring(i, i + windowSize);
1452
+ const distance = levenshteinDistance(searchText, candidate);
1453
+ if (distance <= maxFuzzyDistance) {
1454
+ if (!bestMatch || distance < bestMatch.distance) {
1455
+ bestMatch = { start: i, distance };
1456
+ }
1457
+ }
1458
+ }
1459
+ if (bestMatch) {
1460
+ return {
1461
+ start: bestMatch.start,
1462
+ end: bestMatch.start + windowSize,
1463
+ matchQuality: "fuzzy"
1464
+ };
1465
+ }
1466
+ return null;
1467
+ }
1468
+ function findTextWithContext(content, exact, prefix, suffix, positionHint) {
1381
1469
  if (!exact) return null;
1382
1470
  const occurrences = [];
1383
1471
  let index = content.indexOf(exact);
@@ -1386,7 +1474,15 @@ function findTextWithContext(content, exact, prefix, suffix) {
1386
1474
  index = content.indexOf(exact, index + 1);
1387
1475
  }
1388
1476
  if (occurrences.length === 0) {
1389
- console.warn(`[FuzzyAnchor] Text not found: "${exact.substring(0, 50)}..."`);
1477
+ console.warn(`[FuzzyAnchor] Exact text not found, trying fuzzy match: "${exact.substring(0, 50)}..."`);
1478
+ const fuzzyMatch = findBestTextMatch(content, exact, positionHint);
1479
+ if (fuzzyMatch) {
1480
+ console.warn(
1481
+ `[FuzzyAnchor] Found ${fuzzyMatch.matchQuality} match at position ${fuzzyMatch.start}`
1482
+ );
1483
+ return { start: fuzzyMatch.start, end: fuzzyMatch.end };
1484
+ }
1485
+ console.warn(`[FuzzyAnchor] No acceptable match found for: "${exact.substring(0, 50)}..."`);
1390
1486
  return null;
1391
1487
  }
1392
1488
  if (occurrences.length === 1) {
@@ -1414,7 +1510,7 @@ function findTextWithContext(content, exact, prefix, suffix) {
1414
1510
  const fuzzyPrefixMatch = !prefix || actualPrefix.includes(prefix.trim());
1415
1511
  const fuzzySuffixMatch = !suffix || actualSuffix.includes(suffix.trim());
1416
1512
  if (fuzzyPrefixMatch && fuzzySuffixMatch) {
1417
- console.warn(`[FuzzyAnchor] Using fuzzy match at position ${pos2}`);
1513
+ console.warn(`[FuzzyAnchor] Using fuzzy context match at position ${pos2}`);
1418
1514
  return { start: pos2, end: pos2 + exact.length };
1419
1515
  }
1420
1516
  }
@@ -1684,75 +1780,6 @@ function extractContext(content, start, end) {
1684
1780
  }
1685
1781
  return { prefix, suffix };
1686
1782
  }
1687
- function levenshteinDistance(str1, str2) {
1688
- const len1 = str1.length;
1689
- const len2 = str2.length;
1690
- const matrix = [];
1691
- for (let i = 0; i <= len1; i++) {
1692
- matrix[i] = [i];
1693
- }
1694
- for (let j = 0; j <= len2; j++) {
1695
- matrix[0][j] = j;
1696
- }
1697
- for (let i = 1; i <= len1; i++) {
1698
- for (let j = 1; j <= len2; j++) {
1699
- const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
1700
- const deletion = matrix[i - 1][j] + 1;
1701
- const insertion = matrix[i][j - 1] + 1;
1702
- const substitution = matrix[i - 1][j - 1] + cost;
1703
- matrix[i][j] = Math.min(deletion, insertion, substitution);
1704
- }
1705
- }
1706
- return matrix[len1][len2];
1707
- }
1708
- function findBestMatch(content, searchText, aiStart, aiEnd) {
1709
- const maxFuzzyDistance = Math.max(5, Math.floor(searchText.length * 0.05));
1710
- const exactIndex = content.indexOf(searchText);
1711
- if (exactIndex !== -1) {
1712
- return {
1713
- start: exactIndex,
1714
- end: exactIndex + searchText.length,
1715
- matchQuality: "exact"
1716
- };
1717
- }
1718
- console.log("[findBestMatch] Exact match failed, trying case-insensitive...");
1719
- const lowerContent = content.toLowerCase();
1720
- const lowerSearch = searchText.toLowerCase();
1721
- const caseInsensitiveIndex = lowerContent.indexOf(lowerSearch);
1722
- if (caseInsensitiveIndex !== -1) {
1723
- console.log("[findBestMatch] Found case-insensitive match");
1724
- return {
1725
- start: caseInsensitiveIndex,
1726
- end: caseInsensitiveIndex + searchText.length,
1727
- matchQuality: "case-insensitive"
1728
- };
1729
- }
1730
- console.log("[findBestMatch] Case-insensitive failed, trying fuzzy match...");
1731
- const windowSize = searchText.length;
1732
- const searchRadius = Math.min(500, content.length);
1733
- const searchStart = Math.max(0, aiStart - searchRadius);
1734
- const searchEnd = Math.min(content.length, aiEnd + searchRadius);
1735
- let bestMatch = null;
1736
- for (let i = searchStart; i <= searchEnd - windowSize; i++) {
1737
- const candidate = content.substring(i, i + windowSize);
1738
- const distance = levenshteinDistance(searchText, candidate);
1739
- if (distance <= maxFuzzyDistance) {
1740
- if (!bestMatch || distance < bestMatch.distance) {
1741
- bestMatch = { start: i, distance };
1742
- console.log(`[findBestMatch] Found fuzzy match at ${i} with distance ${distance}`);
1743
- }
1744
- }
1745
- }
1746
- if (bestMatch) {
1747
- return {
1748
- start: bestMatch.start,
1749
- end: bestMatch.start + windowSize,
1750
- matchQuality: "fuzzy"
1751
- };
1752
- }
1753
- console.log("[findBestMatch] No acceptable match found");
1754
- return null;
1755
- }
1756
1783
  function validateAndCorrectOffsets(content, aiStart, aiEnd, exact) {
1757
1784
  const exactPreview = exact.length > 50 ? exact.substring(0, 50) + "..." : exact;
1758
1785
  const textAtOffset = content.substring(aiStart, aiEnd);
@@ -1776,7 +1803,7 @@ function validateAndCorrectOffsets(content, aiStart, aiEnd, exact) {
1776
1803
  Found at AI offset (${aiStart}-${aiEnd}): "${foundPreview}"
1777
1804
  Attempting multi-strategy search...`
1778
1805
  );
1779
- const match = findBestMatch(content, exact, aiStart, aiEnd);
1806
+ const match = findBestTextMatch(content, exact, aiStart);
1780
1807
  if (!match) {
1781
1808
  const exactLong = exact.length > 100 ? exact.substring(0, 100) + "..." : exact;
1782
1809
  console.error(
@@ -1911,6 +1938,6 @@ function getMimeCategory(mimeType) {
1911
1938
  return "unsupported";
1912
1939
  }
1913
1940
 
1914
- export { APIError, JWTTokenSchema, LOCALES, SSEClient, SemiontApiClient, accessToken, annotationUri, authCode, baseUrl, cloneToken, createCircleSvg, createPolygonSvg, createRectangleSvg, decodeRepresentation, decodeWithCharset, email, entityType, extractBoundingBox, extractCharset, extractContext, findTextWithContext, formatLocaleDisplay, getAllLocaleCodes, getAnnotationExactText, getBodySource, getBodyType, getChecksum, getCommentText, getCreator, getDerivedFrom, getExactText, getExtensionForMimeType, getFragmentSelector, getLanguage, getLocaleEnglishName, getLocaleInfo, getLocaleNativeName, getMimeCategory, getNodeEncoding, getPrimaryMediaType, getPrimaryRepresentation, getPrimarySelector, getResourceEntityTypes, getResourceId, getStorageUri, getSvgSelector, getTargetSelector, getTargetSource, getTextPositionSelector, getTextQuoteSelector, googleCredential, hasTargetSelector, isArchived, isAssessment, isBodyResolved, isComment, isDraft, isHighlight, isImageMimeType, isPdfMimeType, isReference, isResolvedReference, isStubReference, isTag, isTextMimeType, isValidEmail, jobId, mcpToken, normalizeCoordinates, parseSvgSelector, refreshToken, resourceAnnotationUri, resourceUri, scaleSvgToNative, searchQuery, userDID, validateAndCorrectOffsets, validateData, validateSvgMarkup, verifyPosition };
1941
+ export { APIError, JWTTokenSchema, LOCALES, SSEClient, SemiontApiClient, accessToken, annotationUri, authCode, baseUrl, cloneToken, createCircleSvg, createPolygonSvg, createRectangleSvg, decodeRepresentation, decodeWithCharset, email, entityType, extractBoundingBox, extractCharset, extractContext, findBestTextMatch, findTextWithContext, formatLocaleDisplay, getAllLocaleCodes, getAnnotationExactText, getBodySource, getBodyType, getChecksum, getCommentText, getCreator, getDerivedFrom, getExactText, getExtensionForMimeType, getFragmentSelector, getLanguage, getLocaleEnglishName, getLocaleInfo, getLocaleNativeName, getMimeCategory, getNodeEncoding, getPrimaryMediaType, getPrimaryRepresentation, getPrimarySelector, getResourceEntityTypes, getResourceId, getStorageUri, getSvgSelector, getTargetSelector, getTargetSource, getTextPositionSelector, getTextQuoteSelector, googleCredential, hasTargetSelector, isArchived, isAssessment, isBodyResolved, isComment, isDraft, isHighlight, isImageMimeType, isPdfMimeType, isReference, isResolvedReference, isStubReference, isTag, isTextMimeType, isValidEmail, jobId, mcpToken, normalizeCoordinates, normalizeText, parseSvgSelector, refreshToken, resourceAnnotationUri, resourceUri, scaleSvgToNative, searchQuery, userDID, validateAndCorrectOffsets, validateData, validateSvgMarkup, verifyPosition };
1915
1942
  //# sourceMappingURL=index.js.map
1916
1943
  //# sourceMappingURL=index.js.map