tdk-api-wrapper 1.7.0 → 1.7.1

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/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TDK
4
- } from "./chunk-ZFWZXNGY.mjs";
4
+ } from "./chunk-YY4WA2AO.mjs";
5
5
 
6
6
  // src/cli.ts
7
7
  var rawArgs = process.argv.slice(2);
@@ -138,7 +138,7 @@ async function startRepl() {
138
138
  async function run() {
139
139
  const binaryName = (process.argv[1] || "").toLowerCase();
140
140
  if (command === "mcp" || rawArgs.includes("--mcp") || binaryName.includes("tdk-mcp")) {
141
- const { runMcpServer } = await import("./mcp-NAXIX4TQ.mjs");
141
+ const { runMcpServer } = await import("./mcp-GBTXQJLW.mjs");
142
142
  await runMcpServer();
143
143
  return;
144
144
  }
package/dist/index.d.mts CHANGED
@@ -188,19 +188,6 @@ declare class TDK {
188
188
  private static readonly BASE_URL;
189
189
  private static readonly AUDIO_API_HOST;
190
190
  private static readonly KUBBEALTI_HOST;
191
- /**
192
- * `eski.lugatim.com` (Kubbealtı Lugatı's data API) sends only its leaf
193
- * certificate during the TLS handshake, omitting the intermediates a
194
- * correctly configured server would include — a server-side misconfiguration,
195
- * not something we should paper over by disabling verification. These are
196
- * the two certificates the server *should* be sending (fetched from the
197
- * leaf's own Authority Information Access URLs), supplied here so Node can
198
- * still build a full, properly verified chain up to a root it already
199
- * trusts (ISRG Root X1). If Let's Encrypt rotates this intermediate, this
200
- * stops working and every Kubbealtı call fails closed to `null` — same
201
- * fail-closed contract as the rest of this file's fragile integrations.
202
- */
203
- private static readonly KUBBEALTI_EXTRA_CA;
204
191
  private static defaultTimeoutMs;
205
192
  private static defaultRetries;
206
193
  private static maxCacheSize;
@@ -399,7 +386,6 @@ declare class TDK {
399
386
  * spans) — cutting there avoids that trailing cruft.
400
387
  */
401
388
  private static fetchRuleText;
402
- private static htmlToPlainText;
403
389
  /**
404
390
  * GETs a JSON path from Kubbealtı Lugatı's data API (`eski.lugatim.com`),
405
391
  * supplying `KUBBEALTI_EXTRA_CA` to work around that host's incomplete
@@ -502,24 +488,6 @@ declare class TDK {
502
488
  * headword. This is an inherent limitation of the data source, not a bug.
503
489
  */
504
490
  static analyzeText(text: string): Promise<WordAnalysis[]>;
505
- /**
506
- * Damerau-Levenshtein edit-distance (optimal string alignment variant):
507
- * like classic Levenshtein but also counts an adjacent-character
508
- * transposition (e.g. "yanlız" -> "yalnız") as a single edit instead of
509
- * two substitutions — a very common class of typo that plain Levenshtein
510
- * otherwise misses.
511
- */
512
- private static damerauLevenshtein;
513
- /**
514
- * Keyboard- and diacritic-aware edit distance: same optimal-string-alignment
515
- * recurrence as {@link damerauLevenshtein}, but a substitution is charged by
516
- * {@link keyboardSubCost} (a fraction of an edit when the two letters are
517
- * adjacent on a Turkish Q keyboard or are ASCII/diacritic siblings) and a
518
- * transposition costs {@link TRANSPOSITION_COST}. Insertions and deletions
519
- * still cost a full 1. Used only to *rank* spelling candidates; the plain
520
- * integer distance still gates whether a suggestion is offered at all.
521
- */
522
- private static keyboardAwareDistance;
523
491
  /**
524
492
  * Fetches multiple words concurrently with a small delay to avoid rate limiting.
525
493
  */
@@ -623,6 +591,13 @@ declare class TDKNetworkError extends TDKError {
623
591
  });
624
592
  }
625
593
 
594
+ /**
595
+ * Turkish suffix catalogue used by the morphology engine's BFS stem-stripper
596
+ * (see `morphology.ts`). Ordered strictly by descending length so that
597
+ * longer composite suffixes match before their individual subcomponents.
598
+ */
599
+ declare const TURKISH_SUFFIXES: readonly string[];
600
+
626
601
  /**
627
602
  * Turkish Morphology Engine & Stem Candidate Generator.
628
603
  *
@@ -633,13 +608,9 @@ declare class TDKNetworkError extends TDKError {
633
608
  * 4. Infinitive restoration (-mek / -mak for verbal stems)
634
609
  * 5. Apostrophe stripping for proper nouns (İstanbul'da -> İstanbul)
635
610
  */
611
+
636
612
  declare const TURKISH_VOWELS = "ae\u0131io\u00F6u\u00FC";
637
613
  declare function isVowel(ch: string): boolean;
638
- /**
639
- * Turkish suffixes ordered strictly by descending length so that longer
640
- * composite suffixes match before their individual subcomponents.
641
- */
642
- declare const TURKISH_SUFFIXES: readonly string[];
643
614
  /**
644
615
  * Reverses Turkish consonant softening (ünsüz yumuşaması):
645
616
  * When a root ends with p, ç, t, k, it softens to b, c, d, ğ, g before a vowel.
package/dist/index.d.ts CHANGED
@@ -188,19 +188,6 @@ declare class TDK {
188
188
  private static readonly BASE_URL;
189
189
  private static readonly AUDIO_API_HOST;
190
190
  private static readonly KUBBEALTI_HOST;
191
- /**
192
- * `eski.lugatim.com` (Kubbealtı Lugatı's data API) sends only its leaf
193
- * certificate during the TLS handshake, omitting the intermediates a
194
- * correctly configured server would include — a server-side misconfiguration,
195
- * not something we should paper over by disabling verification. These are
196
- * the two certificates the server *should* be sending (fetched from the
197
- * leaf's own Authority Information Access URLs), supplied here so Node can
198
- * still build a full, properly verified chain up to a root it already
199
- * trusts (ISRG Root X1). If Let's Encrypt rotates this intermediate, this
200
- * stops working and every Kubbealtı call fails closed to `null` — same
201
- * fail-closed contract as the rest of this file's fragile integrations.
202
- */
203
- private static readonly KUBBEALTI_EXTRA_CA;
204
191
  private static defaultTimeoutMs;
205
192
  private static defaultRetries;
206
193
  private static maxCacheSize;
@@ -399,7 +386,6 @@ declare class TDK {
399
386
  * spans) — cutting there avoids that trailing cruft.
400
387
  */
401
388
  private static fetchRuleText;
402
- private static htmlToPlainText;
403
389
  /**
404
390
  * GETs a JSON path from Kubbealtı Lugatı's data API (`eski.lugatim.com`),
405
391
  * supplying `KUBBEALTI_EXTRA_CA` to work around that host's incomplete
@@ -502,24 +488,6 @@ declare class TDK {
502
488
  * headword. This is an inherent limitation of the data source, not a bug.
503
489
  */
504
490
  static analyzeText(text: string): Promise<WordAnalysis[]>;
505
- /**
506
- * Damerau-Levenshtein edit-distance (optimal string alignment variant):
507
- * like classic Levenshtein but also counts an adjacent-character
508
- * transposition (e.g. "yanlız" -> "yalnız") as a single edit instead of
509
- * two substitutions — a very common class of typo that plain Levenshtein
510
- * otherwise misses.
511
- */
512
- private static damerauLevenshtein;
513
- /**
514
- * Keyboard- and diacritic-aware edit distance: same optimal-string-alignment
515
- * recurrence as {@link damerauLevenshtein}, but a substitution is charged by
516
- * {@link keyboardSubCost} (a fraction of an edit when the two letters are
517
- * adjacent on a Turkish Q keyboard or are ASCII/diacritic siblings) and a
518
- * transposition costs {@link TRANSPOSITION_COST}. Insertions and deletions
519
- * still cost a full 1. Used only to *rank* spelling candidates; the plain
520
- * integer distance still gates whether a suggestion is offered at all.
521
- */
522
- private static keyboardAwareDistance;
523
491
  /**
524
492
  * Fetches multiple words concurrently with a small delay to avoid rate limiting.
525
493
  */
@@ -623,6 +591,13 @@ declare class TDKNetworkError extends TDKError {
623
591
  });
624
592
  }
625
593
 
594
+ /**
595
+ * Turkish suffix catalogue used by the morphology engine's BFS stem-stripper
596
+ * (see `morphology.ts`). Ordered strictly by descending length so that
597
+ * longer composite suffixes match before their individual subcomponents.
598
+ */
599
+ declare const TURKISH_SUFFIXES: readonly string[];
600
+
626
601
  /**
627
602
  * Turkish Morphology Engine & Stem Candidate Generator.
628
603
  *
@@ -633,13 +608,9 @@ declare class TDKNetworkError extends TDKError {
633
608
  * 4. Infinitive restoration (-mek / -mak for verbal stems)
634
609
  * 5. Apostrophe stripping for proper nouns (İstanbul'da -> İstanbul)
635
610
  */
611
+
636
612
  declare const TURKISH_VOWELS = "ae\u0131io\u00F6u\u00FC";
637
613
  declare function isVowel(ch: string): boolean;
638
- /**
639
- * Turkish suffixes ordered strictly by descending length so that longer
640
- * composite suffixes match before their individual subcomponents.
641
- */
642
- declare const TURKISH_SUFFIXES: readonly string[];
643
614
  /**
644
615
  * Reverses Turkish consonant softening (ünsüz yumuşaması):
645
616
  * When a root ends with p, ç, t, k, it softens to b, c, d, ğ, g before a vowel.
package/dist/index.js CHANGED
@@ -76,11 +76,7 @@ var TDKNetworkError = class extends TDKError {
76
76
  }
77
77
  };
78
78
 
79
- // src/morphology.ts
80
- var TURKISH_VOWELS = "ae\u0131io\xF6u\xFC";
81
- function isVowel(ch) {
82
- return TURKISH_VOWELS.includes(ch);
83
- }
79
+ // src/data/suffixes.ts
84
80
  var TURKISH_SUFFIXES = [
85
81
  // 9-letter composite suffixes
86
82
  "lerimizden",
@@ -483,6 +479,12 @@ var TURKISH_SUFFIXES = [
483
479
  "u",
484
480
  "\xFC"
485
481
  ];
482
+
483
+ // src/morphology.ts
484
+ var TURKISH_VOWELS = "ae\u0131io\xF6u\xFC";
485
+ function isVowel(ch) {
486
+ return TURKISH_VOWELS.includes(ch);
487
+ }
486
488
  function restoreConsonantSoftening(stem) {
487
489
  if (stem.length < 2)
488
490
  return [];
@@ -636,12 +638,7 @@ function getStemCandidates(word, minStemLength = 2, maxDepth = 4) {
636
638
  return [...new Set(candidatesWithWeight.map((c) => c.candidate))];
637
639
  }
638
640
 
639
- // src/tdk.ts
640
- var fs = __toESM(require("fs"));
641
- var path = __toESM(require("path"));
642
- var os = __toESM(require("os"));
643
- var https = __toESM(require("https"));
644
- var tls = __toESM(require("tls"));
641
+ // src/data/misspellings.ts
645
642
  var COMMON_MISSPELLINGS = {
646
643
  // -şey ile biten ve ayrı yazılması zorunlu söz öbekleri
647
644
  her\u015Fey: "her \u015Fey",
@@ -795,75 +792,10 @@ var COMMON_MISSPELLINGS = {
795
792
  babaanne: "babaanne"
796
793
  };
797
794
  var SEY_EXCEPTIONS = /* @__PURE__ */ new Set(["d\xFC\u015Fey", "e\u015Fey", "konsey", "jersey", "\u015Fey"]);
798
- var KEYBOARD_ROWS = [
799
- ["qwertyu\u0131op\u011F\xFC", 0],
800
- ["asdfghjkl\u015Fi", 0.5],
801
- ["zxcvbnm\xF6\xE7", 1]
802
- ];
803
- var KEYBOARD_COORDS = (() => {
804
- const coords = {};
805
- KEYBOARD_ROWS.forEach(([keys, offset], row) => {
806
- [...keys].forEach((key, col) => {
807
- coords[key] = [col + offset, row];
808
- });
809
- });
810
- return coords;
811
- })();
812
- var DIACRITIC_SIBLINGS = {
813
- \u0131: "i",
814
- i: "\u0131",
815
- \u00F6: "o",
816
- o: "\xF6",
817
- \u00FC: "u",
818
- u: "\xFC",
819
- \u015F: "s",
820
- s: "\u015F",
821
- \u00E7: "c",
822
- c: "\xE7",
823
- \u011F: "g",
824
- g: "\u011F",
825
- \u00E2: "a",
826
- a: "\xE2"
827
- };
828
- var KEYBOARD_ROW_SUB_COST = 0.4;
829
- var KEYBOARD_DIAGONAL_SUB_COST = 0.55;
830
- var DIACRITIC_SUB_COST = 0.3;
831
- var TRANSPOSITION_COST = 0.8;
832
- function keyboardSubCost(a, b) {
833
- if (a === b)
834
- return 0;
835
- if (DIACRITIC_SIBLINGS[a] === b)
836
- return DIACRITIC_SUB_COST;
837
- const pa = KEYBOARD_COORDS[a];
838
- const pb = KEYBOARD_COORDS[b];
839
- if (!pa || !pb)
840
- return 1;
841
- const dx = Math.abs(pa[0] - pb[0]);
842
- const dy = Math.abs(pa[1] - pb[1]);
843
- if (dy === 0 && dx <= 1 + 1e-9)
844
- return KEYBOARD_ROW_SUB_COST;
845
- if (dy === 1 && dx <= 1 + 1e-9)
846
- return KEYBOARD_DIAGONAL_SUB_COST;
847
- return 1;
848
- }
849
- var TDK = class {
850
- static BASE_URL = "https://sozluk.gov.tr";
851
- static AUDIO_API_HOST = "api.sozluk.gov.tr";
852
- static KUBBEALTI_HOST = "eski.lugatim.com";
853
- /**
854
- * `eski.lugatim.com` (Kubbealtı Lugatı's data API) sends only its leaf
855
- * certificate during the TLS handshake, omitting the intermediates a
856
- * correctly configured server would include — a server-side misconfiguration,
857
- * not something we should paper over by disabling verification. These are
858
- * the two certificates the server *should* be sending (fetched from the
859
- * leaf's own Authority Information Access URLs), supplied here so Node can
860
- * still build a full, properly verified chain up to a root it already
861
- * trusts (ISRG Root X1). If Let's Encrypt rotates this intermediate, this
862
- * stops working and every Kubbealtı call fails closed to `null` — same
863
- * fail-closed contract as the rest of this file's fragile integrations.
864
- */
865
- static KUBBEALTI_EXTRA_CA = [
866
- `-----BEGIN CERTIFICATE-----
795
+
796
+ // src/data/kubbealti-ca.ts
797
+ var KUBBEALTI_EXTRA_CA = [
798
+ `-----BEGIN CERTIFICATE-----
867
799
  MIIE2jCCAsKgAwIBAgIQTr0klH4k05SALYSlL9WzGTANBgkqhkiG9w0BAQsFADAu
868
800
  MQswCQYDVQQGEwJVUzENMAsGA1UEChMESVNSRzEQMA4GA1UEAxMHUm9vdCBZUjAe
869
801
  Fw0yNTA5MDMwMDAwMDBaFw0yODA5MDIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYw
@@ -891,7 +823,7 @@ NA3wJdl4DDUuQSV8hBgx6zoI1ZSGORprDFux7c6rhc77QZMSRrEgomBeklervEve
891
823
  86ylWmZ3WWHV6RLMi8xNvjd71r4EPIGgY7BZU/VPBkq+uA7Gb6mbJnFgV43uh3xy
892
824
  LRFgxIAphIukwTGSMZZR+AI+Qnp0BYTWovHXozOf3H8r6hozEoT02JHn0AeTfA==
893
825
  -----END CERTIFICATE-----`,
894
- `-----BEGIN CERTIFICATE-----
826
+ `-----BEGIN CERTIFICATE-----
895
827
  MIIF9DCCA9ygAwIBAgIRAPJLbRf52a18scn+p4eCaZ8wDQYJKoZIhvcNAQELBQAw
896
828
  TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
897
829
  cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjYwNTEzMDAwMDAw
@@ -925,7 +857,112 @@ RGMuHGnzS3hFIrRTfKxrzUZ9RzQWzEG3K6fJ3r2nqSltkeytis9DIBoFY9VmVyjL
925
857
  M71DMi+y1+TRSJVClEMwvA4yL++7q9XZx5r5wBRWB4kQTKH5qyoZnDw7iiuh1lID
926
858
  yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
927
859
  -----END CERTIFICATE-----`
928
- ];
860
+ ];
861
+
862
+ // src/data/keyboard-layout.ts
863
+ var KEYBOARD_ROWS = [
864
+ ["qwertyu\u0131op\u011F\xFC", 0],
865
+ ["asdfghjkl\u015Fi", 0.5],
866
+ ["zxcvbnm\xF6\xE7", 1]
867
+ ];
868
+ var KEYBOARD_COORDS = (() => {
869
+ const coords = {};
870
+ KEYBOARD_ROWS.forEach(([keys, offset], row) => {
871
+ [...keys].forEach((key, col) => {
872
+ coords[key] = [col + offset, row];
873
+ });
874
+ });
875
+ return coords;
876
+ })();
877
+ var DIACRITIC_SIBLINGS = {
878
+ \u0131: "i",
879
+ i: "\u0131",
880
+ \u00F6: "o",
881
+ o: "\xF6",
882
+ \u00FC: "u",
883
+ u: "\xFC",
884
+ \u015F: "s",
885
+ s: "\u015F",
886
+ \u00E7: "c",
887
+ c: "\xE7",
888
+ \u011F: "g",
889
+ g: "\u011F",
890
+ \u00E2: "a",
891
+ a: "\xE2"
892
+ };
893
+ var KEYBOARD_ROW_SUB_COST = 0.4;
894
+ var KEYBOARD_DIAGONAL_SUB_COST = 0.55;
895
+ var DIACRITIC_SUB_COST = 0.3;
896
+ var TRANSPOSITION_COST = 0.8;
897
+ function keyboardSubCost(a, b) {
898
+ if (a === b)
899
+ return 0;
900
+ if (DIACRITIC_SIBLINGS[a] === b)
901
+ return DIACRITIC_SUB_COST;
902
+ const pa = KEYBOARD_COORDS[a];
903
+ const pb = KEYBOARD_COORDS[b];
904
+ if (!pa || !pb)
905
+ return 1;
906
+ const dx = Math.abs(pa[0] - pb[0]);
907
+ const dy = Math.abs(pa[1] - pb[1]);
908
+ if (dy === 0 && dx <= 1 + 1e-9)
909
+ return KEYBOARD_ROW_SUB_COST;
910
+ if (dy === 1 && dx <= 1 + 1e-9)
911
+ return KEYBOARD_DIAGONAL_SUB_COST;
912
+ return 1;
913
+ }
914
+
915
+ // src/lib/edit-distance.ts
916
+ function damerauLevenshtein(a, b) {
917
+ const dp = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
918
+ for (let i = 0; i <= a.length; i++)
919
+ dp[i][0] = i;
920
+ for (let j = 0; j <= b.length; j++)
921
+ dp[0][j] = j;
922
+ for (let i = 1; i <= a.length; i++) {
923
+ for (let j = 1; j <= b.length; j++) {
924
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
925
+ dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
926
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
927
+ dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + cost);
928
+ }
929
+ }
930
+ }
931
+ return dp[a.length][b.length];
932
+ }
933
+ function keyboardAwareDistance(a, b) {
934
+ const dp = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
935
+ for (let i = 0; i <= a.length; i++)
936
+ dp[i][0] = i;
937
+ for (let j = 0; j <= b.length; j++)
938
+ dp[0][j] = j;
939
+ for (let i = 1; i <= a.length; i++) {
940
+ for (let j = 1; j <= b.length; j++) {
941
+ const cost = keyboardSubCost(a[i - 1], b[j - 1]);
942
+ dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
943
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
944
+ dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + TRANSPOSITION_COST);
945
+ }
946
+ }
947
+ }
948
+ return dp[a.length][b.length];
949
+ }
950
+
951
+ // src/lib/html.ts
952
+ function htmlToPlainText(html) {
953
+ return html.replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div)>/gi, "\n\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/gi, " ").replace(/&lt;/gi, "<").replace(/&gt;/gi, ">").replace(/&quot;/gi, '"').replace(/&#39;|&rsquo;/gi, "'").replace(/&amp;/gi, "&").replace(/[ \t]+/g, " ").replace(/[ \t]*\n[ \t]*/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
954
+ }
955
+
956
+ // src/tdk.ts
957
+ var fs = __toESM(require("fs"));
958
+ var path = __toESM(require("path"));
959
+ var os = __toESM(require("os"));
960
+ var https = __toESM(require("https"));
961
+ var tls = __toESM(require("tls"));
962
+ var TDK = class {
963
+ static BASE_URL = "https://sozluk.gov.tr";
964
+ static AUDIO_API_HOST = "api.sozluk.gov.tr";
965
+ static KUBBEALTI_HOST = "eski.lugatim.com";
929
966
  // Configuration
930
967
  static defaultTimeoutMs = 8e3;
931
968
  static defaultRetries = 1;
@@ -1472,12 +1509,12 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1472
1509
  continue;
1473
1510
  if (Math.abs(candidate.length - cleanWord.length) > 2)
1474
1511
  continue;
1475
- const rawDist = this.damerauLevenshtein(cleanWord, candidate);
1512
+ const rawDist = damerauLevenshtein(cleanWord, candidate);
1476
1513
  if (rawDist === 0 || rawDist > 2)
1477
1514
  continue;
1478
1515
  const firstMismatch = candidate[0] === cleanWord[0] ? 0 : 1;
1479
1516
  const lengthMismatch = candidate.length === cleanWord.length ? 0 : 1;
1480
- const score = this.keyboardAwareDistance(cleanWord, candidate) + (firstMismatch > 0 ? 1.2 : 0);
1517
+ const score = keyboardAwareDistance(cleanWord, candidate) + (firstMismatch > 0 ? 1.2 : 0);
1481
1518
  const better = !best || score < best.score - 1e-9 || Math.abs(score - best.score) < 1e-9 && firstMismatch < best.firstMismatch || Math.abs(score - best.score) < 1e-9 && firstMismatch === best.firstMismatch && lengthMismatch < best.lengthMismatch;
1482
1519
  if (better) {
1483
1520
  best = { candidate, score, rawDist, firstMismatch, lengthMismatch };
@@ -1608,14 +1645,11 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1608
1645
  const contentEnd = html.indexOf("<footer", contentStart);
1609
1646
  if (contentEnd === -1)
1610
1647
  return null;
1611
- return this.htmlToPlainText(html.slice(contentStart, contentEnd));
1648
+ return htmlToPlainText(html.slice(contentStart, contentEnd));
1612
1649
  } catch {
1613
1650
  return null;
1614
1651
  }
1615
1652
  }
1616
- static htmlToPlainText(html) {
1617
- return html.replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div)>/gi, "\n\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/gi, " ").replace(/&lt;/gi, "<").replace(/&gt;/gi, ">").replace(/&quot;/gi, '"').replace(/&#39;|&rsquo;/gi, "'").replace(/&amp;/gi, "&").replace(/[ \t]+/g, " ").replace(/[ \t]*\n[ \t]*/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
1618
- }
1619
1653
  /**
1620
1654
  * GETs a JSON path from Kubbealtı Lugatı's data API (`eski.lugatim.com`),
1621
1655
  * supplying `KUBBEALTI_EXTRA_CA` to work around that host's incomplete
@@ -1629,7 +1663,7 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1629
1663
  hostname: this.KUBBEALTI_HOST,
1630
1664
  path: path2,
1631
1665
  method: "GET",
1632
- ca: [...tls.rootCertificates, ...this.KUBBEALTI_EXTRA_CA],
1666
+ ca: [...tls.rootCertificates, ...KUBBEALTI_EXTRA_CA],
1633
1667
  headers: {
1634
1668
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
1635
1669
  }
@@ -1721,7 +1755,7 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1721
1755
  const entries = await this.getKubbealti(word);
1722
1756
  if (!entries)
1723
1757
  return null;
1724
- return entries.map((e) => this.htmlToPlainText(e.anlam));
1758
+ return entries.map((e) => htmlToPlainText(e.anlam));
1725
1759
  }
1726
1760
  /**
1727
1761
  * Autocomplete suggestions from Kubbealtı Lugatı's own typeahead endpoint
@@ -1757,7 +1791,7 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1757
1791
  const match = html.match(/<meta name="description" content="([^"]*)"/);
1758
1792
  if (!match)
1759
1793
  return null;
1760
- const description = this.htmlToPlainText(match[1]);
1794
+ const description = htmlToPlainText(match[1]);
1761
1795
  if (description === "\xC7a\u011Fda\u015F T\xFCrk\xE7enin Etimolojisi")
1762
1796
  return null;
1763
1797
  return description;
@@ -1988,56 +2022,6 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1988
2022
  }
1989
2023
  return analyses;
1990
2024
  }
1991
- /**
1992
- * Damerau-Levenshtein edit-distance (optimal string alignment variant):
1993
- * like classic Levenshtein but also counts an adjacent-character
1994
- * transposition (e.g. "yanlız" -> "yalnız") as a single edit instead of
1995
- * two substitutions — a very common class of typo that plain Levenshtein
1996
- * otherwise misses.
1997
- */
1998
- static damerauLevenshtein(a, b) {
1999
- const dp = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
2000
- for (let i = 0; i <= a.length; i++)
2001
- dp[i][0] = i;
2002
- for (let j = 0; j <= b.length; j++)
2003
- dp[0][j] = j;
2004
- for (let i = 1; i <= a.length; i++) {
2005
- for (let j = 1; j <= b.length; j++) {
2006
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
2007
- dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
2008
- if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
2009
- dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + cost);
2010
- }
2011
- }
2012
- }
2013
- return dp[a.length][b.length];
2014
- }
2015
- /**
2016
- * Keyboard- and diacritic-aware edit distance: same optimal-string-alignment
2017
- * recurrence as {@link damerauLevenshtein}, but a substitution is charged by
2018
- * {@link keyboardSubCost} (a fraction of an edit when the two letters are
2019
- * adjacent on a Turkish Q keyboard or are ASCII/diacritic siblings) and a
2020
- * transposition costs {@link TRANSPOSITION_COST}. Insertions and deletions
2021
- * still cost a full 1. Used only to *rank* spelling candidates; the plain
2022
- * integer distance still gates whether a suggestion is offered at all.
2023
- */
2024
- static keyboardAwareDistance(a, b) {
2025
- const dp = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
2026
- for (let i = 0; i <= a.length; i++)
2027
- dp[i][0] = i;
2028
- for (let j = 0; j <= b.length; j++)
2029
- dp[0][j] = j;
2030
- for (let i = 1; i <= a.length; i++) {
2031
- for (let j = 1; j <= b.length; j++) {
2032
- const cost = keyboardSubCost(a[i - 1], b[j - 1]);
2033
- dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
2034
- if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
2035
- dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + TRANSPOSITION_COST);
2036
- }
2037
- }
2038
- }
2039
- return dp[a.length][b.length];
2040
- }
2041
2025
  /**
2042
2026
  * Fetches multiple words concurrently with a small delay to avoid rate limiting.
2043
2027
  */
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createMcpServer,
3
3
  runMcpServer
4
- } from "./chunk-MELLECWT.mjs";
4
+ } from "./chunk-ZG7YRT7V.mjs";
5
5
  import {
6
6
  TDK,
7
7
  TDKClient,
@@ -17,7 +17,7 @@ import {
17
17
  restoreInfinitive,
18
18
  restoreVowelDrop,
19
19
  restoreVowelNarrowing
20
- } from "./chunk-ZFWZXNGY.mjs";
20
+ } from "./chunk-YY4WA2AO.mjs";
21
21
  export {
22
22
  TDK,
23
23
  TDKClient,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  createMcpServer,
3
3
  runMcpServer
4
- } from "./chunk-MELLECWT.mjs";
5
- import "./chunk-ZFWZXNGY.mjs";
4
+ } from "./chunk-ZG7YRT7V.mjs";
5
+ import "./chunk-YY4WA2AO.mjs";
6
6
  export {
7
7
  createMcpServer,
8
8
  runMcpServer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tdk-api-wrapper",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "TDK (Türk Dil Kurumu) unofficial live data API wrapper and MCP server for Node.js",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -38,7 +38,7 @@
38
38
  "model-context-protocol"
39
39
  ],
40
40
  "author": "cemyilmazzzz122 <cemyleo12@icloud.com> (https://github.com/cemyilmazzzz122)",
41
- "license": "MIT",
41
+ "license": "GPL-3.0-or-later",
42
42
  "homepage": "https://github.com/cemyilmazzzz122/tdk-api#readme",
43
43
  "repository": {
44
44
  "type": "git",