@dragon708/docmind-browser 1.1.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.
package/dist/index.d.ts CHANGED
@@ -1,43 +1,162 @@
1
- import { AnalysisResult } from '@dragon708/docmind-shared';
2
- export { AnalysisAnalyzer, AnalysisResult, DetectFileKindInput, DocxAnalysisCoreResult, FileKind, FileKindMetadata, GenericAnalysisResult, ImageAnalysisCoreResult, PdfAnalysisCoreResult, TextAnalysisResult, detectFileKind } from '@dragon708/docmind-shared';
1
+ import { DocMindAnalyzeOptions, AnalysisResult, FileKind, RuntimeDescriptor, DocMindPublicIntent, AnalysisAnalyzer, ProcessingPlanDescriptor, ExplainAnalysisPlanOptions, GetCapabilitiesOptions } from '@dragon708/docmind-shared';
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
 
5
- /** Options for {@link analyzeFile} in the browser entry (no PDF pipeline). */
6
- interface BrowserAnalyzeOptions {
7
- readonly signal?: AbortSignal;
8
- readonly ocr?: OcrOptions;
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
+ }
14
+ /**
15
+ * OCR behavior for browser intents that touch raster images.
16
+ * - `off`: do not invoke Tesseract; text stays empty with an explanatory warning.
17
+ * - `auto` (default): run OCR when the input is classified as an image.
18
+ * - `force`: same as `auto` in the browser runtime (no PDF-style text layer to compare); reserved for parity with Node.
19
+ */
20
+ type BrowserOcrMode = "off" | "auto" | "force";
21
+ /** Browser OCR options: Tesseract knobs from `@dragon708/docmind-ocr` plus optional {@link BrowserOcrMode}. */
22
+ interface BrowserOcrOptions extends OcrOptions {
23
+ readonly mode?: BrowserOcrMode;
24
+ }
25
+ /**
26
+ * Options for public browser methods (`analyzeFile`, intent APIs).
27
+ * There is no PDF pipeline in the browser; {@link BrowserOcrOptions.mode} applies to images only.
28
+ */
29
+ interface BrowserAnalyzeOptions extends DocMindAnalyzeOptions {
30
+ /** Image OCR only; no PDF in this runtime. See {@link BrowserOcrOptions.mode}. */
31
+ readonly ocr?: BrowserOcrOptions;
32
+ /** Solo DOCX: ver {@link BrowserAnalyzeDocxOptionsSlice}. */
33
+ readonly docx?: BrowserAnalyzeDocxOptionsSlice;
9
34
  }
10
35
 
11
- /** PDF is not processed in the browser; use `@dragon708/docmind-node` on the server. */
12
- declare const BROWSER_PDF_UNSUPPORTED_WARNING = "PDF text extraction is not available in the browser runtime; use @dragon708/docmind-node on the server.";
13
36
  /**
14
37
  * Inputs supported by the browser entry (DOM types only — no `fs`, no Node `Buffer` in the public surface).
15
38
  */
16
39
  type BrowserAnalyzeInput = File | Blob | ArrayBuffer;
40
+
17
41
  /**
18
- * Browser-only router: DOCX, images (OCR), and text. PDF yields `not_implemented` with a clear warning.
42
+ * Browser `analyzeFile` router. Package-level scope and limitations are documented on the package entry (`index.ts`).
43
+ */
44
+
45
+ /** PDF is not processed in the browser; use `@dragon708/docmind-node` on the server. */
46
+ declare const BROWSER_PDF_UNSUPPORTED_WARNING = "PDF text extraction is not available in the browser runtime; use @dragon708/docmind-node on the server.";
47
+ /**
48
+ * Full-document router: DOCX (text + HTML), images (OCR subject to {@link BrowserOcrOptions.mode}),
49
+ * plain text (UTF-8 decode). PDF yields `not_implemented` with {@link BROWSER_PDF_UNSUPPORTED_WARNING}.
19
50
  */
20
51
  declare function analyzeFile(input: BrowserAnalyzeInput, options?: BrowserAnalyzeOptions): Promise<AnalysisResult>;
21
52
 
22
53
  /**
23
- * Text only: DOCX `extractTextFromDocx`; imagen `ocr`; texto `analyzeText`.
24
- * PDF no está soportado en el navegador (mismo aviso que `analyzeFile`).
54
+ * Full text extraction using the same document pipeline as {@link analyzeFile} (not ad-hoc DOCX/OCR calls).
55
+ * Plain-text inputs still decode via the shared text analyzer inside `analyzeFile`.
25
56
  */
26
57
  declare function extractText(input: BrowserAnalyzeInput, options?: BrowserAnalyzeOptions): Promise<AnalysisResult>;
27
58
  /**
28
- * Metadatos: en el navegador no hay pipeline PDF ni metadatos DOCX dedicados;
29
- * DOCX/imagen con avisos; texto `analyzeText`.
59
+ * Metadata-oriented view. Does not run heavy extractors for DOCX/images (stubs only).
60
+ * Plain-text files use the same `analyzeFile` path as {@link extractText} for consistency.
30
61
  */
31
62
  declare function extractMetadata(input: BrowserAnalyzeInput, options?: BrowserAnalyzeOptions): Promise<AnalysisResult>;
32
63
  /**
33
- * HTML: DOCX `extractTextFromDocx` + `convertDocxToHtml`; texto `<pre>`;
34
- * PDF/imagen no aplican en browser como HTML rico.
64
+ * HTML-oriented view. Uses {@link analyzeFile} for DOCX and plain text only so raster images never trigger OCR.
65
+ * PDF and unknown kinds follow the same stubs as other intents.
35
66
  */
36
67
  declare function convertToHtml(input: BrowserAnalyzeInput, options?: BrowserAnalyzeOptions): Promise<AnalysisResult>;
37
68
  /**
38
- * OCR: imagen `ocr`; DOCX `analyzeDocx` con aviso (sin OCR); texto → `analyzeText`.
39
- * PDF no soportado en browser.
69
+ * OCR-focused intent. Honors {@link BrowserAnalyzeOptions.ocr} **mode** (`off` | `auto` | `force`) for images.
70
+ * DOCX returns structured extract with a notice (no OCR). Text decodes as UTF-8 (no OCR).
40
71
  */
41
72
  declare function runOcr(input: BrowserAnalyzeInput, options?: BrowserAnalyzeOptions): Promise<AnalysisResult>;
42
73
 
43
- export { BROWSER_PDF_UNSUPPORTED_WARNING, type BrowserAnalyzeInput, type BrowserAnalyzeOptions, analyzeFile, convertToHtml, extractMetadata, extractText, runOcr };
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
+
111
+ /**
112
+ * Whether DocMind will try a non-OCR text/HTML path (e.g. Mammoth, UTF-8, PDF text layer — when available).
113
+ */
114
+ interface NativeExtractionPlan {
115
+ readonly willAttempt: boolean;
116
+ readonly description: string;
117
+ }
118
+ /** Whether raster/PDF OCR could run for this intent + kind (subject to options). */
119
+ interface OcrPlan {
120
+ readonly mayUse: boolean;
121
+ readonly description: string;
122
+ }
123
+ /**
124
+ * Structured explanation of what DocMind would do for a public intent (no heavy I/O).
125
+ * Suitable for playgrounds and debug UIs.
126
+ */
127
+ interface ExplainAnalysisPlanReport {
128
+ /** Detected {@link FileKind} from name/MIME/sniff hints. */
129
+ readonly kind: FileKind;
130
+ /** Same as {@link kind}; kept for symmetry with older `ExplainAnalysisPlanResult` consumers. */
131
+ readonly detectedKind: FileKind;
132
+ readonly runtime: RuntimeDescriptor;
133
+ readonly intent: DocMindPublicIntent | (string & {});
134
+ /** Router target analyzer for this kind (`none` when unknown or PDF in browser). */
135
+ readonly primaryAnalyzer: AnalysisAnalyzer;
136
+ readonly nativeExtraction: NativeExtractionPlan;
137
+ readonly ocr: OcrPlan;
138
+ /** User-facing caveats (PDF unsupported, unknown kind, OCR off, etc.). */
139
+ readonly limitations: readonly string[];
140
+ /** Ordered pipeline steps (planned/skipped/done metadata only). */
141
+ readonly plan: ProcessingPlanDescriptor;
142
+ readonly docxEmbeddedImages?: DocxEmbeddedImageCapabilities;
143
+ readonly docxStructure?: DocxStructuralCapabilities;
144
+ readonly warnings?: readonly string[];
145
+ }
146
+
147
+ /** Options for {@link explainAnalysisPlan}: shared fields plus optional `ocr` / `docx` for accurate step preview. */
148
+ type BrowserExplainAnalysisPlanOptions = ExplainAnalysisPlanOptions & Pick<BrowserAnalyzeOptions, "ocr" | "docx">;
149
+
150
+ /**
151
+ * Epic 1 — **Capabilities:** detects kind from the same hints as `analyzeFile`, then lists which of
152
+ * `text` | `metadata` | `html` | `ocr` | `pages` apply in the browser (PDF always unsupported).
153
+ * No Mammoth/Tesseract/PDF parsing. For DOCX, {@link GetCapabilitiesReport.docxStructure} / `docxEmbeddedImages` describe v2 opt-in features.
154
+ */
155
+ declare function getCapabilities(input: BrowserAnalyzeInput, options?: GetCapabilitiesOptions): Promise<GetCapabilitiesReport>;
156
+ /**
157
+ * Epic 1 — **Plan preview:** structured explanation (analyzer, native extraction vs OCR, `limitations`, `plan.steps`)
158
+ * for a {@link DocMindPublicIntent}. Optional `ocr` refines image steps; optional `docx.include` adds planned OOXML parallel steps for DOCX. No heavy I/O.
159
+ */
160
+ declare function explainAnalysisPlan(input: BrowserAnalyzeInput, options?: BrowserExplainAnalysisPlanOptions): Promise<ExplainAnalysisPlanReport>;
161
+
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
@@ -1,10 +1,62 @@
1
1
  import { assertValidAnalyzeFileInput, detectFileKind, notImplementedResult, UNKNOWN_FORMAT_WARNING, analyzeText, toUint8Array, InvalidInputError } from '@dragon708/docmind-shared';
2
2
  export { detectFileKind } from '@dragon708/docmind-shared';
3
- import { extractTextFromDocx, convertDocxToHtml, analyzeDocx } from '@dragon708/docmind-docx';
3
+ import { analyzeDocx } from '@dragon708/docmind-docx';
4
4
  import { ocr } from '@dragon708/docmind-ocr';
5
5
 
6
6
  // src/analyzeFile.ts
7
- async function analyzeDocxForBrowser(input, signal) {
7
+ function assertBrowserInput(input) {
8
+ const ok = input instanceof File || input instanceof Blob || input instanceof ArrayBuffer;
9
+ if (!ok) {
10
+ throw new InvalidInputError("Expected a File, Blob, or ArrayBuffer.");
11
+ }
12
+ }
13
+ function throwIfAborted(signal) {
14
+ if (signal?.aborted) {
15
+ const err = new Error("The operation was aborted");
16
+ err.name = "AbortError";
17
+ throw err;
18
+ }
19
+ }
20
+ function prepareBrowserAnalyzeInput(input) {
21
+ assertBrowserInput(input);
22
+ assertValidAnalyzeFileInput(input);
23
+ return input;
24
+ }
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;
8
60
  if (signal?.aborted) {
9
61
  const err = new Error("The operation was aborted");
10
62
  err.name = "AbortError";
@@ -22,16 +74,13 @@ async function analyzeDocxForBrowser(input, signal) {
22
74
  warnings: ["No document bytes were provided for analysis."]
23
75
  };
24
76
  }
25
- const r = await analyzeDocx(data);
26
- return {
27
- fileKind: "docx",
28
- analyzer: "docx",
29
- status: "ok",
30
- kind: "docx",
31
- text: r.text,
32
- html: r.html,
33
- warnings: [...r.warnings]
34
- };
77
+ const docxOpts = analyzeDocxOptionsFromBrowser(options);
78
+ const r = docxOpts !== void 0 ? await analyzeDocx(data, docxOpts) : await analyzeDocx(data);
79
+ return docxPackageResultToAnalysisResult(r);
80
+ }
81
+ var OCR_OFF_WARNING = 'OCR mode is "off"; no recognition was run. Use mode "auto" or "force" to extract text from images.';
82
+ function resolveOcrMode(options) {
83
+ return options?.ocr?.mode ?? "auto";
35
84
  }
36
85
  async function analyzeImageForBrowser(input, options) {
37
86
  if (options?.signal?.aborted) {
@@ -52,6 +101,19 @@ async function analyzeImageForBrowser(input, options) {
52
101
  warnings: ["No image bytes were provided for analysis."]
53
102
  };
54
103
  }
104
+ const mode = resolveOcrMode(options);
105
+ if (mode === "off") {
106
+ return {
107
+ fileKind: "image",
108
+ analyzer: "image",
109
+ status: "ok",
110
+ kind: "image",
111
+ text: "",
112
+ confidence: 0,
113
+ ocrUsed: false,
114
+ warnings: [OCR_OFF_WARNING]
115
+ };
116
+ }
55
117
  const ocrOpts = {
56
118
  ...options?.ocr ?? {},
57
119
  signal: options?.ocr?.signal ?? options?.signal
@@ -71,12 +133,6 @@ async function analyzeImageForBrowser(input, options) {
71
133
 
72
134
  // src/analyzeFile.ts
73
135
  var BROWSER_PDF_UNSUPPORTED_WARNING = "PDF text extraction is not available in the browser runtime; use @dragon708/docmind-node on the server.";
74
- function assertBrowserInput(input) {
75
- const ok = input instanceof File || input instanceof Blob || input instanceof ArrayBuffer;
76
- if (!ok) {
77
- throw new InvalidInputError("Expected a File, Blob, or ArrayBuffer.");
78
- }
79
- }
80
136
  async function analyzeFile(input, options) {
81
137
  if (options?.signal?.aborted) {
82
138
  const err = new Error("The operation was aborted");
@@ -91,7 +147,7 @@ async function analyzeFile(input, options) {
91
147
  case "pdf":
92
148
  return notImplementedResult("pdf", "pdf", [BROWSER_PDF_UNSUPPORTED_WARNING]);
93
149
  case "docx":
94
- return analyzeDocxForBrowser(bytesInput, options?.signal);
150
+ return analyzeDocxForBrowser(bytesInput, options);
95
151
  case "image":
96
152
  return analyzeImageForBrowser(bytesInput, options);
97
153
  case "text":
@@ -100,104 +156,29 @@ async function analyzeFile(input, options) {
100
156
  return notImplementedResult(fileKind, "none", [UNKNOWN_FORMAT_WARNING]);
101
157
  }
102
158
  }
103
- function assertBrowserInput2(input) {
104
- const ok = input instanceof File || input instanceof Blob || input instanceof ArrayBuffer;
105
- if (!ok) {
106
- throw new InvalidInputError("Expected a File, Blob, or ArrayBuffer.");
107
- }
108
- }
109
- function throwIfAborted(signal) {
110
- if (signal?.aborted) {
111
- const err = new Error("The operation was aborted");
112
- err.name = "AbortError";
113
- throw err;
114
- }
115
- }
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.";
160
+ var IMAGE_METADATA_NOTE = "Raster images have no document metadata bundle in this API.";
116
161
  function escapeHtmlMinimal(s) {
117
162
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
118
163
  }
119
- var DOCX_METADATA_STUB = "Structured document metadata for DOCX is not exposed as a separate API; use extractText or analyzeFile.";
120
- var IMAGE_METADATA_NOTE = "Raster images have no document metadata bundle in this API.";
121
- async function kindOf(input) {
122
- assertBrowserInput2(input);
123
- assertValidAnalyzeFileInput(input);
124
- return input;
164
+ function toExtractTextResult(full) {
165
+ if (full.status !== "ok") return full;
166
+ if (full.fileKind === "docx") {
167
+ return { ...full, html: "" };
168
+ }
169
+ return full;
125
170
  }
126
171
  async function extractText(input, options) {
127
172
  throwIfAborted(options?.signal);
128
- const resolved = await kindOf(input);
129
- const kind = detectFileKind(resolved);
130
- const bytesInput = input;
131
- const signal = options?.signal;
132
- switch (kind) {
133
- case "pdf":
134
- return notImplementedResult("pdf", "pdf", [BROWSER_PDF_UNSUPPORTED_WARNING]);
135
- case "docx": {
136
- const data = await toUint8Array(bytesInput);
137
- if (data.byteLength === 0) {
138
- return {
139
- fileKind: "docx",
140
- analyzer: "docx",
141
- status: "ok",
142
- kind: "docx",
143
- text: "",
144
- html: "",
145
- warnings: ["No document bytes were provided for analysis."]
146
- };
147
- }
148
- const r = await extractTextFromDocx(data);
149
- return {
150
- fileKind: "docx",
151
- analyzer: "docx",
152
- status: "ok",
153
- kind: "docx",
154
- text: r.text,
155
- html: "",
156
- warnings: r.warnings
157
- };
158
- }
159
- case "image": {
160
- const data = await toUint8Array(bytesInput);
161
- if (data.byteLength === 0) {
162
- return {
163
- fileKind: "image",
164
- analyzer: "image",
165
- status: "ok",
166
- kind: "image",
167
- text: "",
168
- confidence: 0,
169
- ocrUsed: true,
170
- warnings: ["No image bytes were provided for analysis."]
171
- };
172
- }
173
- const ocrOpts = {
174
- ...options?.ocr ?? {},
175
- signal: options?.ocr?.signal ?? signal
176
- };
177
- const r = await ocr(data, ocrOpts);
178
- return {
179
- fileKind: "image",
180
- analyzer: "image",
181
- status: "ok",
182
- kind: "image",
183
- text: r.text,
184
- confidence: r.confidence,
185
- ocrUsed: r.ocrUsed,
186
- warnings: []
187
- };
188
- }
189
- case "text":
190
- return analyzeText(bytesInput, { signal });
191
- default:
192
- return notImplementedResult(kind, "none", [UNKNOWN_FORMAT_WARNING]);
193
- }
173
+ prepareBrowserAnalyzeInput(input);
174
+ const full = await analyzeFile(input, options);
175
+ return toExtractTextResult(full);
194
176
  }
195
177
  async function extractMetadata(input, options) {
196
178
  throwIfAborted(options?.signal);
197
- const resolved = await kindOf(input);
179
+ const resolved = prepareBrowserAnalyzeInput(input);
198
180
  const kind = detectFileKind(resolved);
199
- const bytesInput = input;
200
- const signal = options?.signal;
181
+ options?.signal;
201
182
  switch (kind) {
202
183
  case "pdf":
203
184
  return notImplementedResult("pdf", "pdf", [BROWSER_PDF_UNSUPPORTED_WARNING]);
@@ -223,20 +204,59 @@ async function extractMetadata(input, options) {
223
204
  warnings: [IMAGE_METADATA_NOTE]
224
205
  };
225
206
  case "text":
226
- return analyzeText(bytesInput, { signal });
207
+ return analyzeFile(input, options);
227
208
  default:
228
209
  return notImplementedResult(kind, "none", [UNKNOWN_FORMAT_WARNING]);
229
210
  }
230
211
  }
231
212
  async function convertToHtml(input, options) {
232
213
  throwIfAborted(options?.signal);
233
- const resolved = await kindOf(input);
214
+ const resolved = prepareBrowserAnalyzeInput(input);
215
+ const kind = detectFileKind(resolved);
216
+ if (kind === "pdf") {
217
+ return notImplementedResult("pdf", "pdf", [BROWSER_PDF_UNSUPPORTED_WARNING]);
218
+ }
219
+ if (kind === "image") {
220
+ return {
221
+ fileKind: "image",
222
+ analyzer: "image",
223
+ status: "ok",
224
+ kind: "image",
225
+ text: "",
226
+ confidence: 0,
227
+ ocrUsed: true,
228
+ warnings: ["No HTML representation for raster images; use extractText / runOcr."]
229
+ };
230
+ }
231
+ if (kind === "unknown") {
232
+ return notImplementedResult(kind, "none", [UNKNOWN_FORMAT_WARNING]);
233
+ }
234
+ const r = await analyzeFile(input, options);
235
+ if (r.status !== "ok") return r;
236
+ if (r.fileKind === "text") {
237
+ const html = `<pre>${escapeHtmlMinimal(r.text)}</pre>`;
238
+ return {
239
+ ...r,
240
+ html,
241
+ warnings: [
242
+ ...r.warnings,
243
+ "HTML for plain text is a <pre> wrapper around decoded UTF-8 content."
244
+ ]
245
+ };
246
+ }
247
+ return r;
248
+ }
249
+ async function runOcr(input, options) {
250
+ throwIfAborted(options?.signal);
251
+ const resolved = prepareBrowserAnalyzeInput(input);
234
252
  const kind = detectFileKind(resolved);
235
253
  const bytesInput = input;
236
254
  const signal = options?.signal;
237
255
  switch (kind) {
238
256
  case "pdf":
239
257
  return notImplementedResult("pdf", "pdf", [BROWSER_PDF_UNSUPPORTED_WARNING]);
258
+ case "image":
259
+ return analyzeImageForBrowser(bytesInput, options);
240
260
  case "docx": {
241
261
  const data = await toUint8Array(bytesInput);
242
262
  if (data.byteLength === 0) {
@@ -250,120 +270,467 @@ async function convertToHtml(input, options) {
250
270
  warnings: ["No document bytes were provided for analysis."]
251
271
  };
252
272
  }
253
- const [textPart, htmlPart] = await Promise.all([
254
- extractTextFromDocx(data),
255
- convertDocxToHtml(data)
256
- ]);
257
- return {
258
- fileKind: "docx",
259
- analyzer: "docx",
260
- status: "ok",
261
- kind: "docx",
262
- text: textPart.text,
263
- html: htmlPart.html,
264
- warnings: [...textPart.warnings, ...htmlPart.warnings]
265
- };
266
- }
267
- case "text": {
268
- const t = await analyzeText(bytesInput, { signal });
269
- const html = `<pre>${escapeHtmlMinimal(t.text)}</pre>`;
270
- return {
271
- ...t,
272
- html,
273
+ const opt = analyzeDocxOptionsFromBrowser(options);
274
+ const raw = opt !== void 0 ? await analyzeDocx(data, opt) : await analyzeDocx(data);
275
+ const withNote = {
276
+ ...raw,
273
277
  warnings: [
274
- ...t.warnings,
275
- "HTML for plain text is a <pre> wrapper around decoded UTF-8 content."
278
+ ...raw.warnings,
279
+ "OCR does not apply to DOCX; returned structured text/HTML extract."
276
280
  ]
277
281
  };
282
+ return docxPackageResultToAnalysisResult(withNote);
278
283
  }
279
- case "image":
280
- return {
281
- fileKind: "image",
282
- analyzer: "image",
283
- status: "ok",
284
- kind: "image",
285
- text: "",
286
- confidence: 0,
287
- ocrUsed: true,
288
- warnings: ["No HTML representation for raster images; use extractText / runOcr."]
289
- };
284
+ case "text":
285
+ return analyzeText(bytesInput, { signal });
290
286
  default:
291
287
  return notImplementedResult(kind, "none", [UNKNOWN_FORMAT_WARNING]);
292
288
  }
293
289
  }
294
- async function runOcr(input, options) {
295
- throwIfAborted(options?.signal);
296
- const resolved = await kindOf(input);
297
- const kind = detectFileKind(resolved);
298
- const bytesInput = input;
299
- const signal = options?.signal;
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 = [];
300
335
  switch (kind) {
301
336
  case "pdf":
302
- return notImplementedResult("pdf", "pdf", [BROWSER_PDF_UNSUPPORTED_WARNING]);
303
- case "image": {
304
- const data = await toUint8Array(bytesInput);
305
- if (data.byteLength === 0) {
306
- return {
307
- fileKind: "image",
308
- analyzer: "image",
309
- status: "ok",
310
- kind: "image",
311
- text: "",
312
- confidence: 0,
313
- ocrUsed: true,
314
- warnings: ["No image bytes were provided for analysis."]
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
+
402
+ // src/analysisPlanReport.ts
403
+ function lim(...items) {
404
+ return items.filter(Boolean);
405
+ }
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) {
419
+ const runtime = { id: "browser" };
420
+ const imageOcrActive = ocrMode !== "off";
421
+ let primaryAnalyzer = kind === "pdf" ? "pdf" : kind === "docx" ? "docx" : kind === "image" ? "image" : kind === "text" ? "text" : "none";
422
+ let nativeExtraction;
423
+ let ocr2;
424
+ let limitations = [];
425
+ const ocrOffNote = ocrMode === "off" ? 'Image OCR is skipped when ocr.mode is "off".' : "";
426
+ if (kind === "pdf") {
427
+ limitations = lim(BROWSER_PDF_UNSUPPORTED_WARNING);
428
+ nativeExtraction = {
429
+ willAttempt: false,
430
+ description: "PDF is not processed in the browser runtime; use @dragon708/docmind-node."
431
+ };
432
+ ocr2 = {
433
+ mayUse: false,
434
+ description: "PDF OCR is not available in the browser."
435
+ };
436
+ return finalizeBrowserDocxExplainReport({
437
+ kind,
438
+ detectedKind: kind,
439
+ runtime,
440
+ intent,
441
+ primaryAnalyzer: "pdf",
442
+ nativeExtraction,
443
+ ocr: ocr2,
444
+ limitations,
445
+ plan,
446
+ warnings: [BROWSER_PDF_UNSUPPORTED_WARNING]
447
+ });
448
+ }
449
+ if (kind === "unknown") {
450
+ limitations = lim(
451
+ "Could not classify the file from name, MIME, or bytes; analysis will return not_implemented until hints improve."
452
+ );
453
+ nativeExtraction = { willAttempt: false, description: "No analyzer selected without a known file kind." };
454
+ ocr2 = { mayUse: false, description: "OCR is not used for unknown kinds." };
455
+ return finalizeBrowserDocxExplainReport({
456
+ kind,
457
+ detectedKind: kind,
458
+ runtime,
459
+ intent,
460
+ primaryAnalyzer: "none",
461
+ nativeExtraction,
462
+ ocr: ocr2,
463
+ limitations,
464
+ plan
465
+ });
466
+ }
467
+ switch (intent) {
468
+ case "analyzeFile":
469
+ case "extractText":
470
+ if (kind === "docx") {
471
+ nativeExtraction = {
472
+ willAttempt: true,
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." : "")
474
+ };
475
+ ocr2 = { mayUse: false, description: "DOCX does not use OCR in DocMind." };
476
+ } else if (kind === "image") {
477
+ nativeExtraction = {
478
+ willAttempt: false,
479
+ description: "Raster images have no native text layer in this pipeline."
480
+ };
481
+ ocr2 = {
482
+ mayUse: imageOcrActive,
483
+ description: imageOcrActive ? "Tesseract.js may run to recover text (subject to format support)." : "OCR skipped while ocr.mode is off."
484
+ };
485
+ limitations = lim(ocrOffNote);
486
+ } else {
487
+ nativeExtraction = {
488
+ willAttempt: true,
489
+ description: "Plain text is decoded as UTF-8 (BOM stripped, replacement on invalid bytes)."
315
490
  };
491
+ ocr2 = { mayUse: false, description: "OCR does not apply to text files." };
316
492
  }
317
- const ocrOpts = {
318
- ...options?.ocr ?? {},
319
- signal: options?.ocr?.signal ?? signal
320
- };
321
- const r = await ocr(data, ocrOpts);
493
+ break;
494
+ case "extractMetadata":
495
+ if (kind === "docx" || kind === "image") {
496
+ nativeExtraction = {
497
+ willAttempt: false,
498
+ description: "No heavy extractor; extractMetadata returns a stub with guidance."
499
+ };
500
+ ocr2 = { mayUse: false, description: "OCR is not invoked for this metadata path." };
501
+ limitations = lim(
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."
503
+ );
504
+ } else {
505
+ nativeExtraction = {
506
+ willAttempt: true,
507
+ description: "Plain text is decoded; metadata is limited to decoded content."
508
+ };
509
+ ocr2 = { mayUse: false, description: "OCR does not apply." };
510
+ limitations = lim("Plain text has no structured document metadata.");
511
+ }
512
+ break;
513
+ case "convertToHtml":
514
+ if (kind === "docx") {
515
+ nativeExtraction = {
516
+ willAttempt: true,
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."
518
+ };
519
+ ocr2 = { mayUse: false, description: "DOCX path does not use OCR." };
520
+ } else if (kind === "text") {
521
+ nativeExtraction = {
522
+ willAttempt: true,
523
+ description: "UTF-8 decode then wrap in a <pre> element."
524
+ };
525
+ ocr2 = { mayUse: false, description: "OCR does not apply." };
526
+ } else {
527
+ nativeExtraction = {
528
+ willAttempt: false,
529
+ description: "No rich HTML path for this kind in the browser."
530
+ };
531
+ ocr2 = { mayUse: false, description: "OCR does not produce layout HTML here." };
532
+ limitations = lim(
533
+ kind === "image" ? "Raster images have no HTML representation; use extractText or runOcr." : ""
534
+ );
535
+ }
536
+ break;
537
+ case "runOcr":
538
+ if (kind === "image") {
539
+ nativeExtraction = {
540
+ willAttempt: false,
541
+ description: "No native text layer; recognition is OCR-only."
542
+ };
543
+ ocr2 = {
544
+ mayUse: imageOcrActive,
545
+ description: imageOcrActive ? "Tesseract.js runs for raster text." : "OCR skipped while ocr.mode is off."
546
+ };
547
+ limitations = lim(ocrOffNote);
548
+ } else if (kind === "docx") {
549
+ nativeExtraction = {
550
+ willAttempt: true,
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."
552
+ };
553
+ ocr2 = { mayUse: false, description: "DOCX is not OCR'd." };
554
+ limitations = lim("Returned content is structured extract, not OCR output.");
555
+ } else {
556
+ nativeExtraction = {
557
+ willAttempt: true,
558
+ description: "Plain text is UTF-8 decoded only."
559
+ };
560
+ ocr2 = { mayUse: false, description: "OCR does not apply to text files." };
561
+ }
562
+ break;
563
+ default:
564
+ nativeExtraction = { willAttempt: false, description: "Intent not specialized in this runtime." };
565
+ ocr2 = { mayUse: false, description: "See plan steps." };
566
+ }
567
+ return finalizeBrowserDocxExplainReport({
568
+ kind,
569
+ detectedKind: kind,
570
+ runtime,
571
+ intent,
572
+ primaryAnalyzer,
573
+ nativeExtraction,
574
+ ocr: ocr2,
575
+ limitations,
576
+ plan
577
+ });
578
+ }
579
+
580
+ // src/introspection.ts
581
+ function resolveOcrMode2(ocr2) {
582
+ return ocr2?.mode ?? "auto";
583
+ }
584
+ function planForAnalyzeFile(kind, ocrMode, docxInclude) {
585
+ switch (kind) {
586
+ case "pdf":
322
587
  return {
323
- fileKind: "image",
324
- analyzer: "image",
325
- status: "ok",
326
- kind: "image",
327
- text: r.text,
328
- confidence: r.confidence,
329
- ocrUsed: r.ocrUsed,
330
- warnings: []
588
+ intent: "analyzeFile",
589
+ steps: [
590
+ { id: "detect_kind", status: "done" },
591
+ { id: "pdf_pipeline", status: "skipped" }
592
+ ]
331
593
  };
332
- }
333
594
  case "docx": {
334
- const data = await toUint8Array(bytesInput);
335
- if (data.byteLength === 0) {
336
- return {
337
- fileKind: "docx",
338
- analyzer: "docx",
339
- status: "ok",
340
- kind: "docx",
341
- text: "",
342
- html: "",
343
- warnings: ["No document bytes were provided for analysis."]
344
- };
345
- }
346
- const r = await analyzeDocx(data);
595
+ const parallel = docxIncludeRequested(docxInclude);
347
596
  return {
348
- fileKind: "docx",
349
- analyzer: "docx",
350
- status: "ok",
351
- kind: "docx",
352
- text: r.text,
353
- html: r.html,
354
- warnings: [
355
- ...r.warnings,
356
- "OCR does not apply to DOCX; returned structured text/HTML extract."
597
+ intent: "analyzeFile",
598
+ steps: [
599
+ { id: "detect_kind", status: "done" },
600
+ { id: "docx_mammoth", status: "planned" },
601
+ ...parallel ? [{ id: "docx_ooxml_parallel", status: "planned" }] : []
357
602
  ]
358
603
  };
359
604
  }
605
+ case "image":
606
+ return {
607
+ intent: "analyzeFile",
608
+ steps: [
609
+ { id: "detect_kind", status: "done" },
610
+ {
611
+ id: "image_ocr",
612
+ status: ocrMode === "off" ? "skipped" : "planned"
613
+ }
614
+ ]
615
+ };
360
616
  case "text":
361
- return analyzeText(bytesInput, { signal });
617
+ return {
618
+ intent: "analyzeFile",
619
+ steps: [
620
+ { id: "detect_kind", status: "done" },
621
+ { id: "utf8_decode", status: "planned" }
622
+ ]
623
+ };
362
624
  default:
363
- return notImplementedResult(kind, "none", [UNKNOWN_FORMAT_WARNING]);
625
+ return {
626
+ intent: "analyzeFile",
627
+ steps: [{ id: "detect_kind", status: "done" }, { id: "route", status: "failed" }]
628
+ };
629
+ }
630
+ }
631
+ function planForIntent(intentOpt, kind, ocrMode, docxInclude) {
632
+ const intent = intentOpt ?? "analyzeFile";
633
+ if (intent === "analyzeFile") return planForAnalyzeFile(kind, ocrMode, docxInclude);
634
+ if (intent === "extractText") {
635
+ const base = planForAnalyzeFile(kind, ocrMode, docxInclude);
636
+ return { ...base, intent: "extractText" };
637
+ }
638
+ if (intent === "extractMetadata") {
639
+ if (kind === "text") {
640
+ return {
641
+ intent: "extractMetadata",
642
+ steps: [
643
+ { id: "detect_kind", status: "done" },
644
+ { id: "utf8_decode", status: "planned" }
645
+ ]
646
+ };
647
+ }
648
+ return {
649
+ intent: "extractMetadata",
650
+ steps: [
651
+ { id: "detect_kind", status: "done" },
652
+ { id: "metadata_stub", status: kind === "docx" || kind === "image" ? "planned" : "skipped" }
653
+ ]
654
+ };
655
+ }
656
+ if (intent === "convertToHtml") {
657
+ if (kind === "docx") {
658
+ const parallel = docxIncludeRequested(docxInclude);
659
+ return {
660
+ intent: "convertToHtml",
661
+ steps: [
662
+ { id: "detect_kind", status: "done" },
663
+ { id: "docx_mammoth_html", status: "planned" },
664
+ ...parallel ? [{ id: "docx_ooxml_parallel", status: "planned" }] : []
665
+ ]
666
+ };
667
+ }
668
+ if (kind === "text") {
669
+ return {
670
+ intent: "convertToHtml",
671
+ steps: [
672
+ { id: "detect_kind", status: "done" },
673
+ { id: "utf8_decode", status: "planned" },
674
+ { id: "wrap_pre", status: "planned" }
675
+ ]
676
+ };
677
+ }
678
+ return {
679
+ intent: "convertToHtml",
680
+ steps: [
681
+ { id: "detect_kind", status: "done" },
682
+ { id: "rich_html", status: "skipped" }
683
+ ]
684
+ };
685
+ }
686
+ if (intent === "runOcr") {
687
+ if (kind === "image") {
688
+ return {
689
+ intent: "runOcr",
690
+ steps: [
691
+ { id: "detect_kind", status: "done" },
692
+ { id: "tesseract_ocr", status: ocrMode === "off" ? "skipped" : "planned" }
693
+ ]
694
+ };
695
+ }
696
+ if (kind === "docx") {
697
+ const parallel = docxIncludeRequested(docxInclude);
698
+ return {
699
+ intent: "runOcr",
700
+ steps: [
701
+ { id: "detect_kind", status: "done" },
702
+ { id: "docx_mammoth", status: "planned" },
703
+ ...parallel ? [{ id: "docx_ooxml_parallel", status: "planned" }] : []
704
+ ]
705
+ };
706
+ }
707
+ return {
708
+ intent: "runOcr",
709
+ steps: [
710
+ { id: "detect_kind", status: "done" },
711
+ { id: "ocr", status: "skipped" }
712
+ ]
713
+ };
364
714
  }
715
+ return planForAnalyzeFile(kind, ocrMode, docxInclude);
716
+ }
717
+ async function getCapabilities(input, options) {
718
+ throwIfAborted(options?.signal);
719
+ prepareBrowserAnalyzeInput(input);
720
+ const kind = detectFileKind(input);
721
+ return buildBrowserCapabilityReport(kind);
722
+ }
723
+ async function explainAnalysisPlan(input, options) {
724
+ throwIfAborted(options?.signal);
725
+ prepareBrowserAnalyzeInput(input);
726
+ const kind = detectFileKind(input);
727
+ const intent = options?.intent ?? "analyzeFile";
728
+ const ocrMode = resolveOcrMode2(options?.ocr);
729
+ const docxInc = options?.docx?.include;
730
+ const plan = planForIntent(intent, kind, ocrMode, docxInc);
731
+ return buildBrowserExplainReport(kind, intent, ocrMode, plan, docxInc);
365
732
  }
366
733
 
367
- export { BROWSER_PDF_UNSUPPORTED_WARNING, analyzeFile, convertToHtml, extractMetadata, extractText, runOcr };
734
+ export { BROWSER_PDF_UNSUPPORTED_WARNING, DOCX_EMBEDDED_IMAGE_CAPABILITIES_BROWSER, DOCX_STRUCTURE_CAPABILITIES_BROWSER, analyzeFile, convertToHtml, docxIncludeRequested, explainAnalysisPlan, extractMetadata, extractText, getCapabilities, runOcr };
368
735
  //# sourceMappingURL=index.js.map
369
736
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dragon708/docmind-browser",
3
- "version": "1.1.0",
4
- "description": "Browser DocMind entry: DOCX, OCR, text (no PDF; use @dragon708/docmind-node on the server).",
3
+ "version": "1.4.0",
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,
7
7
  "main": "./dist/index.js",
@@ -15,7 +15,8 @@
15
15
  }
16
16
  },
17
17
  "files": [
18
- "dist"
18
+ "dist/**/*.js",
19
+ "dist/**/*.d.ts"
19
20
  ],
20
21
  "publishConfig": {
21
22
  "access": "public"
@@ -32,9 +33,9 @@
32
33
  ],
33
34
  "license": "MIT",
34
35
  "dependencies": {
35
- "@dragon708/docmind-docx": "^1.0.0",
36
+ "@dragon708/docmind-docx": "^1.7.0",
36
37
  "@dragon708/docmind-ocr": "^1.0.0",
37
- "@dragon708/docmind-shared": "^1.0.0"
38
+ "@dragon708/docmind-shared": "^1.1.0"
38
39
  },
39
40
  "devDependencies": {
40
41
  "@types/node": "^20.19.37",
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/analyzers/docx.ts","../src/analyzers/image.ts","../src/analyzeFile.ts","../src/publicActions.ts"],"names":["extractDocx","toUint8Array","assertBrowserInput","InvalidInputError","assertValidAnalyzeFileInput","detectFileKind","notImplementedResult","ocr","analyzeText","UNKNOWN_FORMAT_WARNING"],"mappings":"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","file":"index.js","sourcesContent":["import { analyzeDocx as extractDocx } from \"@dragon708/docmind-docx\";\nimport type { AnalysisResult, FileLikeInput } from \"@dragon708/docmind-shared\";\nimport { toUint8Array } from \"@dragon708/docmind-shared\";\n\n/**\n * DOCX → `@dragon708/docmind-docx` (browser-safe: Mammoth + JSZip).\n */\nexport async function analyzeDocxForBrowser(\n input: FileLikeInput,\n signal?: AbortSignal,\n): Promise<AnalysisResult> {\n if (signal?.aborted) {\n const err = new Error(\"The operation was aborted\");\n err.name = \"AbortError\";\n throw err;\n }\n\n const data = await toUint8Array(input);\n if (data.byteLength === 0) {\n return {\n fileKind: \"docx\",\n analyzer: \"docx\",\n status: \"ok\",\n kind: \"docx\",\n text: \"\",\n html: \"\",\n warnings: [\"No document bytes were provided for analysis.\"],\n };\n }\n\n const r = await extractDocx(data);\n return {\n fileKind: \"docx\",\n analyzer: \"docx\",\n status: \"ok\",\n kind: \"docx\",\n text: r.text,\n html: r.html,\n warnings: [...r.warnings],\n };\n}\n","import { ocr } from \"@dragon708/docmind-ocr\";\nimport type { AnalysisResult, FileLikeInput } from \"@dragon708/docmind-shared\";\nimport { toUint8Array } from \"@dragon708/docmind-shared\";\nimport type { BrowserAnalyzeOptions } from \"../browserAnalyzeOptions.js\";\n\n/**\n * Image → `@dragon708/docmind-ocr` (Tesseract in WASM / browser).\n */\nexport async function analyzeImageForBrowser(\n input: FileLikeInput,\n options?: BrowserAnalyzeOptions,\n): Promise<AnalysisResult> {\n if (options?.signal?.aborted) {\n const err = new Error(\"The operation was aborted\");\n err.name = \"AbortError\";\n throw err;\n }\n\n const data = await toUint8Array(input);\n if (data.byteLength === 0) {\n return {\n fileKind: \"image\",\n analyzer: \"image\",\n status: \"ok\",\n kind: \"image\",\n text: \"\",\n confidence: 0,\n ocrUsed: true,\n warnings: [\"No image bytes were provided for analysis.\"],\n };\n }\n\n const ocrOpts = {\n ...(options?.ocr ?? {}),\n signal: options?.ocr?.signal ?? options?.signal,\n };\n\n const r = await ocr(data, ocrOpts);\n return {\n fileKind: \"image\",\n analyzer: \"image\",\n status: \"ok\",\n kind: \"image\",\n text: r.text,\n confidence: r.confidence,\n ocrUsed: r.ocrUsed,\n warnings: [],\n };\n}\n","import type { AnalysisResult, FileLikeInput } from \"@dragon708/docmind-shared\";\r\nimport {\r\n analyzeText,\r\n assertValidAnalyzeFileInput,\r\n detectFileKind,\r\n InvalidInputError,\r\n notImplementedResult,\r\n UNKNOWN_FORMAT_WARNING,\r\n} from \"@dragon708/docmind-shared\";\r\nimport type { DetectFileKindInput } from \"@dragon708/docmind-shared\";\r\nimport type { BrowserAnalyzeOptions } from \"./browserAnalyzeOptions.js\";\r\nimport { analyzeDocxForBrowser } from \"./analyzers/docx.js\";\r\nimport { analyzeImageForBrowser } from \"./analyzers/image.js\";\r\n\r\n/** PDF is not processed in the browser; use `@dragon708/docmind-node` on the server. */\r\nexport const BROWSER_PDF_UNSUPPORTED_WARNING =\r\n \"PDF text extraction is not available in the browser runtime; use @dragon708/docmind-node on the server.\";\r\n\r\n/**\r\n * Inputs supported by the browser entry (DOM types only — no `fs`, no Node `Buffer` in the public surface).\r\n */\r\nexport type BrowserAnalyzeInput = File | Blob | ArrayBuffer;\r\n\r\nfunction assertBrowserInput(input: unknown): asserts input is BrowserAnalyzeInput {\r\n const ok =\r\n input instanceof File ||\r\n input instanceof Blob ||\r\n input instanceof ArrayBuffer;\r\n if (!ok) {\r\n throw new InvalidInputError(\"Expected a File, Blob, or ArrayBuffer.\");\r\n }\r\n}\r\n\r\n/**\r\n * Browser-only router: DOCX, images (OCR), and text. PDF yields `not_implemented` with a clear warning.\r\n */\r\nexport async function analyzeFile(\r\n input: BrowserAnalyzeInput,\r\n options?: BrowserAnalyzeOptions,\r\n): Promise<AnalysisResult> {\r\n if (options?.signal?.aborted) {\r\n const err = new Error(\"The operation was aborted\");\r\n err.name = \"AbortError\";\r\n throw err;\r\n }\r\n\r\n assertBrowserInput(input);\r\n assertValidAnalyzeFileInput(input);\r\n\r\n const fileKind = detectFileKind(input as DetectFileKindInput);\r\n\r\n const bytesInput = input as FileLikeInput;\r\n\r\n switch (fileKind) {\r\n case \"pdf\":\r\n return notImplementedResult(\"pdf\", \"pdf\", [BROWSER_PDF_UNSUPPORTED_WARNING]);\r\n case \"docx\":\r\n return analyzeDocxForBrowser(bytesInput, options?.signal);\r\n case \"image\":\r\n return analyzeImageForBrowser(bytesInput, options);\r\n case \"text\":\r\n return analyzeText(bytesInput, { signal: options?.signal });\r\n default:\r\n return notImplementedResult(fileKind, \"none\", [UNKNOWN_FORMAT_WARNING]);\r\n }\r\n}\r\n","import type { AnalysisResult, DetectFileKindInput, FileLikeInput } from \"@dragon708/docmind-shared\";\nimport {\n analyzeText,\n assertValidAnalyzeFileInput,\n detectFileKind,\n InvalidInputError,\n notImplementedResult,\n UNKNOWN_FORMAT_WARNING,\n toUint8Array,\n} from \"@dragon708/docmind-shared\";\nimport {\n analyzeDocx,\n convertDocxToHtml,\n extractTextFromDocx,\n} from \"@dragon708/docmind-docx\";\nimport { ocr } from \"@dragon708/docmind-ocr\";\nimport type { BrowserAnalyzeOptions } from \"./browserAnalyzeOptions.js\";\nimport { BROWSER_PDF_UNSUPPORTED_WARNING } from \"./analyzeFile.js\";\nimport type { BrowserAnalyzeInput } from \"./analyzeFile.js\";\n\nfunction assertBrowserInput(input: unknown): asserts input is BrowserAnalyzeInput {\n const ok =\n input instanceof File ||\n input instanceof Blob ||\n input instanceof ArrayBuffer;\n if (!ok) {\n throw new InvalidInputError(\"Expected a File, Blob, or ArrayBuffer.\");\n }\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) {\n const err = new Error(\"The operation was aborted\");\n err.name = \"AbortError\";\n throw err;\n }\n}\n\nfunction escapeHtmlMinimal(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\nconst DOCX_METADATA_STUB =\n \"Structured document metadata for DOCX is not exposed as a separate API; use extractText or analyzeFile.\";\n\nconst IMAGE_METADATA_NOTE =\n \"Raster images have no document metadata bundle in this API.\";\n\nasync function kindOf(input: BrowserAnalyzeInput): Promise<DetectFileKindInput> {\n assertBrowserInput(input);\n assertValidAnalyzeFileInput(input);\n return input as DetectFileKindInput;\n}\n\n/**\n * Text only: DOCX → `extractTextFromDocx`; imagen → `ocr`; texto → `analyzeText`.\n * PDF no está soportado en el navegador (mismo aviso que `analyzeFile`).\n */\nexport async function extractText(\n input: BrowserAnalyzeInput,\n options?: BrowserAnalyzeOptions,\n): Promise<AnalysisResult> {\n throwIfAborted(options?.signal);\n const resolved = await kindOf(input);\n const kind = detectFileKind(resolved);\n const bytesInput = input as FileLikeInput;\n const signal = options?.signal;\n\n switch (kind) {\n case \"pdf\":\n return notImplementedResult(\"pdf\", \"pdf\", [BROWSER_PDF_UNSUPPORTED_WARNING]);\n case \"docx\": {\n const data = await toUint8Array(bytesInput);\n if (data.byteLength === 0) {\n return {\n fileKind: \"docx\",\n analyzer: \"docx\",\n status: \"ok\",\n kind: \"docx\",\n text: \"\",\n html: \"\",\n warnings: [\"No document bytes were provided for analysis.\"],\n };\n }\n const r = await extractTextFromDocx(data);\n return {\n fileKind: \"docx\",\n analyzer: \"docx\",\n status: \"ok\",\n kind: \"docx\",\n text: r.text,\n html: \"\",\n warnings: r.warnings,\n };\n }\n case \"image\": {\n const data = await toUint8Array(bytesInput);\n if (data.byteLength === 0) {\n return {\n fileKind: \"image\",\n analyzer: \"image\",\n status: \"ok\",\n kind: \"image\",\n text: \"\",\n confidence: 0,\n ocrUsed: true,\n warnings: [\"No image bytes were provided for analysis.\"],\n };\n }\n const ocrOpts = {\n ...(options?.ocr ?? {}),\n signal: options?.ocr?.signal ?? signal,\n };\n const r = await ocr(data, ocrOpts);\n return {\n fileKind: \"image\",\n analyzer: \"image\",\n status: \"ok\",\n kind: \"image\",\n text: r.text,\n confidence: r.confidence,\n ocrUsed: r.ocrUsed,\n warnings: [],\n };\n }\n case \"text\":\n return analyzeText(bytesInput, { signal });\n default:\n return notImplementedResult(kind, \"none\", [UNKNOWN_FORMAT_WARNING]);\n }\n}\n\n/**\n * Metadatos: en el navegador no hay pipeline PDF ni metadatos DOCX dedicados;\n * DOCX/imagen con avisos; texto → `analyzeText`.\n */\nexport async function extractMetadata(\n input: BrowserAnalyzeInput,\n options?: BrowserAnalyzeOptions,\n): Promise<AnalysisResult> {\n throwIfAborted(options?.signal);\n const resolved = await kindOf(input);\n const kind = detectFileKind(resolved);\n const bytesInput = input as FileLikeInput;\n const signal = options?.signal;\n\n switch (kind) {\n case \"pdf\":\n return notImplementedResult(\"pdf\", \"pdf\", [BROWSER_PDF_UNSUPPORTED_WARNING]);\n case \"docx\":\n return {\n fileKind: \"docx\",\n analyzer: \"docx\",\n status: \"ok\",\n kind: \"docx\",\n text: \"\",\n html: \"\",\n warnings: [DOCX_METADATA_STUB],\n };\n case \"image\":\n return {\n fileKind: \"image\",\n analyzer: \"image\",\n status: \"ok\",\n kind: \"image\",\n text: \"\",\n confidence: 0,\n ocrUsed: true,\n warnings: [IMAGE_METADATA_NOTE],\n };\n case \"text\":\n return analyzeText(bytesInput, { signal });\n default:\n return notImplementedResult(kind, \"none\", [UNKNOWN_FORMAT_WARNING]);\n }\n}\n\n/**\n * HTML: DOCX → `extractTextFromDocx` + `convertDocxToHtml`; texto → `<pre>`;\n * PDF/imagen no aplican en browser como HTML rico.\n */\nexport async function convertToHtml(\n input: BrowserAnalyzeInput,\n options?: BrowserAnalyzeOptions,\n): Promise<AnalysisResult> {\n throwIfAborted(options?.signal);\n const resolved = await kindOf(input);\n const kind = detectFileKind(resolved);\n const bytesInput = input as FileLikeInput;\n const signal = options?.signal;\n\n switch (kind) {\n case \"pdf\":\n return notImplementedResult(\"pdf\", \"pdf\", [BROWSER_PDF_UNSUPPORTED_WARNING]);\n case \"docx\": {\n const data = await toUint8Array(bytesInput);\n if (data.byteLength === 0) {\n return {\n fileKind: \"docx\",\n analyzer: \"docx\",\n status: \"ok\",\n kind: \"docx\",\n text: \"\",\n html: \"\",\n warnings: [\"No document bytes were provided for analysis.\"],\n };\n }\n const [textPart, htmlPart] = await Promise.all([\n extractTextFromDocx(data),\n convertDocxToHtml(data),\n ]);\n return {\n fileKind: \"docx\",\n analyzer: \"docx\",\n status: \"ok\",\n kind: \"docx\",\n text: textPart.text,\n html: htmlPart.html,\n warnings: [...textPart.warnings, ...htmlPart.warnings],\n };\n }\n case \"text\": {\n const t = await analyzeText(bytesInput, { signal });\n const html = `<pre>${escapeHtmlMinimal(t.text)}</pre>`;\n return {\n ...t,\n html,\n warnings: [\n ...t.warnings,\n \"HTML for plain text is a <pre> wrapper around decoded UTF-8 content.\",\n ],\n } as AnalysisResult;\n }\n case \"image\":\n return {\n fileKind: \"image\",\n analyzer: \"image\",\n status: \"ok\",\n kind: \"image\",\n text: \"\",\n confidence: 0,\n ocrUsed: true,\n warnings: [\"No HTML representation for raster images; use extractText / runOcr.\"],\n };\n default:\n return notImplementedResult(kind, \"none\", [UNKNOWN_FORMAT_WARNING]);\n }\n}\n\n/**\n * OCR: imagen → `ocr`; DOCX → `analyzeDocx` con aviso (sin OCR); texto → `analyzeText`.\n * PDF no soportado en browser.\n */\nexport async function runOcr(\n input: BrowserAnalyzeInput,\n options?: BrowserAnalyzeOptions,\n): Promise<AnalysisResult> {\n throwIfAborted(options?.signal);\n const resolved = await kindOf(input);\n const kind = detectFileKind(resolved);\n const bytesInput = input as FileLikeInput;\n const signal = options?.signal;\n\n switch (kind) {\n case \"pdf\":\n return notImplementedResult(\"pdf\", \"pdf\", [BROWSER_PDF_UNSUPPORTED_WARNING]);\n case \"image\": {\n const data = await toUint8Array(bytesInput);\n if (data.byteLength === 0) {\n return {\n fileKind: \"image\",\n analyzer: \"image\",\n status: \"ok\",\n kind: \"image\",\n text: \"\",\n confidence: 0,\n ocrUsed: true,\n warnings: [\"No image bytes were provided for analysis.\"],\n };\n }\n const ocrOpts = {\n ...(options?.ocr ?? {}),\n signal: options?.ocr?.signal ?? signal,\n };\n const r = await ocr(data, ocrOpts);\n return {\n fileKind: \"image\",\n analyzer: \"image\",\n status: \"ok\",\n kind: \"image\",\n text: r.text,\n confidence: r.confidence,\n ocrUsed: r.ocrUsed,\n warnings: [],\n };\n }\n case \"docx\": {\n const data = await toUint8Array(bytesInput);\n if (data.byteLength === 0) {\n return {\n fileKind: \"docx\",\n analyzer: \"docx\",\n status: \"ok\",\n kind: \"docx\",\n text: \"\",\n html: \"\",\n warnings: [\"No document bytes were provided for analysis.\"],\n };\n }\n const r = await analyzeDocx(data);\n return {\n fileKind: \"docx\",\n analyzer: \"docx\",\n status: \"ok\",\n kind: \"docx\",\n text: r.text,\n html: r.html,\n warnings: [\n ...r.warnings,\n \"OCR does not apply to DOCX; returned structured text/HTML extract.\",\n ],\n };\n }\n case \"text\":\n return analyzeText(bytesInput, { signal });\n default:\n return notImplementedResult(kind, \"none\", [UNKNOWN_FORMAT_WARNING]);\n }\n}\n"]}