fix(connectors): index Office documents and PDFs from SharePoint and OneDrive - #6785
Conversation
…OneDrive The SharePoint and OneDrive connectors filtered their listings against a 12-item plain-text extension whitelist, so a document library of .docx, .pdf or .xlsx files synced as "success, 0 documents" — no document, no failed row, and no log line, which is indistinguishable from a wrong folder path. Both whitelists had been unchanged since the connectors shipped, and Sim already parses all of these formats for a manually uploaded knowledge base document. Adds a shared `extractConnectorText` in connectors/utils that routes binary document formats through the same `parseBuffer` the upload path uses, so the OOXML zip-bomb guard and each parser's extraction limits apply. The previously-accepted text formats stay on their exact existing path: sending .csv through CsvParser would silently reformat every already-indexed connector document on its next re-index. Also logs a per-page count of files skipped for an unsupported extension. Unsupported files are counted rather than turned into failed document rows, so a library full of images does not fill the knowledge base with noise.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Failed or placeholder extractions (legacy OLE, image-only decks, empty PDFs) surface as skipped documents via
Reviewed by Cursor Bugbot for commit 1bb1b2b. Configure here. |
Greptile SummaryThe PR enables SharePoint and OneDrive connectors to index Office, PDF, and OpenDocument files while preserving the existing decoding path for text formats.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the previously reported legacy parser fallback issue is addressed by rejecting degraded extraction results and preserving them as visible failed documents.
|
| Filename | Overview |
|---|---|
| apps/sim/connectors/utils.ts | Adds centralized indexable-extension detection, binary parsing, and rejection of empty or degraded extraction results. |
| apps/sim/connectors/sharepoint/sharepoint.ts | Expands SharePoint listing and hydration to supported document formats while preserving size and extraction-failure handling. |
| apps/sim/connectors/onedrive/onedrive.ts | Applies the shared document extraction and unsupported-extension diagnostics to OneDrive. |
| apps/sim/lib/file-parsers/index.ts | Replaces the failure-tolerant dynamic registry with explicit parser mappings for the newly supported format variants. |
| apps/sim/lib/file-parsers/doc-parser.ts | Declares legacy DOC fallback output as degraded so automated connector syncs do not index it. |
| apps/sim/lib/file-parsers/pptx-parser.ts | Declares PowerPoint fallback output as degraded so connector syncs surface extraction failure instead of fabricated content. |
| apps/sim/lib/file-parsers/opendocument-parser.ts | Adds guarded ODT and ODP parsing without a raw-byte fallback. |
| apps/sim/lib/file-parsers/types.ts | Extends parser metadata and supported-format contracts for degraded extraction and additional Office/OpenDocument variants. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
List[SharePoint or OneDrive listing] --> Filter{Indexable extension?}
Filter -- No --> Log[Count unsupported extension]
Filter -- Yes --> Stub[Create deferred document stub]
Stub --> Download[Download with byte limit]
Download --> Kind{Text or binary?}
Kind -- Text --> Decode[UTF-8 or HTML-to-text]
Kind -- Binary --> Parse[Shared file parser]
Parse --> Quality{Content usable and not degraded?}
Quality -- Yes --> Index[Index extracted text]
Quality -- No --> Skip[Persist visible failed/skipped document]
Decode --> Index
Reviews (3): Last reviewed commit: "fix(file-parsers): resolve the parser re..." | Re-trigger Greptile
`DocParser` and `PptxParser` never throw by design — on a legacy OLE `.doc`/`.ppt` or a deck with no extractable text they return a placeholder sentence or scraped ZIP internals so an interactive upload still shows the user something. Verified against real OOXML fixtures: an image-only `.pptx` yields 1.9KB of `[Content_Types].xml…` as "content", and a legacy `.ppt` yields "Unable to extract text from PowerPoint file." A connector sync would embed that into the vector index at scale, so it needs to tell a real extraction from a fabricated one. Adds a declared `degraded` flag to `FileParseMetadata`, set by exactly those two fallback paths, rather than having callers sniff `extractionMethod`. `DocParser`'s plaintext branch stays unflagged: a text file misnamed `.doc` is a genuine extraction. `extractConnectorText` now raises `ConnectorTextExtractionError` when a parsed format comes back degraded or blank, and SharePoint/OneDrive surface it as a skipped document via the existing `markSkipped` path — so the file appears in the knowledge base as a failed row telling the user to re-save it as DOCX/PPTX/XLSX, instead of being silently dropped or indexed as junk. The upload path is unaffected; it ignores the new flag.
Follow-up: verified the parsers against real fixtures, found a second defectQuestion raised: do I built genuine OOXML archives with
FixRather than have callers sniff
The upload path is unaffected — it ignores the new flag. Also verified while I was in here
TestsNew Both new guards were confirmed able to fail: removing
|
… handle
A document library holds whole format families, not just the headline extension
of each. These all extract correctly with the libraries already installed — they
were simply never registered, so every one of them was reported as an
unsupported file type:
docm dotx (WordprocessingML — mammoth reads word/document.xml regardless of
the package content type)
xlsm xlsb xltx ods (SheetJS reads every workbook container natively)
pptm potx (PresentationML)
odt odp (OpenDocument, via a new OpenDocumentParser)
Verified against real fixtures built with jszip and SheetJS rather than assumed:
officeparser identifies a Buffer by sniffing content with `file-type`, not by the
name we pass, so the routing had to be measured. `ods` goes to the spreadsheet
parser rather than OpenDocumentParser so its output keeps per-sheet structure.
`rtf` is deliberately excluded: nothing bundled extracts it, and DocParser's
plaintext branch would pass its control words through as if they were prose.
Converts the registry from `require()` inside per-parser `try/catch` blocks that
only logged to static imports. Every parser dependency is a regular, non-optional
one, so a resolution failure should fail loudly — the old form produced a silently
**empty** registry in which every format became `Unsupported file type`, with an
empty "Supported types are:" list as the only clue. The heavy extraction libraries
are still deferred inside the individual parsers, and connectors now import the
registry lazily so the ~60 connectors that never touch a file do not pull SheetJS.
Adds registry.test.ts, which exercises the real module: index.test.ts mocks
`@/lib/file-parsers` itself, so it validated its own fake routing table and the
real registry had no coverage at all. The new test gates every member of
SupportedFileType on having a registered parser that supports buffer parsing.
Format audit: what was missing, and what is genuinely impossibleRegistered in this push — all already parseable, just never wired upVerified with real fixtures built via
Zero new dependencies. Why the degraded ones are degraded, and what can actually be done
Image-only
Happy to add Two defects found while auditing1. The registry could silently support nothing. It loaded every parser with 2. Verification
|
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 0cbab90. Configure here.
…ect keys The registry rewrite switched extension lookup from `Object.keys(parsers).includes(ext)` to a bracket read on an object literal, which also resolves inherited keys. `PARSERS['constructor']` therefore returned `Object` — truthy, with no parse methods — so a caller-supplied extension of `constructor` fell through to "does not support buffer parsing" instead of being rejected as an unsupported type, and `parseFile` would have raised a TypeError. It also disagreed with `isSupportedFileType`, which used `Object.hasOwn` and correctly returned false for the same input. A Map has no prototype chain to walk, so lookup and support check now agree by construction. `isSupportedFileType` also guards a non-string argument, which the try/catch it replaced used to absorb.
Self-review found one defect I introduced — fixed in
|
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 1bb1b2b. Configure here.
Problem
A customer pointed a SharePoint connector at a document library of SOPs and got
0 documentson every sync — no error, no failed rows,status: completed. Three days were spent re-checking the site URL, the folder path, and the credential, all of which were correct.The SharePoint and OneDrive connectors filtered their listings against a 12-item plain-text extension whitelist:
Anything else —
.docx,.pdf,.xlsx,.pptx— failedisSupportedTextFileduring listing and was dropped before it could become a document. The folder resolved correctly; it just had nothing the filter would accept, so the sync legitimately reported success with zero documents. That outcome is indistinguishable from a wrong folder path, which is what made it so hard to diagnose.Two things worth noting:
lib/file-parserscoverspdf doc docx xls xlsx ppt pptx, and the same customer had a.docxsitting in the same knowledge base, uploaded manually and processed successfully. The parsers existed; the connectors just never called them —downloadFileContentdid a rawbuffer.toString('utf8').Confirming evidence from the affected workspace: the customer's working connector on the same site and credential holds 64 documents, and all 64 are
.csv,.htm, or.txt. Zero Office documents across the entire library tree — exactly the shape the whitelist imposes.Change
Adds three helpers to
apps/sim/connectors/utils.ts, next to the existingCONNECTOR_MAX_FILE_BYTESthat already aligns the connector size cap with the upload cap:CONNECTOR_INDEXABLE_EXTENSIONS/isIndexableConnectorFile(name)— the union of the text formats connectors already accepted and the binary document formats the knowledge base can parse.extractConnectorText(buffer, fileName)— UTF-8 for text formats,htmlToPlainTextfor HTML, andparseBufferfor binary document formats.sharepoint.tsandonedrive.tsnow use those instead of their local whitelists, and theirdownloadFileContentreturns aBufferrather than a pre-decoded string.The change is deliberately additive.
CONNECTOR_TEXT_EXTENSIONSandCONNECTOR_PARSED_EXTENSIONSare kept as separate lists precisely so a format that synced yesterday takes the identical path today. Routing.csvthroughCsvParseror.jsonthrough the JSON parser would reformat content that is already embedded, changing every existing connector document on its next re-index — so those keep bypassing the parsers. Only the newly-accepted binary formats reachparseBuffer, which is also where the OOXML zip-bomb guard and each parser's own extraction limits (MAX_PDF_TEXT_CHARS, the 60s PDF deadline) apply.Also adds a per-page
logger.infocounting files skipped for an unsupported extension, with the distinct extensions seen. Unsupported files are counted, not turned intofaileddocument rows — a library full of images would otherwise flood the knowledge base UI. The goal is only to make "0 documents" explicable in the run trace.Tests
apps/sim/connectors/utils.test.ts:.png/.mp4/.zipstill rejected; extensionless and trailing-dot names rejected; case-insensitive.docxroutes throughparseBufferwith the right extension.txt/.csv/.yaml/.tsv/.xmldecode as UTF-8 and never invoke a parserapps/sim/connectors/sharepoint/sharepoint.test.ts:.docx/.pdf/.xlsx/.pptx/.txtreturns all five (this is the reported bug).png/.mp4/.txtstill returns only the.txtVerified the new tests can fail: narrowing
CONNECTOR_INDEXABLE_EXTENSIONSback to the text-only set turns exactly 3 of them red.vitest run connectors/— 695 passed (25 files)tsgo --noEmit -p apps/sim/tsconfig.json— clean apart from a pre-existing unrelatedCannot find module 'mssql'bun run check:audits— 29/29 passFollow-ups not in this PR
.pdfin connectors puts the sync path behind the same PDF extraction concern tracked separately for the upload path. The parser's own char/time caps apply and the size cap already matches manual upload, so this does not widen the limit — but it does add a second entry point worth resolving there.box,dropbox,s3,sftp, andgoogle-drivehave their own file-type handling that was not touched here. If they carry the same gap, they can adoptextractConnectorTextin a follow-up.