simple-dynamsoft-mcp 7.3.53 → 7.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.
- package/data/metadata/data-manifest.json +10 -10
- package/package.json +4 -2
- package/scripts/check-version-drift.mjs +80 -0
- package/src/rag/config.js +5 -0
- package/src/rag/index.js +5 -1
- package/src/rag/lexical-provider.js +48 -15
- package/src/rag/providers.js +27 -6
- package/src/rag/search-utils.js +144 -4
- package/src/rag/vector-cache.js +17 -1
- package/src/server/create-server.js +121 -99
- package/src/server/normalizers.js +78 -1
- package/src/server/public-offerings.js +12 -0
- package/src/server/resource-index/builders.js +76 -16
- package/src/server/resource-index/config.js +4 -2
- package/src/server/resource-index/docs-loader.js +22 -2
- package/src/server/resource-index/samples.js +24 -3
- package/src/server/resource-index/version-policy.js +34 -8
- package/src/server/resources/register-resources.js +4 -1
- package/src/server/tools/public-routing.js +8 -0
- package/src/server/tools/register-index-tools.js +64 -10
- package/src/server/tools/register-project-tools.js +160 -18
- package/src/server/tools/register-quickstart-tools.js +357 -40
- package/src/server/tools/register-sample-tools.js +10 -5
- package/src/server/tools/register-version-tools.js +10 -5
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { existsSync, statSync } from "node:fs";
|
|
2
2
|
import { extname, join } from "node:path";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
buildUnknownPublicProductResponse,
|
|
6
|
+
isKnownPublicOffering,
|
|
7
|
+
API_LEVEL_NOTE,
|
|
8
|
+
DBR_ONLY_EDITIONS_NOTE,
|
|
9
|
+
WEB_ONLY_OMIT_NOTE
|
|
10
|
+
} from "../public-offerings.js";
|
|
5
11
|
import { buildUnsupportedPublicScopeResponse } from "./public-routing.js";
|
|
6
12
|
|
|
7
13
|
export function registerQuickstartTools({
|
|
@@ -25,8 +31,54 @@ export function registerQuickstartTools({
|
|
|
25
31
|
getDdvSamplePath,
|
|
26
32
|
readCodeFile,
|
|
27
33
|
getMainCodeFile,
|
|
28
|
-
getWebSamplePath
|
|
34
|
+
getWebSamplePath,
|
|
35
|
+
getMrzWebSamplePath,
|
|
36
|
+
getMdsWebSamplePath,
|
|
37
|
+
getSampleSuggestions,
|
|
38
|
+
getSampleIdFromUri,
|
|
39
|
+
formatScopeLabel
|
|
29
40
|
}) {
|
|
41
|
+
// Actionable miss response: instead of a bare "Sample not found", surface
|
|
42
|
+
// related samples the agent can fetch next (mirrors get_sample_files). (#151)
|
|
43
|
+
async function buildQuickstartMissResponse({ reason, product, edition, platform, scenario }) {
|
|
44
|
+
const lines = [reason];
|
|
45
|
+
let suggestions = [];
|
|
46
|
+
if (typeof getSampleSuggestions === "function") {
|
|
47
|
+
try {
|
|
48
|
+
suggestions = await getSampleSuggestions({
|
|
49
|
+
query: [scenario, product, edition, platform].filter(Boolean).join(" "),
|
|
50
|
+
product,
|
|
51
|
+
edition,
|
|
52
|
+
platform,
|
|
53
|
+
limit: 5
|
|
54
|
+
});
|
|
55
|
+
} catch {
|
|
56
|
+
suggestions = [];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const content = [{
|
|
60
|
+
type: "text",
|
|
61
|
+
text: suggestions.length
|
|
62
|
+
? `${reason}\nRelated samples you can fetch with get_sample_files or open with get_quickstart:`
|
|
63
|
+
: `${reason}\nCall get_index to see valid product/edition/platform combinations, or search for a scenario.`
|
|
64
|
+
}];
|
|
65
|
+
for (const entry of suggestions) {
|
|
66
|
+
const versionLabel = entry.version ? `v${entry.version}` : "n/a";
|
|
67
|
+
const scopeLabel = typeof formatScopeLabel === "function" ? formatScopeLabel(entry) : `${entry.product}/${entry.edition}`;
|
|
68
|
+
const sampleId = entry.type === "sample" && typeof getSampleIdFromUri === "function" ? getSampleIdFromUri(entry.uri) : "";
|
|
69
|
+
const sampleHint = sampleId ? ` | sample_id: ${sampleId}` : "";
|
|
70
|
+
content.push({
|
|
71
|
+
type: "resource_link",
|
|
72
|
+
uri: entry.uri,
|
|
73
|
+
name: entry.title,
|
|
74
|
+
description: `${entry.type.toUpperCase()} | ${scopeLabel} | ${versionLabel} - ${entry.summary}${sampleHint}`,
|
|
75
|
+
mimeType: entry.mimeType,
|
|
76
|
+
annotations: { audience: ["assistant"], priority: 0.6 }
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return { isError: true, content };
|
|
80
|
+
}
|
|
81
|
+
|
|
30
82
|
function getPublicWebQuickstartLinks(product) {
|
|
31
83
|
if (product === "mrz") {
|
|
32
84
|
return {
|
|
@@ -94,11 +146,11 @@ export function registerQuickstartTools({
|
|
|
94
146
|
"",
|
|
95
147
|
"PARAMETERS:",
|
|
96
148
|
"- product (required): dbr, dwt, ddv, mrz, or mds.",
|
|
97
|
-
|
|
98
|
-
|
|
149
|
+
`- edition: core, mobile, web, or server. ${DBR_ONLY_EDITIONS_NOTE} Inferred from platform if omitted.`,
|
|
150
|
+
`- platform: only DBR spans multiple platforms (android, ios, js, python, cpp, java, dotnet, nodejs, react, vue, angular, flutter, react-native, maui, etc.). ${WEB_ONLY_OMIT_NOTE}`,
|
|
99
151
|
"- language: kotlin, java, swift, js, ts, python, cpp, csharp, react, vue, angular. Helps select the best sample variant.",
|
|
100
152
|
"- version: Version constraint. Latest major is used by default.",
|
|
101
|
-
|
|
153
|
+
`- api_level: ${API_LEVEL_NOTE}`,
|
|
102
154
|
"- scenario: MRZ, document scan, camera, image, single, multiple, react, vue, angular, etc. DBR web defaults to foundational guidance; MRZ and MDS return public workflow guidance where available.",
|
|
103
155
|
"",
|
|
104
156
|
"RETURNS: A formatted text block with SDK version, trial license key, install commands, and sample code. Ready to copy-paste.",
|
|
@@ -107,11 +159,11 @@ export function registerQuickstartTools({
|
|
|
107
159
|
].join("\n"),
|
|
108
160
|
inputSchema: {
|
|
109
161
|
product: z.string().trim().min(1, "Product is required.").describe("Product: dbr, dwt, ddv, mrz, mds"),
|
|
110
|
-
edition: z.string().optional().describe(
|
|
111
|
-
platform: z.string().optional().describe(
|
|
162
|
+
edition: z.string().optional().describe(`Edition: core, mobile, web, server/desktop. ${DBR_ONLY_EDITIONS_NOTE}`),
|
|
163
|
+
platform: z.string().optional().describe(`Platform (DBR only spans multiple): android, ios, maui, react-native, flutter, js, python, cpp, java, dotnet, nodejs, angular, blazor, capacitor, electron, es6, native-ts, next, nuxt, pwa, react, requirejs, svelte, vue, webview, spm, core. ${WEB_ONLY_OMIT_NOTE}`),
|
|
112
164
|
language: z.string().optional().describe("Language hint: kotlin, java, swift, js, ts, python, cpp, csharp, react, vue, angular"),
|
|
113
165
|
version: z.string().optional().describe("Version constraint"),
|
|
114
|
-
api_level: z.string().optional().describe(
|
|
166
|
+
api_level: z.string().optional().describe(`API level: ${API_LEVEL_NOTE}`),
|
|
115
167
|
scenario: z.string().optional().describe("Scenario: camera, image, single, multiple, MRZ, document scan/normalization, driver license, react, etc.")
|
|
116
168
|
},
|
|
117
169
|
annotations: {
|
|
@@ -281,7 +333,44 @@ export function registerQuickstartTools({
|
|
|
281
333
|
if (effectiveEdition === "web") {
|
|
282
334
|
const sdkEntry = registry.sdks["dcv-web"];
|
|
283
335
|
if (isPublicDcvProduct) {
|
|
336
|
+
// Serve the hydrated hello-world sample inline instead of link-only.
|
|
337
|
+
// The dedicated web sample repos ship runnable starters (#136).
|
|
284
338
|
const publicLinks = getPublicWebQuickstartLinks(normalizedProduct);
|
|
339
|
+
const getDedicated = normalizedProduct === "mrz" ? getMrzWebSamplePath : getMdsWebSamplePath;
|
|
340
|
+
let dedicatedSample = "hello-world";
|
|
341
|
+
if (normalizedProduct === "mds" && (scenarioLower.includes("pdf"))) dedicatedSample = "scanning-to-pdf";
|
|
342
|
+
else if (scenarioLower.includes("image") || scenarioLower.includes("file")) {
|
|
343
|
+
dedicatedSample = normalizedProduct === "mrz" ? "use-file-input" : "image-file-scanning";
|
|
344
|
+
}
|
|
345
|
+
const dedicatedPath = typeof getDedicated === "function" ? getDedicated("root", dedicatedSample) : "";
|
|
346
|
+
// Guard against a directory result (the resolver can return a dir when a
|
|
347
|
+
// sample lacks a single html entry): readCodeFile would throw EISDIR.
|
|
348
|
+
if (dedicatedPath && existsSync(dedicatedPath) && statSync(dedicatedPath).isFile()) {
|
|
349
|
+
const dedicatedContent = readCodeFile(dedicatedPath);
|
|
350
|
+
const mrzFields = normalizedProduct === "mrz"
|
|
351
|
+
? "\n**Result fields** (`result.data`): firstName, lastName, documentNumber, dateOfExpiry, dateOfBirth, nationality, sex, issuingState.\n"
|
|
352
|
+
: "";
|
|
353
|
+
return {
|
|
354
|
+
content: [{
|
|
355
|
+
type: "text",
|
|
356
|
+
text: [
|
|
357
|
+
`# Quick Start: ${publicProductLabel} Web`,
|
|
358
|
+
"",
|
|
359
|
+
`**SDK Version:** ${sdkEntry.version}`,
|
|
360
|
+
`**Trial License:** \`${registry.trial_license}\``,
|
|
361
|
+
mrzFields,
|
|
362
|
+
`## Sample: ${dedicatedSample}.html`,
|
|
363
|
+
"```html",
|
|
364
|
+
dedicatedContent,
|
|
365
|
+
"```",
|
|
366
|
+
"",
|
|
367
|
+
`Docs: ${publicLinks.docsUrl}`,
|
|
368
|
+
`More samples: ${publicLinks.samplesUrl}`
|
|
369
|
+
].filter(Boolean).join("\n")
|
|
370
|
+
}]
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
// Fall back to reference links only if the sample is not hydrated.
|
|
285
374
|
return buildPublicReferenceQuickstart({
|
|
286
375
|
product: normalizedProduct,
|
|
287
376
|
edition: effectiveEdition,
|
|
@@ -386,36 +475,80 @@ export function registerQuickstartTools({
|
|
|
386
475
|
if (normalizedProduct === "dbr" && normalizedEdition === "server") {
|
|
387
476
|
const sdkEntry = registry.sdks["dbr-server"];
|
|
388
477
|
const scenarioLower = (scenario || "").toLowerCase();
|
|
389
|
-
const
|
|
390
|
-
|
|
478
|
+
const targetPlatform = normalizePlatform(normalizedPlatform) || "python";
|
|
479
|
+
|
|
480
|
+
// Per-platform "hello world" sample names (repos differ in convention).
|
|
481
|
+
const SERVER_DEFAULT_SAMPLE = {
|
|
482
|
+
python: scenarioLower.includes("video") ? "video_decoding" : "read_an_image",
|
|
483
|
+
nodejs: "express",
|
|
484
|
+
java: scenarioLower.includes("video") ? "VideoDecoding" : "HelloWorld",
|
|
485
|
+
cpp: scenarioLower.includes("video") ? "VideoDecoding" : "HelloWorld",
|
|
486
|
+
dotnet: "HelloWorld"
|
|
487
|
+
};
|
|
488
|
+
const sampleName = SERVER_DEFAULT_SAMPLE[targetPlatform];
|
|
489
|
+
if (!sampleName) {
|
|
490
|
+
return await buildQuickstartMissResponse({
|
|
491
|
+
reason: `DBR server quickstart is not available for platform "${targetPlatform}". Supported: python, nodejs, java, cpp, dotnet.`,
|
|
492
|
+
product: "dbr", edition: "server", platform: targetPlatform, scenario
|
|
493
|
+
});
|
|
494
|
+
}
|
|
391
495
|
|
|
392
|
-
|
|
393
|
-
|
|
496
|
+
const samplePath = getDbrServerSamplePath(targetPlatform, sampleName);
|
|
497
|
+
if (!samplePath || !existsSync(samplePath)) {
|
|
498
|
+
return await buildQuickstartMissResponse({
|
|
499
|
+
reason: `DBR server sample "${sampleName}" not found for ${targetPlatform}.`,
|
|
500
|
+
product: "dbr", edition: "server", platform: targetPlatform, scenario
|
|
501
|
+
});
|
|
394
502
|
}
|
|
395
503
|
|
|
396
|
-
|
|
504
|
+
// java/cpp/dotnet/nodejs samples are project directories; python is a file.
|
|
505
|
+
let contentFileName = sampleName;
|
|
506
|
+
let contentPath = samplePath;
|
|
507
|
+
if (statSync(samplePath).isDirectory()) {
|
|
508
|
+
const codeFiles = findCodeFilesInSample(samplePath);
|
|
509
|
+
const main = codeFiles.find((f) => /^(main|program|hello|read|index|app|server)/i.test(f.filename)) || codeFiles[0];
|
|
510
|
+
if (!main) {
|
|
511
|
+
return await buildQuickstartMissResponse({
|
|
512
|
+
reason: `Found the ${sampleName} project for ${targetPlatform} but no primary source file inside it.`,
|
|
513
|
+
product: "dbr", edition: "server", platform: targetPlatform, scenario
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
contentPath = main.path;
|
|
517
|
+
contentFileName = main.relativePath || main.filename;
|
|
518
|
+
}
|
|
519
|
+
const content = readCodeFile(contentPath);
|
|
520
|
+
const platformLabel = { python: "Python", nodejs: "Node.js", java: "Java", cpp: "C++", dotnet: ".NET" }[targetPlatform] || targetPlatform;
|
|
521
|
+
const installLines = [];
|
|
522
|
+
const installObj = sdkEntry.platforms?.[targetPlatform]?.installation;
|
|
523
|
+
if (installObj && typeof installObj === "object") {
|
|
524
|
+
for (const value of Object.values(installObj)) {
|
|
525
|
+
if (typeof value === "string" && value.trim()) installLines.push(value);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
const fence = { python: "python", nodejs: "javascript", java: "java", cpp: "cpp", dotnet: "csharp" }[targetPlatform] || "text";
|
|
397
529
|
|
|
398
530
|
return {
|
|
399
531
|
content: [{
|
|
400
532
|
type: "text",
|
|
401
533
|
text: [
|
|
402
|
-
|
|
534
|
+
`# Quick Start: DBR Server (${platformLabel})`,
|
|
403
535
|
"",
|
|
404
536
|
`**SDK Version:** ${sdkEntry.version}`,
|
|
405
537
|
`**Trial License:** \`${registry.trial_license}\``,
|
|
406
538
|
"",
|
|
407
|
-
"## Install",
|
|
408
|
-
"```bash",
|
|
409
|
-
|
|
410
|
-
"```",
|
|
411
|
-
"",
|
|
412
|
-
`## ${sampleName}
|
|
413
|
-
"```
|
|
539
|
+
installLines.length ? "## Install" : "",
|
|
540
|
+
installLines.length ? "```bash" : "",
|
|
541
|
+
...installLines,
|
|
542
|
+
installLines.length ? "```" : "",
|
|
543
|
+
installLines.length ? "" : "",
|
|
544
|
+
`## ${sampleName} — ${contentFileName}`,
|
|
545
|
+
"```" + fence,
|
|
414
546
|
content,
|
|
415
547
|
"```",
|
|
416
548
|
"",
|
|
417
|
-
`
|
|
418
|
-
|
|
549
|
+
`Full project files: get_sample_files product=dbr edition=server platform=${targetPlatform} sample_id=${sampleName}`,
|
|
550
|
+
`Docs: ${sdkEntry.platforms?.[targetPlatform]?.docs?.["user-guide"] || "N/A"}`
|
|
551
|
+
].filter(Boolean).join("\n")
|
|
419
552
|
}]
|
|
420
553
|
};
|
|
421
554
|
}
|
|
@@ -423,14 +556,106 @@ export function registerQuickstartTools({
|
|
|
423
556
|
if (normalizedProduct === "dbr" && normalizedEdition === "web") {
|
|
424
557
|
const sdkEntry = registry.sdks["dbr-web"];
|
|
425
558
|
const scenarioLower = (scenario || "").toLowerCase();
|
|
426
|
-
|
|
427
|
-
|
|
559
|
+
|
|
560
|
+
// Framework-specific starter: if the caller named a JS framework that ships
|
|
561
|
+
// a project under frameworks/, serve runnable foundational code inline AND
|
|
562
|
+
// point to the full framework project via get_sample_files. Framework
|
|
563
|
+
// samples are multi-file Vite/CLI projects, so a single inlined file is not
|
|
564
|
+
// standalone-runnable — the fetch pointer is how the agent gets the rest
|
|
565
|
+
// (issue #134).
|
|
566
|
+
const DBR_WEB_FRAMEWORKS = new Set(["react", "angular", "vue", "next", "nuxt", "svelte", "electron", "capacitor", "blazor", "es6", "native-ts", "pwa", "requirejs", "webview"]);
|
|
567
|
+
if (normalizedPlatform && DBR_WEB_FRAMEWORKS.has(normalizedPlatform)) {
|
|
568
|
+
const foundationalPath = getWebSamplePath("basics", "scan-a-single-barcode")
|
|
569
|
+
|| getWebSamplePath("basics", "hello-world");
|
|
570
|
+
const foundationalCode = foundationalPath && existsSync(foundationalPath) ? readCodeFile(foundationalPath) : "";
|
|
571
|
+
return {
|
|
572
|
+
content: [{
|
|
573
|
+
type: "text",
|
|
574
|
+
text: [
|
|
575
|
+
`# Quick Start: DBR Web (${normalizedPlatform})`,
|
|
576
|
+
"",
|
|
577
|
+
`**SDK Version:** ${sdkEntry.version}`,
|
|
578
|
+
`**Trial License:** \`${registry.trial_license}\``,
|
|
579
|
+
`**Starter profile:** ${normalizedPlatform} framework project available`,
|
|
580
|
+
"",
|
|
581
|
+
"## Install (npm)",
|
|
582
|
+
"```bash",
|
|
583
|
+
sdkEntry.platforms.web.installation.npm,
|
|
584
|
+
"```",
|
|
585
|
+
"",
|
|
586
|
+
`## Full ${normalizedPlatform} project`,
|
|
587
|
+
`A ready-to-run ${normalizedPlatform} sample ships with this MCP. Fetch all its files with:`,
|
|
588
|
+
"```",
|
|
589
|
+
`get_sample_files product=dbr edition=web platform=${normalizedPlatform} sample_id=frameworks/${normalizedPlatform}`,
|
|
590
|
+
"```",
|
|
591
|
+
foundationalCode ? "" : null,
|
|
592
|
+
foundationalCode ? "## Foundational reference (vanilla JS — the same CaptureVisionRouter flow the framework sample wraps)" : null,
|
|
593
|
+
foundationalCode ? "```html" : null,
|
|
594
|
+
foundationalCode || null,
|
|
595
|
+
foundationalCode ? "```" : null,
|
|
596
|
+
"",
|
|
597
|
+
`Docs: ${sdkEntry.platforms.web.docs["user-guide"]}`
|
|
598
|
+
].filter((line) => line !== null).join("\n")
|
|
599
|
+
}]
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Map the scenario to a foundational sample under basics/. Web has no
|
|
604
|
+
// high-level vs low-level API split (api_level is a mobile-only concept),
|
|
605
|
+
// so it is intentionally not consulted here.
|
|
606
|
+
let sampleName;
|
|
607
|
+
// The camera scenario fallback below substitutes a differently-named
|
|
608
|
+
// scenarios/* sample, so it is only appropriate for the generic
|
|
609
|
+
// camera/single/default request — not for requests that named a
|
|
610
|
+
// specific starter (hello) or a different intent (image/file, which is
|
|
611
|
+
// camera-based nowhere in scenarios/*). Those hard-error honestly when
|
|
612
|
+
// their sample is absent.
|
|
613
|
+
let allowCameraFallback = false;
|
|
614
|
+
if (scenarioLower.includes("hello")) {
|
|
615
|
+
sampleName = "hello-world";
|
|
616
|
+
} else if (scenarioLower.includes("image") || scenarioLower.includes("file")) {
|
|
617
|
+
sampleName = "read-an-image";
|
|
618
|
+
} else {
|
|
619
|
+
sampleName = "scan-a-single-barcode"; // camera / single / default
|
|
620
|
+
allowCameraFallback = true;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Foundational samples now live under basics/ upstream; getWebSamplePath
|
|
624
|
+
// falls back to the repo root when basics/ is absent, so this stays
|
|
625
|
+
// compatible with older sample sets that kept them at the root.
|
|
626
|
+
let samplePath = getWebSamplePath("basics", sampleName);
|
|
627
|
+
let fallbackSample = null;
|
|
628
|
+
|
|
629
|
+
// Graceful degradation: a deployment may serve an older sample data set
|
|
630
|
+
// that predates the foundational samples. Rather than hard-erroring,
|
|
631
|
+
// fall back to a reliably-present camera scenario sample — but only when
|
|
632
|
+
// the request is camera-intent (see allowCameraFallback above).
|
|
633
|
+
if ((!samplePath || !existsSync(samplePath)) && allowCameraFallback) {
|
|
634
|
+
for (const candidate of ["scan-common-1D-and-2D", "scan-qr-code"]) {
|
|
635
|
+
const candidatePath = getWebSamplePath("scenarios", candidate);
|
|
636
|
+
if (candidatePath && existsSync(candidatePath)) {
|
|
637
|
+
samplePath = candidatePath;
|
|
638
|
+
fallbackSample = candidate;
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
428
643
|
|
|
429
644
|
if (!samplePath || !existsSync(samplePath)) {
|
|
430
|
-
return
|
|
645
|
+
return await buildQuickstartMissResponse({
|
|
646
|
+
reason: `DBR web sample "${sampleName}" not found in the served sample set.`,
|
|
647
|
+
product: "dbr", edition: "web", platform: normalizedPlatform, scenario
|
|
648
|
+
});
|
|
431
649
|
}
|
|
432
650
|
|
|
433
651
|
const content = readCodeFile(samplePath);
|
|
652
|
+
const displaySample = fallbackSample || sampleName;
|
|
653
|
+
const sampleHeading = fallbackSample
|
|
654
|
+
? `## Sample: ${displaySample} (camera scenario fallback)`
|
|
655
|
+
: `## Foundational sample: ${displaySample}`;
|
|
656
|
+
const fallbackNoteLines = fallbackSample
|
|
657
|
+
? [`> Note: \`${sampleName}\` was not available in the served sample set; showing the \`${fallbackSample}\` camera scenario instead.`, ""]
|
|
658
|
+
: [];
|
|
434
659
|
|
|
435
660
|
return {
|
|
436
661
|
content: [{
|
|
@@ -443,7 +668,9 @@ export function registerQuickstartTools({
|
|
|
443
668
|
"**Starter profile:** Foundational-first",
|
|
444
669
|
"",
|
|
445
670
|
"Use the foundational web flow first so capture and decoding remain explicit and easier to adapt.",
|
|
671
|
+
"api_level does not apply to DBR web (it is a mobile-only distinction).",
|
|
446
672
|
"",
|
|
673
|
+
...fallbackNoteLines,
|
|
447
674
|
"## Option 1: CDN",
|
|
448
675
|
"```html",
|
|
449
676
|
`<script src="${sdkEntry.platforms.web.installation.cdn}"></script>`,
|
|
@@ -454,7 +681,7 @@ export function registerQuickstartTools({
|
|
|
454
681
|
sdkEntry.platforms.web.installation.npm,
|
|
455
682
|
"```",
|
|
456
683
|
"",
|
|
457
|
-
|
|
684
|
+
sampleHeading,
|
|
458
685
|
"```html",
|
|
459
686
|
content,
|
|
460
687
|
"```",
|
|
@@ -471,24 +698,73 @@ export function registerQuickstartTools({
|
|
|
471
698
|
const level = normalizeApiLevel(api_level || scenario);
|
|
472
699
|
const scenarioLower = (scenario || "").toLowerCase();
|
|
473
700
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
701
|
+
const isCrossPlatform = ["flutter", "react-native", "maui"].includes(targetPlatform);
|
|
702
|
+
const wantsImage = scenarioLower.includes("image") || scenarioLower.includes("file");
|
|
703
|
+
const wantsDriverLicense = scenarioLower.includes("driver") || scenarioLower.includes("license") || scenarioLower.includes("licence");
|
|
477
704
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
705
|
+
let sampleName;
|
|
706
|
+
if (isCrossPlatform) {
|
|
707
|
+
// Cross-platform repos use different sample names than Android/iOS. There
|
|
708
|
+
// is no still-image decode sample in these editions (#132, #159).
|
|
709
|
+
if (wantsImage) {
|
|
710
|
+
return {
|
|
711
|
+
content: [{
|
|
712
|
+
type: "text",
|
|
713
|
+
text: [
|
|
714
|
+
`# DBR ${targetPlatform}: still-image decoding`,
|
|
715
|
+
"",
|
|
716
|
+
`The ${targetPlatform} edition ships camera-stream barcode scanning, not a still-image/gallery decode sample.`,
|
|
717
|
+
"",
|
|
718
|
+
"Nearest options:",
|
|
719
|
+
"- Use the camera-based scanner below (ScanBarcodes_ReadyToUseComponent).",
|
|
720
|
+
"- For decoding a picked/gallery image, use the native Android/iOS `DecodeFromAnImage` sample (get_quickstart product=dbr edition=mobile platform=android scenario=image) and bridge it, or call the foundational API on a captured frame.",
|
|
721
|
+
"",
|
|
722
|
+
`Docs: ${sdkEntry.platforms[targetPlatform]?.docs?.[level]?.["user-guide"] || sdkEntry.platforms[targetPlatform]?.docs?.["high-level"]?.["user-guide"] || "N/A"}`
|
|
723
|
+
].join("\n")
|
|
724
|
+
}]
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
sampleName = wantsDriverLicense
|
|
728
|
+
? "ScanDriversLicense"
|
|
729
|
+
: (level === "low-level" ? "ScanBarcodes_FoundationalAPI" : "ScanBarcodes_ReadyToUseComponent");
|
|
730
|
+
} else {
|
|
731
|
+
sampleName = "ScanSingleBarcode";
|
|
732
|
+
if (scenarioLower.includes("multiple") || scenarioLower.includes("batch")) sampleName = "ScanMultipleBarcodes";
|
|
733
|
+
else if (wantsImage) sampleName = "DecodeFromAnImage";
|
|
734
|
+
|
|
735
|
+
if (level === "low-level") {
|
|
736
|
+
if (sampleName === "ScanSingleBarcode" || sampleName === "ScanMultipleBarcodes") {
|
|
737
|
+
sampleName = "DecodeWithCameraEnhancer";
|
|
738
|
+
}
|
|
481
739
|
}
|
|
482
740
|
}
|
|
483
741
|
|
|
484
|
-
|
|
742
|
+
// Prefer a Kotlin variant when the caller asked for Kotlin (#135).
|
|
743
|
+
const wantsKotlin = String(language || "").toLowerCase() === "kotlin";
|
|
744
|
+
let samplePath = "";
|
|
745
|
+
let servedVariant = sampleName;
|
|
746
|
+
if (wantsKotlin && targetPlatform === "android") {
|
|
747
|
+
const ktPath = getMobileSamplePath(targetPlatform, level, `${sampleName}Kt`);
|
|
748
|
+
if (existsSync(ktPath)) {
|
|
749
|
+
samplePath = ktPath;
|
|
750
|
+
servedVariant = `${sampleName}Kt`;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
if (!samplePath) samplePath = getMobileSamplePath(targetPlatform, level, sampleName);
|
|
754
|
+
|
|
485
755
|
if (!existsSync(samplePath)) {
|
|
486
|
-
return
|
|
756
|
+
return await buildQuickstartMissResponse({
|
|
757
|
+
reason: `DBR mobile sample "${sampleName}" not found for ${targetPlatform}.`,
|
|
758
|
+
product: "dbr", edition: "mobile", platform: targetPlatform, scenario
|
|
759
|
+
});
|
|
487
760
|
}
|
|
488
761
|
|
|
489
762
|
const mainFile = getMainCodeFile(targetPlatform, samplePath);
|
|
490
763
|
if (!mainFile) {
|
|
491
|
-
return
|
|
764
|
+
return await buildQuickstartMissResponse({
|
|
765
|
+
reason: `Found the ${servedVariant} sample for ${targetPlatform} but could not locate its main code file.`,
|
|
766
|
+
product: "dbr", edition: "mobile", platform: targetPlatform, scenario
|
|
767
|
+
});
|
|
492
768
|
}
|
|
493
769
|
|
|
494
770
|
const content = readCodeFile(mainFile.path);
|
|
@@ -521,7 +797,7 @@ dependencies {
|
|
|
521
797
|
\`\`\`xml
|
|
522
798
|
<uses-permission android:name="android.permission.CAMERA" />
|
|
523
799
|
\`\`\``;
|
|
524
|
-
} else {
|
|
800
|
+
} else if (targetPlatform === "ios") {
|
|
525
801
|
deps = `
|
|
526
802
|
## Dependencies
|
|
527
803
|
|
|
@@ -540,13 +816,41 @@ end
|
|
|
540
816
|
<key>NSCameraUsageDescription</key>
|
|
541
817
|
<string>Camera access for barcode scanning</string>
|
|
542
818
|
\`\`\``;
|
|
819
|
+
} else if (targetPlatform === "flutter") {
|
|
820
|
+
deps = `
|
|
821
|
+
## Dependencies
|
|
822
|
+
|
|
823
|
+
**pubspec.yaml**
|
|
824
|
+
\`\`\`yaml
|
|
825
|
+
dependencies:
|
|
826
|
+
dynamsoft_barcode_reader_bundle: ^${sdkEntry.version}
|
|
827
|
+
\`\`\`
|
|
828
|
+
Then run \`flutter pub get\`. Add camera usage permissions to AndroidManifest.xml and Info.plist.`;
|
|
829
|
+
} else if (targetPlatform === "react-native") {
|
|
830
|
+
deps = `
|
|
831
|
+
## Dependencies
|
|
832
|
+
|
|
833
|
+
\`\`\`bash
|
|
834
|
+
npm install dynamsoft-capture-vision-react-native
|
|
835
|
+
\`\`\`
|
|
836
|
+
Add camera permissions to AndroidManifest.xml and Info.plist, then rebuild the app.`;
|
|
837
|
+
} else if (targetPlatform === "maui") {
|
|
838
|
+
deps = `
|
|
839
|
+
## Dependencies
|
|
840
|
+
|
|
841
|
+
\`\`\`xml
|
|
842
|
+
<PackageReference Include="Dynamsoft.BarcodeReaderBundle.Maui" Version="${sdkEntry.version}" />
|
|
843
|
+
\`\`\`
|
|
844
|
+
Add camera permissions in Platforms/Android/AndroidManifest.xml and Platforms/iOS/Info.plist.`;
|
|
543
845
|
}
|
|
544
846
|
|
|
545
847
|
const output = [
|
|
546
848
|
"# Quick Start: DBR Mobile",
|
|
547
849
|
"",
|
|
850
|
+
`**Platform:** ${targetPlatform}`,
|
|
548
851
|
`**SDK Version:** ${sdkEntry.version}`,
|
|
549
852
|
`**API Level:** ${level}`,
|
|
853
|
+
servedVariant !== sampleName ? `**Variant:** ${servedVariant} (Kotlin)` : "",
|
|
550
854
|
`**Trial License:** \`${registry.trial_license}\``,
|
|
551
855
|
"",
|
|
552
856
|
deps,
|
|
@@ -556,8 +860,9 @@ end
|
|
|
556
860
|
content,
|
|
557
861
|
"```",
|
|
558
862
|
"",
|
|
559
|
-
`
|
|
560
|
-
|
|
863
|
+
`Full project files: get_sample_files product=dbr edition=mobile platform=${targetPlatform} sample_id=${servedVariant}`,
|
|
864
|
+
`Docs: ${sdkEntry.platforms[targetPlatform]?.docs?.[level]?.["user-guide"] || "N/A"}`
|
|
865
|
+
].filter(Boolean);
|
|
561
866
|
|
|
562
867
|
return { content: [{ type: "text", text: output.join("\n") }] };
|
|
563
868
|
}
|
|
@@ -681,7 +986,19 @@ end
|
|
|
681
986
|
|
|
682
987
|
return {
|
|
683
988
|
isError: true,
|
|
684
|
-
content: [{
|
|
989
|
+
content: [{
|
|
990
|
+
type: "text",
|
|
991
|
+
text: [
|
|
992
|
+
`Unsupported product/edition for quickstart: product="${normalizedProduct || product}", edition="${normalizedEdition || edition || "(inferred)"}".`,
|
|
993
|
+
"Supported combinations:",
|
|
994
|
+
"- dbr: web (js + react/angular/vue/next/...), mobile (android/ios/flutter/react-native/maui), server (python/nodejs/java/cpp/dotnet)",
|
|
995
|
+
"- dwt: web",
|
|
996
|
+
"- ddv: web",
|
|
997
|
+
"- mrz: web",
|
|
998
|
+
"- mds: web",
|
|
999
|
+
"Call get_index to see valid product/edition/platform combinations."
|
|
1000
|
+
].join("\n")
|
|
1001
|
+
}]
|
|
685
1002
|
};
|
|
686
1003
|
}
|
|
687
1004
|
);
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
buildUnknownPublicProductResponse,
|
|
4
|
+
isKnownPublicOffering,
|
|
5
|
+
DBR_ONLY_EDITIONS_NOTE,
|
|
6
|
+
WEB_ONLY_OMIT_NOTE
|
|
7
|
+
} from "../public-offerings.js";
|
|
3
8
|
import { buildUnsupportedPublicScopeResponse } from "./public-routing.js";
|
|
4
9
|
|
|
5
10
|
export function registerSampleTools({
|
|
@@ -34,8 +39,8 @@ export function registerSampleTools({
|
|
|
34
39
|
"",
|
|
35
40
|
"PARAMETERS:",
|
|
36
41
|
"- product: dbr, dwt, ddv, mrz, or mds. Omit to list across all public offerings.",
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
`- edition: core, mobile, web, or server. ${DBR_ONLY_EDITIONS_NOTE} Omit to list across all editions.`,
|
|
43
|
+
`- platform: only DBR spans multiple platforms (android, ios, js, python, cpp, java, dotnet, nodejs, react, vue, angular, flutter, react-native, maui, etc.). ${WEB_ONLY_OMIT_NOTE}`,
|
|
39
44
|
"- limit: 1-200 (default 50). Max number of results.",
|
|
40
45
|
"",
|
|
41
46
|
"RETURNS: A single text content item that starts with totals and plain URIs, then appends 'JSON:' followed by a JSON object with total count and sample entries. Each entry includes sample_id, uri (sample:// URI), product, edition, platform, version, title, and summary. Use sample_id or uri with get_sample_files to retrieve full project files.",
|
|
@@ -46,8 +51,8 @@ export function registerSampleTools({
|
|
|
46
51
|
].join("\n"),
|
|
47
52
|
inputSchema: {
|
|
48
53
|
product: z.string().optional().describe("Product: dbr, dwt, ddv, mrz, mds"),
|
|
49
|
-
edition: z.string().optional().describe(
|
|
50
|
-
platform: z.string().optional().describe(
|
|
54
|
+
edition: z.string().optional().describe(`Edition: core, mobile, web, server/desktop. ${DBR_ONLY_EDITIONS_NOTE}`),
|
|
55
|
+
platform: z.string().optional().describe(`Platform (DBR only spans multiple): android, ios, maui, react-native, flutter, js, python, cpp, java, dotnet, nodejs, angular, blazor, capacitor, electron, es6, native-ts, next, nuxt, pwa, react, requirejs, svelte, vue, webview, spm, core. ${WEB_ONLY_OMIT_NOTE}`),
|
|
51
56
|
limit: z.number().int().min(1).max(200).optional().describe("Max results (default 50)")
|
|
52
57
|
},
|
|
53
58
|
annotations: {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
buildUnknownPublicProductResponse,
|
|
4
|
+
isKnownPublicOffering,
|
|
5
|
+
DBR_ONLY_EDITIONS_NOTE,
|
|
6
|
+
WEB_ONLY_OMIT_NOTE
|
|
7
|
+
} from "../public-offerings.js";
|
|
3
8
|
|
|
4
9
|
export function registerVersionTools({
|
|
5
10
|
server,
|
|
@@ -64,8 +69,8 @@ export function registerVersionTools({
|
|
|
64
69
|
"",
|
|
65
70
|
"PARAMETERS:",
|
|
66
71
|
"- product (required): dbr, dwt, ddv, mrz, or mds.",
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
`- edition: core, mobile, web, or server. ${DBR_ONLY_EDITIONS_NOTE} Omit to see all editions for the product.`,
|
|
73
|
+
`- platform: only DBR spans multiple platforms (android, ios, js, python, cpp, java, dotnet, nodejs, etc.). ${WEB_ONLY_OMIT_NOTE} Helps narrow edition when ambiguous.`,
|
|
69
74
|
"- constraint: Version constraint like 'latest', '11.x', '10'. Only latest major version is served; legacy versions (e.g. DBR v9) return an error with migration guidance.",
|
|
70
75
|
"- feature: Optional feature hint for version policy checks.",
|
|
71
76
|
"",
|
|
@@ -77,8 +82,8 @@ export function registerVersionTools({
|
|
|
77
82
|
].join("\n"),
|
|
78
83
|
inputSchema: {
|
|
79
84
|
product: z.string().trim().min(1, "Product is required.").describe("Product: dbr, dwt, ddv, mrz, mds"),
|
|
80
|
-
edition: z.string().optional().describe(
|
|
81
|
-
platform: z.string().optional().describe(
|
|
85
|
+
edition: z.string().optional().describe(`Edition: core, mobile, web, server/desktop. ${DBR_ONLY_EDITIONS_NOTE}`),
|
|
86
|
+
platform: z.string().optional().describe(`Platform (DBR only spans multiple): android, ios, maui, react-native, flutter, js, python, cpp, java, dotnet, nodejs, angular, blazor, capacitor, electron, es6, native-ts, next, nuxt, pwa, react, requirejs, svelte, vue, webview, spm, core. ${WEB_ONLY_OMIT_NOTE}`),
|
|
82
87
|
constraint: z.string().optional().describe("Version constraint, e.g., latest, 11.x, 10"),
|
|
83
88
|
feature: z.string().optional().describe("Optional feature hint")
|
|
84
89
|
},
|