@dragon708/docmind-browser 1.2.0 → 1.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +55 -23
  2. package/dist/index.js +200 -115
  3. package/package.json +2 -2
package/dist/index.d.ts CHANGED
@@ -1,7 +1,16 @@
1
1
  import { DocMindAnalyzeOptions, AnalysisResult, FileKind, RuntimeDescriptor, DocMindPublicIntent, AnalysisAnalyzer, ProcessingPlanDescriptor, ExplainAnalysisPlanOptions, GetCapabilitiesOptions } from '@dragon708/docmind-shared';
2
2
  export { AnalysisAnalyzer, AnalysisResult, CapabilityDescriptor, DetectFileKindInput, DocMindPublicIntent, DocxAnalysisCoreResult, ExplainAnalysisPlanOptions, ExplainAnalysisPlanResult, FileKind, FileKindMetadata, GenericAnalysisResult, GetCapabilitiesOptions, GetCapabilitiesResult, ImageAnalysisCoreResult, PdfAnalysisCoreResult, TextAnalysisResult, detectFileKind } from '@dragon708/docmind-shared';
3
3
  import { OcrOptions } from '@dragon708/docmind-ocr';
4
+ import { AnalyzeDocxIncludeFlags, DocxToHtmlOptions } from '@dragon708/docmind-docx';
5
+ export { AnalyzeDocxIncludeFlags } from '@dragon708/docmind-docx';
4
6
 
7
+ /**
8
+ * Opciones DOCX para el facade browser (Mammoth + inclusiones v2 de `@dragon708/docmind-docx`; sin APIs Node-only).
9
+ */
10
+ interface BrowserAnalyzeDocxOptionsSlice {
11
+ readonly include?: AnalyzeDocxIncludeFlags;
12
+ readonly html?: DocxToHtmlOptions;
13
+ }
5
14
  /**
6
15
  * OCR behavior for browser intents that touch raster images.
7
16
  * - `off`: do not invoke Tesseract; text stays empty with an explanatory warning.
@@ -20,6 +29,8 @@ interface BrowserOcrOptions extends OcrOptions {
20
29
  interface BrowserAnalyzeOptions extends DocMindAnalyzeOptions {
21
30
  /** Image OCR only; no PDF in this runtime. See {@link BrowserOcrOptions.mode}. */
22
31
  readonly ocr?: BrowserOcrOptions;
32
+ /** Solo DOCX: ver {@link BrowserAnalyzeDocxOptionsSlice}. */
33
+ readonly docx?: BrowserAnalyzeDocxOptionsSlice;
23
34
  }
24
35
 
25
36
  /**
@@ -60,6 +71,43 @@ declare function convertToHtml(input: BrowserAnalyzeInput, options?: BrowserAnal
60
71
  */
61
72
  declare function runOcr(input: BrowserAnalyzeInput, options?: BrowserAnalyzeOptions): Promise<AnalysisResult>;
62
73
 
74
+ /** High-level features the user can ask DocMind for (per input kind and runtime). */
75
+ type PublicCapabilityId = "text" | "metadata" | "html" | "ocr" | "pages";
76
+ declare function docxIncludeRequested(flags?: AnalyzeDocxIncludeFlags): boolean;
77
+ /** DOCX `word/media` en runtime browser (JSZip; sin pipeline Node). */
78
+ interface DocxEmbeddedImageCapabilities {
79
+ readonly canExtractEmbeddedImages: true;
80
+ readonly documentsMayIncludeImagesRequiringWebConversion: true;
81
+ /** En browser no hay conversión EMF/WMF a PNG empaquetada; `convertDocxEmbeddedImageToWeb` devuelve bytes originales + avisos. */
82
+ readonly webFriendlyRasterConversionInBrowser: false;
83
+ readonly notes: readonly string[];
84
+ }
85
+ declare const DOCX_EMBEDDED_IMAGE_CAPABILITIES_BROWSER: DocxEmbeddedImageCapabilities;
86
+ interface DocxStructuralCapabilities {
87
+ readonly ooxmlExtractorsAvailable: true;
88
+ readonly activatedViaDocxInclude: true;
89
+ readonly features: readonly string[];
90
+ readonly notes: readonly string[];
91
+ }
92
+ declare const DOCX_STRUCTURE_CAPABILITIES_BROWSER: DocxStructuralCapabilities;
93
+ /** Whether a {@link PublicCapabilityId} applies to the detected file in this runtime. */
94
+ interface PublicCapabilitySupport {
95
+ readonly id: PublicCapabilityId;
96
+ readonly supported: boolean;
97
+ readonly warnings?: readonly string[];
98
+ }
99
+ /**
100
+ * Result of {@link getCapabilities}: detected kind, runtime id, per-feature support for this input, and optional global warnings.
101
+ */
102
+ interface GetCapabilitiesReport {
103
+ readonly kind: FileKind;
104
+ readonly runtime: RuntimeDescriptor;
105
+ readonly capabilities: readonly PublicCapabilitySupport[];
106
+ readonly docxEmbeddedImages?: DocxEmbeddedImageCapabilities;
107
+ readonly docxStructure?: DocxStructuralCapabilities;
108
+ readonly warnings?: readonly string[];
109
+ }
110
+
63
111
  /**
64
112
  * Whether DocMind will try a non-OCR text/HTML path (e.g. Mammoth, UTF-8, PDF text layer — when available).
65
113
  */
@@ -91,40 +139,24 @@ interface ExplainAnalysisPlanReport {
91
139
  readonly limitations: readonly string[];
92
140
  /** Ordered pipeline steps (planned/skipped/done metadata only). */
93
141
  readonly plan: ProcessingPlanDescriptor;
142
+ readonly docxEmbeddedImages?: DocxEmbeddedImageCapabilities;
143
+ readonly docxStructure?: DocxStructuralCapabilities;
94
144
  readonly warnings?: readonly string[];
95
145
  }
96
146
 
97
- /** High-level features the user can ask DocMind for (per input kind and runtime). */
98
- type PublicCapabilityId = "text" | "metadata" | "html" | "ocr" | "pages";
99
- /** Whether a {@link PublicCapabilityId} applies to the detected file in this runtime. */
100
- interface PublicCapabilitySupport {
101
- readonly id: PublicCapabilityId;
102
- readonly supported: boolean;
103
- readonly warnings?: readonly string[];
104
- }
105
- /**
106
- * Result of {@link getCapabilities}: detected kind, runtime id, per-feature support for this input, and optional global warnings.
107
- */
108
- interface GetCapabilitiesReport {
109
- readonly kind: FileKind;
110
- readonly runtime: RuntimeDescriptor;
111
- readonly capabilities: readonly PublicCapabilitySupport[];
112
- readonly warnings?: readonly string[];
113
- }
114
-
115
- /** Options for {@link explainAnalysisPlan}: shared fields plus optional `ocr` for accurate OCR-step preview. */
116
- type BrowserExplainAnalysisPlanOptions = ExplainAnalysisPlanOptions & Pick<BrowserAnalyzeOptions, "ocr">;
147
+ /** Options for {@link explainAnalysisPlan}: shared fields plus optional `ocr` / `docx` for accurate step preview. */
148
+ type BrowserExplainAnalysisPlanOptions = ExplainAnalysisPlanOptions & Pick<BrowserAnalyzeOptions, "ocr" | "docx">;
117
149
 
118
150
  /**
119
151
  * Epic 1 — **Capabilities:** detects kind from the same hints as `analyzeFile`, then lists which of
120
152
  * `text` | `metadata` | `html` | `ocr` | `pages` apply in the browser (PDF always unsupported).
121
- * No Mammoth/Tesseract/PDF parsing.
153
+ * No Mammoth/Tesseract/PDF parsing. For DOCX, {@link GetCapabilitiesReport.docxStructure} / `docxEmbeddedImages` describe v2 opt-in features.
122
154
  */
123
155
  declare function getCapabilities(input: BrowserAnalyzeInput, options?: GetCapabilitiesOptions): Promise<GetCapabilitiesReport>;
124
156
  /**
125
157
  * Epic 1 — **Plan preview:** structured explanation (analyzer, native extraction vs OCR, `limitations`, `plan.steps`)
126
- * for a {@link DocMindPublicIntent}. Optional `ocr` in options refines image steps. No heavy I/O.
158
+ * for a {@link DocMindPublicIntent}. Optional `ocr` refines image steps; optional `docx.include` adds planned OOXML parallel steps for DOCX. No heavy I/O.
127
159
  */
128
160
  declare function explainAnalysisPlan(input: BrowserAnalyzeInput, options?: BrowserExplainAnalysisPlanOptions): Promise<ExplainAnalysisPlanReport>;
129
161
 
130
- export { BROWSER_PDF_UNSUPPORTED_WARNING, type BrowserAnalyzeInput, type BrowserAnalyzeOptions, type BrowserExplainAnalysisPlanOptions, type BrowserOcrMode, type BrowserOcrOptions, type ExplainAnalysisPlanReport, type GetCapabilitiesReport, type NativeExtractionPlan, type OcrPlan, type PublicCapabilityId, type PublicCapabilitySupport, analyzeFile, convertToHtml, explainAnalysisPlan, extractMetadata, extractText, getCapabilities, runOcr };
162
+ export { BROWSER_PDF_UNSUPPORTED_WARNING, type BrowserAnalyzeDocxOptionsSlice, type BrowserAnalyzeInput, type BrowserAnalyzeOptions, type BrowserExplainAnalysisPlanOptions, type BrowserOcrMode, type BrowserOcrOptions, DOCX_EMBEDDED_IMAGE_CAPABILITIES_BROWSER, DOCX_STRUCTURE_CAPABILITIES_BROWSER, type DocxEmbeddedImageCapabilities, type DocxStructuralCapabilities, type ExplainAnalysisPlanReport, type GetCapabilitiesReport, type NativeExtractionPlan, type OcrPlan, type PublicCapabilityId, type PublicCapabilitySupport, analyzeFile, convertToHtml, docxIncludeRequested, explainAnalysisPlan, extractMetadata, extractText, getCapabilities, runOcr };
package/dist/index.js CHANGED
@@ -22,7 +22,41 @@ function prepareBrowserAnalyzeInput(input) {
22
22
  assertValidAnalyzeFileInput(input);
23
23
  return input;
24
24
  }
25
- async function analyzeDocxForBrowser(input, signal) {
25
+
26
+ // src/docxBrowserMapper.ts
27
+ function analyzeDocxOptionsFromBrowser(options) {
28
+ const sig = options?.signal;
29
+ const dx = options?.docx;
30
+ if (!dx?.include && !dx?.html && !sig) return void 0;
31
+ const out = { ...dx?.html ?? {} };
32
+ if (dx?.include) out.include = dx.include;
33
+ if (sig) out.signal = sig;
34
+ return out;
35
+ }
36
+ function docxPackageResultToAnalysisResult(r) {
37
+ const base = {
38
+ fileKind: "docx",
39
+ analyzer: "docx",
40
+ status: "ok",
41
+ kind: "docx",
42
+ text: r.text,
43
+ html: r.html,
44
+ warnings: [...r.warnings]
45
+ };
46
+ const v2 = {
47
+ ...r.structure !== void 0 ? { structure: r.structure } : {},
48
+ ...r.headings !== void 0 ? { headings: r.headings } : {},
49
+ ...r.tables !== void 0 ? { tables: r.tables } : {},
50
+ ...r.blocks !== void 0 ? { blocks: r.blocks } : {},
51
+ ...r.pagesApprox !== void 0 ? { pagesApprox: r.pagesApprox } : {},
52
+ ...r.embeddedImages !== void 0 ? { embeddedImages: r.embeddedImages } : {}
53
+ };
54
+ return { ...base, ...v2 };
55
+ }
56
+
57
+ // src/analyzers/docx.ts
58
+ async function analyzeDocxForBrowser(input, options) {
59
+ const signal = options?.signal;
26
60
  if (signal?.aborted) {
27
61
  const err = new Error("The operation was aborted");
28
62
  err.name = "AbortError";
@@ -40,16 +74,9 @@ async function analyzeDocxForBrowser(input, signal) {
40
74
  warnings: ["No document bytes were provided for analysis."]
41
75
  };
42
76
  }
43
- const r = await analyzeDocx(data);
44
- return {
45
- fileKind: "docx",
46
- analyzer: "docx",
47
- status: "ok",
48
- kind: "docx",
49
- text: r.text,
50
- html: r.html,
51
- warnings: [...r.warnings]
52
- };
77
+ const docxOpts = analyzeDocxOptionsFromBrowser(options);
78
+ const r = docxOpts !== void 0 ? await analyzeDocx(data, docxOpts) : await analyzeDocx(data);
79
+ return docxPackageResultToAnalysisResult(r);
53
80
  }
54
81
  var OCR_OFF_WARNING = 'OCR mode is "off"; no recognition was run. Use mode "auto" or "force" to extract text from images.';
55
82
  function resolveOcrMode(options) {
@@ -120,7 +147,7 @@ async function analyzeFile(input, options) {
120
147
  case "pdf":
121
148
  return notImplementedResult("pdf", "pdf", [BROWSER_PDF_UNSUPPORTED_WARNING]);
122
149
  case "docx":
123
- return analyzeDocxForBrowser(bytesInput, options?.signal);
150
+ return analyzeDocxForBrowser(bytesInput, options);
124
151
  case "image":
125
152
  return analyzeImageForBrowser(bytesInput, options);
126
153
  case "text":
@@ -129,7 +156,7 @@ async function analyzeFile(input, options) {
129
156
  return notImplementedResult(fileKind, "none", [UNKNOWN_FORMAT_WARNING]);
130
157
  }
131
158
  }
132
- var DOCX_METADATA_STUB = "Structured document metadata for DOCX is not exposed as a separate API; use extractText or analyzeFile.";
159
+ var DOCX_METADATA_STUB = "Structured document metadata for DOCX is not returned by extractMetadata; use analyzeFile, extractText, or convertToHtml with options.docx.include for OOXML structure, headings, tables, blocks, approximate pages, and embedded images.";
133
160
  var IMAGE_METADATA_NOTE = "Raster images have no document metadata bundle in this API.";
134
161
  function escapeHtmlMinimal(s) {
135
162
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
@@ -243,19 +270,16 @@ async function runOcr(input, options) {
243
270
  warnings: ["No document bytes were provided for analysis."]
244
271
  };
245
272
  }
246
- const r = await analyzeDocx(data);
247
- return {
248
- fileKind: "docx",
249
- analyzer: "docx",
250
- status: "ok",
251
- kind: "docx",
252
- text: r.text,
253
- html: r.html,
273
+ const opt = analyzeDocxOptionsFromBrowser(options);
274
+ const raw = opt !== void 0 ? await analyzeDocx(data, opt) : await analyzeDocx(data);
275
+ const withNote = {
276
+ ...raw,
254
277
  warnings: [
255
- ...r.warnings,
278
+ ...raw.warnings,
256
279
  "OCR does not apply to DOCX; returned structured text/HTML extract."
257
280
  ]
258
281
  };
282
+ return docxPackageResultToAnalysisResult(withNote);
259
283
  }
260
284
  case "text":
261
285
  return analyzeText(bytesInput, { signal });
@@ -264,11 +288,134 @@ async function runOcr(input, options) {
264
288
  }
265
289
  }
266
290
 
291
+ // src/capabilityReport.ts
292
+ function docxIncludeRequested(flags) {
293
+ if (!flags) return false;
294
+ return !!(flags.structure || flags.headings || flags.tables || flags.blocks || flags.pagesApprox || flags.embeddedImages);
295
+ }
296
+ var DOCX_EMBEDDED_IMAGE_CAPABILITIES_BROWSER = {
297
+ canExtractEmbeddedImages: true,
298
+ documentsMayIncludeImagesRequiringWebConversion: true,
299
+ webFriendlyRasterConversionInBrowser: false,
300
+ notes: [
301
+ "`extractImagesFromDocx` from `@dragon708/docmind-docx` runs in-browser on the same ZIP bytes as Mammoth.",
302
+ "PNG, JPEG, GIF, WebP, SVG, TIFF, BMP, ICO are browser-embeddable; EMF/WMF need an external converter or server-side Node tooling."
303
+ ]
304
+ };
305
+ var DOCX_STRUCTURE_CAPABILITIES_BROWSER = {
306
+ ooxmlExtractorsAvailable: true,
307
+ activatedViaDocxInclude: true,
308
+ features: [
309
+ "OOXML structure (body blocks)",
310
+ "headings",
311
+ "tables",
312
+ "semantic blocks",
313
+ "approximate pages (OOXML page-break hints)",
314
+ "embedded images (word/media; mode web/both still browser-safe but EMF/WMF stay non-raster without a converter)"
315
+ ],
316
+ notes: [
317
+ "Use options.docx.include on analyzeFile, extractText, convertToHtml, or runOcr to merge Mammoth with selected `@dragon708/docmind-docx` extractors.",
318
+ "extractMetadata for DOCX stays a stub in the browser facade."
319
+ ]
320
+ };
321
+ var DOCX_META = "Structured document metadata is not exposed separately in the browser runtime; extractMetadata returns a stub for DOCX.";
322
+ var IMAGE_META = "Raster images have no document metadata bundle; extractMetadata returns a stub.";
323
+ var IMAGE_HTML = "No layout HTML for raster images; use extractText or runOcr for text.";
324
+ var TEXT_META_NOTE = "Plain text has no structured document metadata; extractMetadata still returns decoded content.";
325
+ var OCR_OFF_NOTE = 'Image OCR may be skipped when `ocr.mode` is "off" in analyze options.';
326
+ var UNKNOWN_KIND = "Could not determine file kind from name, MIME, or bytes; all features are reported as unsupported until the kind is known.";
327
+ function slot(id, supported, warnings) {
328
+ return warnings?.length ? { id, supported, warnings } : { id, supported };
329
+ }
330
+ function buildBrowserCapabilityReport(kind) {
331
+ const runtime = { id: "browser" };
332
+ const pdf = BROWSER_PDF_UNSUPPORTED_WARNING;
333
+ let capabilities;
334
+ const topWarnings = [];
335
+ switch (kind) {
336
+ case "pdf":
337
+ capabilities = [
338
+ slot("text", false, [pdf]),
339
+ slot("metadata", false, [pdf]),
340
+ slot("html", false, [pdf]),
341
+ slot("ocr", false, [pdf]),
342
+ slot("pages", false, [pdf])
343
+ ];
344
+ break;
345
+ case "docx":
346
+ capabilities = [
347
+ slot("text", true, [
348
+ "Mammoth plain text in analyzeFile; extractText clears html. Optional OOXML fields merge when options.docx.include is set."
349
+ ]),
350
+ slot("metadata", false, [
351
+ `${DOCX_META} Use analyzeFile-style routes with options.docx.include for OOXML structure, headings, tables, blocks, approximate pages, and embedded images.`
352
+ ]),
353
+ slot("html", true, [
354
+ "Mammoth HTML in-browser; docxImagesAsDataUri for web-safe images; EMF/WMF placeholders in HTML unless you handle media separately."
355
+ ]),
356
+ slot("ocr", false, ["OCR does not apply to DOCX in DocMind."]),
357
+ slot("pages", false, [
358
+ "No PDF page count; approximate DOCX pages via options.docx.include.pagesApprox (heuristic, not print layout)."
359
+ ])
360
+ ];
361
+ break;
362
+ case "image":
363
+ capabilities = [
364
+ slot("text", true, ["Text is obtained via OCR when enabled."]),
365
+ slot("metadata", false, [IMAGE_META]),
366
+ slot("html", false, [IMAGE_HTML]),
367
+ slot("ocr", true, [OCR_OFF_NOTE]),
368
+ slot("pages", false)
369
+ ];
370
+ break;
371
+ case "text":
372
+ capabilities = [
373
+ slot("text", true),
374
+ slot("metadata", true, [TEXT_META_NOTE]),
375
+ slot("html", true),
376
+ slot("ocr", false, ["OCR does not apply to plain text files."]),
377
+ slot("pages", false)
378
+ ];
379
+ break;
380
+ default:
381
+ topWarnings.push(UNKNOWN_KIND);
382
+ capabilities = [
383
+ slot("text", false),
384
+ slot("metadata", false),
385
+ slot("html", false),
386
+ slot("ocr", false),
387
+ slot("pages", false)
388
+ ];
389
+ }
390
+ return {
391
+ kind,
392
+ runtime,
393
+ capabilities,
394
+ ...kind === "docx" ? {
395
+ docxEmbeddedImages: DOCX_EMBEDDED_IMAGE_CAPABILITIES_BROWSER,
396
+ docxStructure: DOCX_STRUCTURE_CAPABILITIES_BROWSER
397
+ } : {},
398
+ warnings: topWarnings.length > 0 ? topWarnings : void 0
399
+ };
400
+ }
401
+
267
402
  // src/analysisPlanReport.ts
268
403
  function lim(...items) {
269
404
  return items.filter(Boolean);
270
405
  }
271
- function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
406
+ var DOCX_MAMMOTH_PLUS_OPTIONAL_BROWSER = "Mammoth (`analyzeDocx`) extracts text and HTML from OOXML in-browser; optional parallel OOXML/ZIP extractors run when options.docx.include is set.";
407
+ var DOCX_ZIP_NOTE_BROWSER = "Embedded files under word/media are available via @dragon708/docmind-docx when options.docx.include requests embeddedImages (or call extractImagesFromDocx on the same bytes).";
408
+ function finalizeBrowserDocxExplainReport(report) {
409
+ if (report.kind !== "docx") return report;
410
+ const limitations = report.limitations.includes(DOCX_ZIP_NOTE_BROWSER) ? report.limitations : [...report.limitations, DOCX_ZIP_NOTE_BROWSER];
411
+ return {
412
+ ...report,
413
+ docxEmbeddedImages: DOCX_EMBEDDED_IMAGE_CAPABILITIES_BROWSER,
414
+ docxStructure: DOCX_STRUCTURE_CAPABILITIES_BROWSER,
415
+ limitations
416
+ };
417
+ }
418
+ function buildBrowserExplainReport(kind, intent, ocrMode, plan, docxInclude) {
272
419
  const runtime = { id: "browser" };
273
420
  const imageOcrActive = ocrMode !== "off";
274
421
  let primaryAnalyzer = kind === "pdf" ? "pdf" : kind === "docx" ? "docx" : kind === "image" ? "image" : kind === "text" ? "text" : "none";
@@ -286,7 +433,7 @@ function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
286
433
  mayUse: false,
287
434
  description: "PDF OCR is not available in the browser."
288
435
  };
289
- return {
436
+ return finalizeBrowserDocxExplainReport({
290
437
  kind,
291
438
  detectedKind: kind,
292
439
  runtime,
@@ -297,7 +444,7 @@ function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
297
444
  limitations,
298
445
  plan,
299
446
  warnings: [BROWSER_PDF_UNSUPPORTED_WARNING]
300
- };
447
+ });
301
448
  }
302
449
  if (kind === "unknown") {
303
450
  limitations = lim(
@@ -305,7 +452,7 @@ function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
305
452
  );
306
453
  nativeExtraction = { willAttempt: false, description: "No analyzer selected without a known file kind." };
307
454
  ocr2 = { mayUse: false, description: "OCR is not used for unknown kinds." };
308
- return {
455
+ return finalizeBrowserDocxExplainReport({
309
456
  kind,
310
457
  detectedKind: kind,
311
458
  runtime,
@@ -315,7 +462,7 @@ function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
315
462
  ocr: ocr2,
316
463
  limitations,
317
464
  plan
318
- };
465
+ });
319
466
  }
320
467
  switch (intent) {
321
468
  case "analyzeFile":
@@ -323,7 +470,7 @@ function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
323
470
  if (kind === "docx") {
324
471
  nativeExtraction = {
325
472
  willAttempt: true,
326
- description: "Mammoth reads OOXML for text" + (intent === "extractText" ? " (HTML omitted in extractText)." : " and HTML.")
473
+ description: docxIncludeRequested(docxInclude) ? "Mammoth plus parallel OOXML extractors (per options.docx.include)." + (intent === "extractText" ? " HTML cleared in extractText." : "") : DOCX_MAMMOTH_PLUS_OPTIONAL_BROWSER + (intent === "extractText" ? " HTML omitted in extractText." : "")
327
474
  };
328
475
  ocr2 = { mayUse: false, description: "DOCX does not use OCR in DocMind." };
329
476
  } else if (kind === "image") {
@@ -352,7 +499,7 @@ function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
352
499
  };
353
500
  ocr2 = { mayUse: false, description: "OCR is not invoked for this metadata path." };
354
501
  limitations = lim(
355
- kind === "docx" ? "Structured DOCX metadata is not exposed separately in the browser." : "Raster images have no document metadata bundle in this API."
502
+ kind === "docx" ? "Structured DOCX metadata is not exposed separately in the browser; use analyzeFile / extractText / convertToHtml with options.docx.include for OOXML fields." : "Raster images have no document metadata bundle in this API."
356
503
  );
357
504
  } else {
358
505
  nativeExtraction = {
@@ -367,7 +514,7 @@ function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
367
514
  if (kind === "docx") {
368
515
  nativeExtraction = {
369
516
  willAttempt: true,
370
- description: "Mammoth produces HTML; images are not passed through analyzeFile for this intent."
517
+ description: docxIncludeRequested(docxInclude) ? "Mammoth HTML via analyzeFile plus optional OOXML extractors." : "Mammoth HTML via analyzeFile; optional OOXML v2 when options.docx.include is set."
371
518
  };
372
519
  ocr2 = { mayUse: false, description: "DOCX path does not use OCR." };
373
520
  } else if (kind === "text") {
@@ -401,7 +548,7 @@ function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
401
548
  } else if (kind === "docx") {
402
549
  nativeExtraction = {
403
550
  willAttempt: true,
404
- description: "Mammoth returns structured text/HTML (OCR does not apply to DOCX)."
551
+ description: docxIncludeRequested(docxInclude) ? "Mammoth text/HTML plus optional OOXML extractors; not OCR." : "Mammoth text/HTML; optional OOXML v2 via options.docx.include; not OCR."
405
552
  };
406
553
  ocr2 = { mayUse: false, description: "DOCX is not OCR'd." };
407
554
  limitations = lim("Returned content is structured extract, not OCR output.");
@@ -417,7 +564,7 @@ function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
417
564
  nativeExtraction = { willAttempt: false, description: "Intent not specialized in this runtime." };
418
565
  ocr2 = { mayUse: false, description: "See plan steps." };
419
566
  }
420
- return {
567
+ return finalizeBrowserDocxExplainReport({
421
568
  kind,
422
569
  detectedKind: kind,
423
570
  runtime,
@@ -427,84 +574,14 @@ function buildBrowserExplainReport(kind, intent, ocrMode, plan) {
427
574
  ocr: ocr2,
428
575
  limitations,
429
576
  plan
430
- };
431
- }
432
-
433
- // src/capabilityReport.ts
434
- var DOCX_META = "Structured document metadata is not exposed separately in the browser runtime; extractMetadata returns a stub for DOCX.";
435
- var IMAGE_META = "Raster images have no document metadata bundle; extractMetadata returns a stub.";
436
- var IMAGE_HTML = "No layout HTML for raster images; use extractText or runOcr for text.";
437
- var TEXT_META_NOTE = "Plain text has no structured document metadata; extractMetadata still returns decoded content.";
438
- var OCR_OFF_NOTE = 'Image OCR may be skipped when `ocr.mode` is "off" in analyze options.';
439
- var UNKNOWN_KIND = "Could not determine file kind from name, MIME, or bytes; all features are reported as unsupported until the kind is known.";
440
- function slot(id, supported, warnings) {
441
- return warnings?.length ? { id, supported, warnings } : { id, supported };
442
- }
443
- function buildBrowserCapabilityReport(kind) {
444
- const runtime = { id: "browser" };
445
- const pdf = BROWSER_PDF_UNSUPPORTED_WARNING;
446
- let capabilities;
447
- const topWarnings = [];
448
- switch (kind) {
449
- case "pdf":
450
- capabilities = [
451
- slot("text", false, [pdf]),
452
- slot("metadata", false, [pdf]),
453
- slot("html", false, [pdf]),
454
- slot("ocr", false, [pdf]),
455
- slot("pages", false, [pdf])
456
- ];
457
- break;
458
- case "docx":
459
- capabilities = [
460
- slot("text", true),
461
- slot("metadata", false, [DOCX_META]),
462
- slot("html", true),
463
- slot("ocr", false, ["OCR does not apply to DOCX in DocMind."]),
464
- slot("pages", false)
465
- ];
466
- break;
467
- case "image":
468
- capabilities = [
469
- slot("text", true, ["Text is obtained via OCR when enabled."]),
470
- slot("metadata", false, [IMAGE_META]),
471
- slot("html", false, [IMAGE_HTML]),
472
- slot("ocr", true, [OCR_OFF_NOTE]),
473
- slot("pages", false)
474
- ];
475
- break;
476
- case "text":
477
- capabilities = [
478
- slot("text", true),
479
- slot("metadata", true, [TEXT_META_NOTE]),
480
- slot("html", true),
481
- slot("ocr", false, ["OCR does not apply to plain text files."]),
482
- slot("pages", false)
483
- ];
484
- break;
485
- default:
486
- topWarnings.push(UNKNOWN_KIND);
487
- capabilities = [
488
- slot("text", false),
489
- slot("metadata", false),
490
- slot("html", false),
491
- slot("ocr", false),
492
- slot("pages", false)
493
- ];
494
- }
495
- return {
496
- kind,
497
- runtime,
498
- capabilities,
499
- warnings: topWarnings.length > 0 ? topWarnings : void 0
500
- };
577
+ });
501
578
  }
502
579
 
503
580
  // src/introspection.ts
504
581
  function resolveOcrMode2(ocr2) {
505
582
  return ocr2?.mode ?? "auto";
506
583
  }
507
- function planForAnalyzeFile(kind, ocrMode) {
584
+ function planForAnalyzeFile(kind, ocrMode, docxInclude) {
508
585
  switch (kind) {
509
586
  case "pdf":
510
587
  return {
@@ -514,14 +591,17 @@ function planForAnalyzeFile(kind, ocrMode) {
514
591
  { id: "pdf_pipeline", status: "skipped" }
515
592
  ]
516
593
  };
517
- case "docx":
594
+ case "docx": {
595
+ const parallel = docxIncludeRequested(docxInclude);
518
596
  return {
519
597
  intent: "analyzeFile",
520
598
  steps: [
521
599
  { id: "detect_kind", status: "done" },
522
- { id: "docx_mammoth", status: "planned" }
600
+ { id: "docx_mammoth", status: "planned" },
601
+ ...parallel ? [{ id: "docx_ooxml_parallel", status: "planned" }] : []
523
602
  ]
524
603
  };
604
+ }
525
605
  case "image":
526
606
  return {
527
607
  intent: "analyzeFile",
@@ -548,11 +628,11 @@ function planForAnalyzeFile(kind, ocrMode) {
548
628
  };
549
629
  }
550
630
  }
551
- function planForIntent(intentOpt, kind, ocrMode) {
631
+ function planForIntent(intentOpt, kind, ocrMode, docxInclude) {
552
632
  const intent = intentOpt ?? "analyzeFile";
553
- if (intent === "analyzeFile") return planForAnalyzeFile(kind, ocrMode);
633
+ if (intent === "analyzeFile") return planForAnalyzeFile(kind, ocrMode, docxInclude);
554
634
  if (intent === "extractText") {
555
- const base = planForAnalyzeFile(kind, ocrMode);
635
+ const base = planForAnalyzeFile(kind, ocrMode, docxInclude);
556
636
  return { ...base, intent: "extractText" };
557
637
  }
558
638
  if (intent === "extractMetadata") {
@@ -575,11 +655,13 @@ function planForIntent(intentOpt, kind, ocrMode) {
575
655
  }
576
656
  if (intent === "convertToHtml") {
577
657
  if (kind === "docx") {
658
+ const parallel = docxIncludeRequested(docxInclude);
578
659
  return {
579
660
  intent: "convertToHtml",
580
661
  steps: [
581
662
  { id: "detect_kind", status: "done" },
582
- { id: "docx_mammoth_html", status: "planned" }
663
+ { id: "docx_mammoth_html", status: "planned" },
664
+ ...parallel ? [{ id: "docx_ooxml_parallel", status: "planned" }] : []
583
665
  ]
584
666
  };
585
667
  }
@@ -612,11 +694,13 @@ function planForIntent(intentOpt, kind, ocrMode) {
612
694
  };
613
695
  }
614
696
  if (kind === "docx") {
697
+ const parallel = docxIncludeRequested(docxInclude);
615
698
  return {
616
699
  intent: "runOcr",
617
700
  steps: [
618
701
  { id: "detect_kind", status: "done" },
619
- { id: "docx_structured_extract", status: "planned" }
702
+ { id: "docx_mammoth", status: "planned" },
703
+ ...parallel ? [{ id: "docx_ooxml_parallel", status: "planned" }] : []
620
704
  ]
621
705
  };
622
706
  }
@@ -628,7 +712,7 @@ function planForIntent(intentOpt, kind, ocrMode) {
628
712
  ]
629
713
  };
630
714
  }
631
- return planForAnalyzeFile(kind, ocrMode);
715
+ return planForAnalyzeFile(kind, ocrMode, docxInclude);
632
716
  }
633
717
  async function getCapabilities(input, options) {
634
718
  throwIfAborted(options?.signal);
@@ -642,10 +726,11 @@ async function explainAnalysisPlan(input, options) {
642
726
  const kind = detectFileKind(input);
643
727
  const intent = options?.intent ?? "analyzeFile";
644
728
  const ocrMode = resolveOcrMode2(options?.ocr);
645
- const plan = planForIntent(intent, kind, ocrMode);
646
- return buildBrowserExplainReport(kind, intent, ocrMode, plan);
729
+ const docxInc = options?.docx?.include;
730
+ const plan = planForIntent(intent, kind, ocrMode, docxInc);
731
+ return buildBrowserExplainReport(kind, intent, ocrMode, plan, docxInc);
647
732
  }
648
733
 
649
- export { BROWSER_PDF_UNSUPPORTED_WARNING, analyzeFile, convertToHtml, explainAnalysisPlan, extractMetadata, extractText, getCapabilities, runOcr };
734
+ export { BROWSER_PDF_UNSUPPORTED_WARNING, DOCX_EMBEDDED_IMAGE_CAPABILITIES_BROWSER, DOCX_STRUCTURE_CAPABILITIES_BROWSER, analyzeFile, convertToHtml, docxIncludeRequested, explainAnalysisPlan, extractMetadata, extractText, getCapabilities, runOcr };
650
735
  //# sourceMappingURL=index.js.map
651
736
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dragon708/docmind-browser",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Official DocMind browser facade: analyzeFile and intent APIs (DOCX, image OCR, text). PDF and fs paths use @dragon708/docmind-node.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -33,7 +33,7 @@
33
33
  ],
34
34
  "license": "MIT",
35
35
  "dependencies": {
36
- "@dragon708/docmind-docx": "^1.0.0",
36
+ "@dragon708/docmind-docx": "^1.7.0",
37
37
  "@dragon708/docmind-ocr": "^1.0.0",
38
38
  "@dragon708/docmind-shared": "^1.1.0"
39
39
  },