simple-dynamsoft-mcp 6.2.0 → 6.4.0

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.
@@ -5,6 +5,10 @@ import {
5
5
  DBR_SERVER_PLATFORM_CANDIDATES,
6
6
  DBR_SERVER_PREFERRED_EXTS,
7
7
  DBR_SERVER_PREFERRED_FILES,
8
+ DCV_MOBILE_PLATFORM_CANDIDATES,
9
+ DCV_SERVER_PLATFORM_CANDIDATES,
10
+ DCV_SERVER_PREFERRED_EXTS,
11
+ DCV_SERVER_PREFERRED_FILES,
8
12
  CODE_FILE_EXTENSIONS
9
13
  } from "./config.js";
10
14
  import { SAMPLE_ROOTS, getExistingPath } from "./paths.js";
@@ -13,6 +17,7 @@ import { normalizePlatform } from "../normalizers.js";
13
17
  let cachedWebFrameworkPlatforms = null;
14
18
  let cachedDbrWebFrameworkPlatforms = null;
15
19
  let cachedDdvWebFrameworkPlatforms = null;
20
+ let cachedDcvWebFrameworkPlatforms = null;
16
21
 
17
22
  function getCodeFileExtensions() {
18
23
  return CODE_FILE_EXTENSIONS;
@@ -41,6 +46,14 @@ function getDbrCrossMobileRoot(platform) {
41
46
  return null;
42
47
  }
43
48
 
49
+ function getDcvCrossMobileRoot(platform) {
50
+ if (platform === "maui") return SAMPLE_ROOTS.dcvMaui;
51
+ if (platform === "react-native") return SAMPLE_ROOTS.dcvReactNative;
52
+ if (platform === "flutter") return SAMPLE_ROOTS.dcvFlutter;
53
+ if (platform === "spm") return SAMPLE_ROOTS.dcvSpm;
54
+ return null;
55
+ }
56
+
44
57
  function discoverCrossMobileSamples(platform) {
45
58
  const samples = { "high-level": [], "low-level": [] };
46
59
  const root = getDbrCrossMobileRoot(platform);
@@ -123,6 +136,14 @@ function discoverDirectoryNames(path) {
123
136
  return sortUnique(names);
124
137
  }
125
138
 
139
+ function discoverDirectoryNamesWithFilter(path, matcher) {
140
+ return discoverDirectoryNames(path).filter((name) => matcher(name));
141
+ }
142
+
143
+ function isDcvScenarioSampleName(sampleName) {
144
+ return /scan|scanner|mrz|vin|driver|license|document|gs1/i.test(sampleName || "");
145
+ }
146
+
126
147
  function discoverDbrServerSamples(platform) {
127
148
  const normalizedPlatform = normalizePlatform(platform);
128
149
  if (normalizedPlatform === "python") return discoverPythonSamples();
@@ -147,6 +168,95 @@ function getDbrServerPlatforms() {
147
168
  return DBR_SERVER_PLATFORM_CANDIDATES.filter((platform) => discoverDbrServerSamples(platform).length > 0);
148
169
  }
149
170
 
171
+ function discoverDcvCrossMobileSamples(platform) {
172
+ const root = getDcvCrossMobileRoot(platform);
173
+ if (!root || !existsSync(root)) return [];
174
+ if (platform === "spm") {
175
+ return existsSync(join(root, "Package.swift")) ? ["package-swift"] : [];
176
+ }
177
+
178
+ return discoverDirectoryNamesWithFilter(root, (name) => isDcvScenarioSampleName(name));
179
+ }
180
+
181
+ function discoverDcvMobileSamples(platform) {
182
+ const normalizedPlatform = normalizePlatform(platform);
183
+
184
+ if (["maui", "react-native", "flutter", "spm"].includes(normalizedPlatform)) {
185
+ return discoverDcvCrossMobileSamples(normalizedPlatform);
186
+ }
187
+
188
+ if (normalizedPlatform === "android") {
189
+ return discoverDirectoryNamesWithFilter(join(SAMPLE_ROOTS.dcvMobile, "Android"), (name) => isDcvScenarioSampleName(name));
190
+ }
191
+
192
+ if (normalizedPlatform === "ios") {
193
+ return discoverDirectoryNamesWithFilter(join(SAMPLE_ROOTS.dcvMobile, "ios"), (name) => isDcvScenarioSampleName(name));
194
+ }
195
+
196
+ return [];
197
+ }
198
+
199
+ function discoverDcvPythonSamples() {
200
+ const samples = [];
201
+ const pythonPath = join(SAMPLE_ROOTS.dcvPython, "Samples");
202
+ if (!existsSync(pythonPath)) return samples;
203
+
204
+ for (const entry of readdirSync(pythonPath, { withFileTypes: true })) {
205
+ if (entry.isFile() && entry.name.endsWith(".py")) {
206
+ samples.push(entry.name.replace(".py", ""));
207
+ }
208
+ }
209
+ return sortUnique(samples);
210
+ }
211
+
212
+ function getDcvServerSamplesRoot(platform) {
213
+ if (platform === "python") return SAMPLE_ROOTS.dcvPython;
214
+ if (platform === "dotnet") return SAMPLE_ROOTS.dcvDotnet;
215
+ if (platform === "java") return SAMPLE_ROOTS.dcvJava;
216
+ if (platform === "cpp") return SAMPLE_ROOTS.dcvCpp;
217
+ if (platform === "nodejs") return SAMPLE_ROOTS.dcvNodejs;
218
+ return null;
219
+ }
220
+
221
+ function discoverDcvServerSamples(platform) {
222
+ const normalizedPlatform = normalizePlatform(platform);
223
+ if (normalizedPlatform === "python") return discoverDcvPythonSamples();
224
+ if (normalizedPlatform === "nodejs") return discoverDirectoryNames(getDcvServerSamplesRoot("nodejs"));
225
+
226
+ if (["dotnet", "java", "cpp"].includes(normalizedPlatform)) {
227
+ const root = getDcvServerSamplesRoot(normalizedPlatform);
228
+ return discoverDirectoryNames(join(root || "", "Samples"));
229
+ }
230
+ return [];
231
+ }
232
+
233
+ function getDcvMobilePlatforms() {
234
+ return DCV_MOBILE_PLATFORM_CANDIDATES.filter((platform) => discoverDcvMobileSamples(platform).length > 0);
235
+ }
236
+
237
+ function getDcvServerPlatforms() {
238
+ return DCV_SERVER_PLATFORM_CANDIDATES.filter((platform) => discoverDcvServerSamples(platform).length > 0);
239
+ }
240
+
241
+ function discoverDcvWebSamples() {
242
+ const sampleSet = new Set();
243
+ if (!existsSync(SAMPLE_ROOTS.dcvWeb)) return [];
244
+
245
+ for (const entry of readdirSync(SAMPLE_ROOTS.dcvWeb, { withFileTypes: true })) {
246
+ if (entry.name.startsWith(".")) continue;
247
+ if (entry.isDirectory()) sampleSet.add(entry.name);
248
+ if (entry.isFile() && entry.name.endsWith(".html")) sampleSet.add(entry.name.replace(".html", ""));
249
+ }
250
+ return Array.from(sampleSet).sort();
251
+ }
252
+
253
+ function getDcvWebFrameworkPlatforms() {
254
+ if (cachedDcvWebFrameworkPlatforms) return cachedDcvWebFrameworkPlatforms;
255
+ // Current DCV web samples are plain JS scenario samples.
256
+ cachedDcvWebFrameworkPlatforms = [];
257
+ return cachedDcvWebFrameworkPlatforms;
258
+ }
259
+
150
260
  function discoverWebSamples() {
151
261
  const categories = { root: [], frameworks: [], scenarios: [] };
152
262
  const webPath = getDbrWebSamplesRoot();
@@ -273,7 +383,11 @@ function getDdvWebFrameworkPlatforms() {
273
383
 
274
384
  function getWebFrameworkPlatforms() {
275
385
  if (cachedWebFrameworkPlatforms) return cachedWebFrameworkPlatforms;
276
- const frameworks = new Set([...getDbrWebFrameworkPlatforms(), ...getDdvWebFrameworkPlatforms()]);
386
+ const frameworks = new Set([
387
+ ...getDbrWebFrameworkPlatforms(),
388
+ ...getDdvWebFrameworkPlatforms(),
389
+ ...getDcvWebFrameworkPlatforms()
390
+ ]);
277
391
  cachedWebFrameworkPlatforms = frameworks;
278
392
  return cachedWebFrameworkPlatforms;
279
393
  }
@@ -375,6 +489,85 @@ function getDdvSamplePath(sampleName) {
375
489
  return null;
376
490
  }
377
491
 
492
+ function getDcvMobileSamplePath(platform, sampleName) {
493
+ const normalizedPlatform = normalizePlatform(platform);
494
+
495
+ if (["maui", "react-native", "flutter"].includes(normalizedPlatform)) {
496
+ const root = getDcvCrossMobileRoot(normalizedPlatform);
497
+ const direct = root ? join(root, sampleName) : "";
498
+ return getExistingPath(direct) || direct;
499
+ }
500
+
501
+ if (normalizedPlatform === "spm") {
502
+ const root = getDcvCrossMobileRoot("spm");
503
+ if (!root) return "";
504
+ const packageFile = join(root, "Package.swift");
505
+ const readmeFile = join(root, "README.md");
506
+ if (sampleName === "package-swift") return getExistingPath(packageFile, readmeFile) || packageFile;
507
+ const direct = join(root, sampleName);
508
+ return getExistingPath(direct, packageFile, readmeFile) || direct;
509
+ }
510
+
511
+ if (normalizedPlatform === "android") {
512
+ const direct = join(SAMPLE_ROOTS.dcvMobile, "Android", sampleName);
513
+ return getExistingPath(direct) || direct;
514
+ }
515
+
516
+ if (normalizedPlatform === "ios") {
517
+ const direct = join(SAMPLE_ROOTS.dcvMobile, "ios", sampleName);
518
+ return getExistingPath(direct) || direct;
519
+ }
520
+
521
+ return "";
522
+ }
523
+
524
+ function getDcvServerSamplePath(platform, sampleName) {
525
+ const normalizedPlatform = normalizePlatform(platform) || "python";
526
+
527
+ if (normalizedPlatform === "python") {
528
+ const fileName = sampleName.endsWith(".py") ? sampleName : `${sampleName}.py`;
529
+ const primary = join(SAMPLE_ROOTS.dcvPython, "Samples", fileName);
530
+ return getExistingPath(primary) || primary;
531
+ }
532
+
533
+ if (normalizedPlatform === "nodejs") {
534
+ const root = getDcvServerSamplesRoot("nodejs");
535
+ if (!root) return "";
536
+ const direct = join(root, sampleName);
537
+ const js = join(root, `${sampleName}.js`);
538
+ const mjs = join(root, `${sampleName}.mjs`);
539
+ return getExistingPath(direct, js, mjs) || direct;
540
+ }
541
+
542
+ if (["dotnet", "java", "cpp"].includes(normalizedPlatform)) {
543
+ const root = getDcvServerSamplesRoot(normalizedPlatform);
544
+ if (!root) return "";
545
+ const direct = join(root, "Samples", sampleName);
546
+ return getExistingPath(direct) || direct;
547
+ }
548
+
549
+ return "";
550
+ }
551
+
552
+ function getDcvWebSamplePath(sampleName) {
553
+ if (!existsSync(SAMPLE_ROOTS.dcvWeb)) return null;
554
+ const directDir = join(SAMPLE_ROOTS.dcvWeb, sampleName);
555
+ if (existsSync(directDir) && statSync(directDir).isDirectory()) {
556
+ const indexPath = join(directDir, "index.html");
557
+ if (existsSync(indexPath)) return indexPath;
558
+ const readmePath = join(directDir, "README.md");
559
+ if (existsSync(readmePath)) return readmePath;
560
+ for (const entry of readdirSync(directDir, { withFileTypes: true })) {
561
+ if (entry.isFile() && entry.name.endsWith(".html")) return join(directDir, entry.name);
562
+ }
563
+ return directDir;
564
+ }
565
+
566
+ const htmlPath = join(SAMPLE_ROOTS.dcvWeb, `${sampleName}.html`);
567
+ if (existsSync(htmlPath)) return htmlPath;
568
+ return null;
569
+ }
570
+
378
571
  function readCodeFile(filePath) {
379
572
  if (!existsSync(filePath)) return null;
380
573
  return readFileSync(filePath, "utf8");
@@ -452,30 +645,79 @@ function getDbrServerSampleContent(platform, sampleName) {
452
645
  };
453
646
  }
454
647
 
648
+ function getDcvServerSampleContent(platform, sampleName) {
649
+ const samplePath = getDcvServerSamplePath(platform, sampleName);
650
+ if (!samplePath || !existsSync(samplePath)) return { text: "Sample not found", mimeType: "text/plain" };
651
+
652
+ const stat = statSync(samplePath);
653
+ if (stat.isFile()) {
654
+ const ext = extname(samplePath).replace(".", "");
655
+ return { text: readCodeFile(samplePath), mimeType: getMimeTypeForExtension(ext) };
656
+ }
657
+
658
+ const normalizedPlatform = normalizePlatform(platform);
659
+ const preferredFiles = DCV_SERVER_PREFERRED_FILES[normalizedPlatform] || [];
660
+ for (const name of preferredFiles) {
661
+ const candidate = join(samplePath, name);
662
+ if (existsSync(candidate) && statSync(candidate).isFile()) {
663
+ const ext = extname(candidate).replace(".", "");
664
+ return { text: readCodeFile(candidate), mimeType: getMimeTypeForExtension(ext) };
665
+ }
666
+ }
667
+
668
+ const readmePath = join(samplePath, "README.md");
669
+ if (existsSync(readmePath)) return { text: readCodeFile(readmePath), mimeType: "text/markdown" };
670
+
671
+ const codeFiles = findCodeFilesInSample(samplePath);
672
+ if (codeFiles.length > 0) {
673
+ const preferredExts = DCV_SERVER_PREFERRED_EXTS[normalizedPlatform] || [];
674
+ const preferred = codeFiles.find((file) => preferredExts.includes(file.extension)) || codeFiles[0];
675
+ return { text: readCodeFile(preferred.path), mimeType: getMimeTypeForExtension(preferred.extension) };
676
+ }
677
+
678
+ const files = readdirSync(samplePath, { withFileTypes: true })
679
+ .filter((entry) => entry.isFile())
680
+ .map((entry) => entry.name);
681
+ return {
682
+ text: files.length > 0 ? files.join("\n") : "Sample found, but no code files detected.",
683
+ mimeType: "text/plain"
684
+ };
685
+ }
686
+
455
687
  export {
456
688
  getCodeFileExtensions,
457
689
  isCodeFile,
458
690
  discoverMobileSamples,
459
691
  discoverDbrServerSamples,
460
692
  discoverPythonSamples,
693
+ discoverDcvMobileSamples,
694
+ discoverDcvServerSamples,
695
+ discoverDcvWebSamples,
461
696
  discoverWebSamples,
462
697
  getWebSamplePath,
463
698
  discoverDwtSamples,
464
699
  discoverDdvSamples,
465
700
  mapDdvSampleToFramework,
466
701
  getDbrWebFrameworkPlatforms,
702
+ getDcvWebFrameworkPlatforms,
467
703
  getDdvWebFrameworkPlatforms,
468
704
  getWebFrameworkPlatforms,
469
705
  findCodeFilesInSample,
470
706
  getDbrMobilePlatforms,
471
707
  getDbrServerPlatforms,
708
+ getDcvMobilePlatforms,
709
+ getDcvServerPlatforms,
472
710
  getMobileSamplePath,
473
711
  getPythonSamplePath,
474
712
  getDbrServerSamplePath,
713
+ getDcvMobileSamplePath,
714
+ getDcvServerSamplePath,
715
+ getDcvWebSamplePath,
475
716
  getDwtSamplePath,
476
717
  getDdvSamplePath,
477
718
  readCodeFile,
478
719
  getMainCodeFile,
479
720
  getMimeTypeForExtension,
480
- getDbrServerSampleContent
721
+ getDbrServerSampleContent,
722
+ getDcvServerSampleContent
481
723
  };
@@ -70,6 +70,16 @@ function parseSampleUri(uri) {
70
70
  };
71
71
  }
72
72
 
73
+ if (parsed.product === "dcv" && (parsed.edition === "mobile" || parsed.edition === "server" || parsed.edition === "web")) {
74
+ return {
75
+ product: "dcv",
76
+ edition: parsed.edition,
77
+ platform: parsed.platform,
78
+ version: parsed.version,
79
+ sampleName: parsed.parts[4]
80
+ };
81
+ }
82
+
73
83
  return null;
74
84
  }
75
85
 
@@ -12,7 +12,7 @@ function detectMajorFromQuery(query) {
12
12
  if (!query) return null;
13
13
  const text = String(query);
14
14
  const explicit = text.match(/(?:\bv|\bversion\s*)(\d{1,2})(?:\.\d+)?/i);
15
- const productScoped = text.match(/(?:dbr|dwt|ddv)[^0-9]*(\d{1,2})(?:\.\d+)?/i);
15
+ const productScoped = text.match(/(?:dbr|dcv|dwt|ddv)[^0-9]*(\d{1,2})(?:\.\d+)?/i);
16
16
  const match = explicit || productScoped;
17
17
  if (!match) return null;
18
18
  const major = Number.parseInt(match[1], 10);
@@ -83,6 +83,13 @@ function ensureLatestMajor({ product, version, query, edition, platform, latestM
83
83
  };
84
84
  }
85
85
 
86
+ if (inferredProduct === "dcv") {
87
+ return {
88
+ ok: false,
89
+ message: `This MCP server only serves the latest major version of DCV (v${currentMajor}).`
90
+ };
91
+ }
92
+
86
93
  if (inferredProduct === "dbr" && requestedMajor < 9) {
87
94
  return {
88
95
  ok: false,
@@ -133,12 +140,15 @@ function buildVersionPolicyText(latestMajor) {
133
140
  "This MCP server only serves the latest major versions of each product.",
134
141
  "",
135
142
  `- DBR latest major: v${latestMajor.dbr}`,
143
+ `- DCV latest major: v${latestMajor.dcv}`,
136
144
  `- DWT latest major: v${latestMajor.dwt}`,
137
145
  `- DDV latest major: v${latestMajor.ddv}`,
138
146
  "",
139
147
  "Legacy support:",
140
148
  "- DBR v9 and v10 docs are linked when requested.",
149
+ "- DCV has no legacy archive links in this server.",
141
150
  `- DWT archived docs available: ${dwtLegacyVersions || "none"}.`,
151
+ "- DDV has no legacy archive links in this server.",
142
152
  "",
143
153
  "Requests for older major versions are refused with a helpful message."
144
154
  ].join("\n");