wizards 0.1.9
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/LICENSE +110 -0
- package/README.md +170 -0
- package/apps/runtime/dist/agents/architect.js +453 -0
- package/apps/runtime/dist/agents/project-assistant.js +354 -0
- package/apps/runtime/dist/agents/subscription.js +206 -0
- package/apps/runtime/dist/agents/thought.js +21 -0
- package/apps/runtime/dist/agents/website.js +197 -0
- package/apps/runtime/dist/app.js +153 -0
- package/apps/runtime/dist/auth/account.js +121 -0
- package/apps/runtime/dist/auth/index.js +329 -0
- package/apps/runtime/dist/auth/keys.js +55 -0
- package/apps/runtime/dist/auth/local-ticket.js +23 -0
- package/apps/runtime/dist/authoring/example.js +73 -0
- package/apps/runtime/dist/authoring/guide.js +259 -0
- package/apps/runtime/dist/authoring/ops.js +117 -0
- package/apps/runtime/dist/cli/autostart.js +134 -0
- package/apps/runtime/dist/cli/clients.js +44 -0
- package/apps/runtime/dist/cli/environment.js +81 -0
- package/apps/runtime/dist/cli/exec.js +45 -0
- package/apps/runtime/dist/cli/home.js +74 -0
- package/apps/runtime/dist/cli/machine.js +145 -0
- package/apps/runtime/dist/cli/main.js +125 -0
- package/apps/runtime/dist/cli/setup.js +273 -0
- package/apps/runtime/dist/cli/start.js +190 -0
- package/apps/runtime/dist/cli/status.js +120 -0
- package/apps/runtime/dist/cli/ui.js +12 -0
- package/apps/runtime/dist/cli/update.js +58 -0
- package/apps/runtime/dist/connectors/builtin.js +70 -0
- package/apps/runtime/dist/connectors/external.js +400 -0
- package/apps/runtime/dist/connectors/gmail.js +107 -0
- package/apps/runtime/dist/connectors/imap.js +217 -0
- package/apps/runtime/dist/connectors/index.js +266 -0
- package/apps/runtime/dist/connectors/mail.js +72 -0
- package/apps/runtime/dist/connectors/outlook.js +90 -0
- package/apps/runtime/dist/credits/credits.js +103 -0
- package/apps/runtime/dist/credits/estimate.js +132 -0
- package/apps/runtime/dist/db/adopt.js +149 -0
- package/apps/runtime/dist/db/client.js +146 -0
- package/apps/runtime/dist/db/control-schema.js +70 -0
- package/apps/runtime/dist/db/migrations/control/0000_last_absorbing_man.sql +47 -0
- package/apps/runtime/dist/db/migrations/control/0001_gorgeous_nicolaos.sql +41 -0
- package/apps/runtime/dist/db/migrations/control/0002_secret_penance.sql +1 -0
- package/apps/runtime/dist/db/migrations/control/0003_nasty_mordo.sql +3 -0
- package/apps/runtime/dist/db/migrations/control/0004_breezy_eddie_brock.sql +6 -0
- package/apps/runtime/dist/db/migrations/control/meta/0000_snapshot.json +311 -0
- package/apps/runtime/dist/db/migrations/control/meta/0001_snapshot.json +599 -0
- package/apps/runtime/dist/db/migrations/control/meta/0002_snapshot.json +607 -0
- package/apps/runtime/dist/db/migrations/control/meta/0003_snapshot.json +311 -0
- package/apps/runtime/dist/db/migrations/control/meta/0004_snapshot.json +350 -0
- package/apps/runtime/dist/db/migrations/control/meta/_journal.json +41 -0
- package/apps/runtime/dist/db/migrations/tenant/0000_eminent_freak.sql +188 -0
- package/apps/runtime/dist/db/migrations/tenant/0001_salty_master_chief.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0002_cloudy_firebird.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0003_brown_warbound.sql +52 -0
- package/apps/runtime/dist/db/migrations/tenant/0004_romantic_nocturne.sql +6 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0000_snapshot.json +1323 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0001_snapshot.json +1330 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0002_snapshot.json +1337 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0003_snapshot.json +1605 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0004_snapshot.json +1645 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +41 -0
- package/apps/runtime/dist/db/schema.js +278 -0
- package/apps/runtime/dist/documents/parse.js +230 -0
- package/apps/runtime/dist/engenty/connections-external/build-connector.js +193 -0
- package/apps/runtime/dist/engenty/connections-external/errors.js +11 -0
- package/apps/runtime/dist/engenty/connections-external/import-service.js +270 -0
- package/apps/runtime/dist/engenty/connections-external/importer/classify.js +34 -0
- package/apps/runtime/dist/engenty/connections-external/importer/map-auth.js +185 -0
- package/apps/runtime/dist/engenty/connections-external/importer/normalize-mcp.js +63 -0
- package/apps/runtime/dist/engenty/connections-external/importer/normalize-openapi.js +130 -0
- package/apps/runtime/dist/engenty/connections-external/invoke/http-invoker.js +143 -0
- package/apps/runtime/dist/engenty/connections-external/invoke/mcp-client.js +143 -0
- package/apps/runtime/dist/engenty/connections-external/net/guarded-fetch.js +119 -0
- package/apps/runtime/dist/engenty/connections-external/oauth-dcr.js +88 -0
- package/apps/runtime/dist/engenty/connections-external/registry-client.js +336 -0
- package/apps/runtime/dist/engenty/connections-external/registry-source.js +82 -0
- package/apps/runtime/dist/engenty/connections-external/types.js +7 -0
- package/apps/runtime/dist/engenty/connections-github/connector.js +209 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/calendar.js +359 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/contacts.js +94 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/drive.js +290 -0
- package/apps/runtime/dist/engenty/connections-google/connectors/gmail.js +567 -0
- package/apps/runtime/dist/engenty/connections-google/definitions.js +11 -0
- package/apps/runtime/dist/engenty/connections-google/shared.js +73 -0
- package/apps/runtime/dist/engenty/connections-hubspot/connector.js +140 -0
- package/apps/runtime/dist/engenty/connections-microsoft/action.js +17 -0
- package/apps/runtime/dist/engenty/connections-microsoft/graph.js +114 -0
- package/apps/runtime/dist/engenty/connections-microsoft/onedrive.js +286 -0
- package/apps/runtime/dist/engenty/connections-microsoft/outlook.js +464 -0
- package/apps/runtime/dist/engenty/connections-s3/s3.js +328 -0
- package/apps/runtime/dist/engenty/connections-sdk/files-capability.js +86 -0
- package/apps/runtime/dist/engenty/connections-sdk/oauth2.js +150 -0
- package/apps/runtime/dist/engenty/connections-sdk/registry.js +89 -0
- package/apps/runtime/dist/engenty/connections-sdk/storage-capability.js +84 -0
- package/apps/runtime/dist/engenty/connections-sdk/types.js +30 -0
- package/apps/runtime/dist/engenty/connections-slack/connector.js +360 -0
- package/apps/runtime/dist/engenty/csv-import/csv-matrix.js +178 -0
- package/apps/runtime/dist/engenty/csv-import/import-sources.js +87 -0
- package/apps/runtime/dist/engenty/csv-import/parse-csv.js +129 -0
- package/apps/runtime/dist/engenty/csv-import/serialize-csv.js +20 -0
- package/apps/runtime/dist/engenty/csv-import/types.js +1 -0
- package/apps/runtime/dist/engenty/csv-import/xlsx-workbook.js +159 -0
- package/apps/runtime/dist/engenty/doc-converter/interface.js +9 -0
- package/apps/runtime/dist/engenty/doc-converter/page-break.js +92 -0
- package/apps/runtime/dist/engenty/doc-converter/providers/local/index.js +72 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/classifier.js +30 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/index.js +4 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/invoice.js +73 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/receipt.js +63 -0
- package/apps/runtime/dist/engenty/document-scanner/schemas/shared.js +40 -0
- package/apps/runtime/dist/engenty/search-index/chunks.js +164 -0
- package/apps/runtime/dist/engenty/search-index/contracts.js +9 -0
- package/apps/runtime/dist/engenty/shims/connections-sdk.js +39 -0
- package/apps/runtime/dist/engenty/shims/plugin-sdk.js +1 -0
- package/apps/runtime/dist/engenty/shims/web-ingest.js +3 -0
- package/apps/runtime/dist/engenty/web-ingest/ssrf.js +277 -0
- package/apps/runtime/dist/engine/asks.js +60 -0
- package/apps/runtime/dist/engine/events.js +46 -0
- package/apps/runtime/dist/engine/input.js +170 -0
- package/apps/runtime/dist/engine/prepare.js +51 -0
- package/apps/runtime/dist/engine/requirements.js +124 -0
- package/apps/runtime/dist/engine/resources.js +89 -0
- package/apps/runtime/dist/engine/runner.js +560 -0
- package/apps/runtime/dist/engine/steps.js +598 -0
- package/apps/runtime/dist/engine/template.js +183 -0
- package/apps/runtime/dist/engine/types.js +3 -0
- package/apps/runtime/dist/env.js +224 -0
- package/apps/runtime/dist/files/blobs.js +22 -0
- package/apps/runtime/dist/files/objects.js +86 -0
- package/apps/runtime/dist/files/storage.js +95 -0
- package/apps/runtime/dist/geocode.js +58 -0
- package/apps/runtime/dist/harness/claude.js +138 -0
- package/apps/runtime/dist/harness/codex.js +228 -0
- package/apps/runtime/dist/harness/cursor.js +93 -0
- package/apps/runtime/dist/harness/env.js +124 -0
- package/apps/runtime/dist/harness/gemini.js +126 -0
- package/apps/runtime/dist/harness/index.js +99 -0
- package/apps/runtime/dist/harness/model.js +267 -0
- package/apps/runtime/dist/harness/prompt.js +121 -0
- package/apps/runtime/dist/harness/terminal.js +193 -0
- package/apps/runtime/dist/harness/types.js +7 -0
- package/apps/runtime/dist/index.js +76 -0
- package/apps/runtime/dist/limits.js +57 -0
- package/apps/runtime/dist/link-preview.js +59 -0
- package/apps/runtime/dist/manage.js +151 -0
- package/apps/runtime/dist/mcp/auth.js +102 -0
- package/apps/runtime/dist/mcp/bridge.js +59 -0
- package/apps/runtime/dist/mcp/handler.js +42 -0
- package/apps/runtime/dist/mcp/scopes.js +5 -0
- package/apps/runtime/dist/mcp/tools.js +401 -0
- package/apps/runtime/dist/media/ffmpeg.js +121 -0
- package/apps/runtime/dist/media/generate.js +120 -0
- package/apps/runtime/dist/media/marking.js +121 -0
- package/apps/runtime/dist/media/transcribe.js +30 -0
- package/apps/runtime/dist/model-errors.js +3 -0
- package/apps/runtime/dist/models.js +489 -0
- package/apps/runtime/dist/plugin.js +61 -0
- package/apps/runtime/dist/render/chromium.js +85 -0
- package/apps/runtime/dist/render/convert.js +161 -0
- package/apps/runtime/dist/render/downloads.js +277 -0
- package/apps/runtime/dist/render/guard.js +25 -0
- package/apps/runtime/dist/routes/api.js +74 -0
- package/apps/runtime/dist/routes/delivery.js +52 -0
- package/apps/runtime/dist/routes/internal.js +49 -0
- package/apps/runtime/dist/routes/marketplace.js +36 -0
- package/apps/runtime/dist/routes/runs.js +805 -0
- package/apps/runtime/dist/routes/studio.js +702 -0
- package/apps/runtime/dist/routes/wizard-stream.js +30 -0
- package/apps/runtime/dist/running.js +39 -0
- package/apps/runtime/dist/sandbox/agentos.js +191 -0
- package/apps/runtime/dist/sandbox/docker.js +77 -0
- package/apps/runtime/dist/sandbox/index.js +30 -0
- package/apps/runtime/dist/sandbox/types.js +1 -0
- package/apps/runtime/dist/secrets/crypto.js +28 -0
- package/apps/runtime/dist/secrets/signing.js +34 -0
- package/apps/runtime/dist/secrets/vault.js +59 -0
- package/apps/runtime/dist/services/architect.js +92 -0
- package/apps/runtime/dist/services/brand.js +20 -0
- package/apps/runtime/dist/services/cloud.js +52 -0
- package/apps/runtime/dist/services/draft-events.js +27 -0
- package/apps/runtime/dist/services/errors.js +24 -0
- package/apps/runtime/dist/services/files.js +129 -0
- package/apps/runtime/dist/services/links.js +16 -0
- package/apps/runtime/dist/services/marketplace.js +292 -0
- package/apps/runtime/dist/services/package.js +202 -0
- package/apps/runtime/dist/services/profile.js +23 -0
- package/apps/runtime/dist/services/project-files.js +266 -0
- package/apps/runtime/dist/services/project-index.js +109 -0
- package/apps/runtime/dist/services/projects.js +181 -0
- package/apps/runtime/dist/services/runs.js +224 -0
- package/apps/runtime/dist/services/shares.js +129 -0
- package/apps/runtime/dist/services/widgets.js +34 -0
- package/apps/runtime/dist/services/wizards.js +342 -0
- package/apps/runtime/dist/settings.js +16 -0
- package/apps/runtime/dist/store/index.js +279 -0
- package/apps/runtime/dist/tenants/control.js +106 -0
- package/apps/runtime/dist/tenants/tenant.js +26 -0
- package/apps/runtime/dist/tools/browser.js +380 -0
- package/apps/runtime/dist/tools/connector.js +204 -0
- package/apps/runtime/dist/tools/index.js +234 -0
- package/apps/runtime/dist/tools/mail.js +104 -0
- package/apps/runtime/dist/tools/net-guard.js +59 -0
- package/apps/runtime/dist/tools/project.js +53 -0
- package/apps/runtime/dist/tools/shared.js +42 -0
- package/apps/runtime/dist/tools/store.js +238 -0
- package/apps/runtime/dist/update.js +118 -0
- package/apps/runtime/dist/widgets/bundle.js +99 -0
- package/apps/runtime/dist/widgets/render.js +312 -0
- package/apps/runtime/dist/widgets/runtime.js +84 -0
- package/apps/runtime/dist/widgets/script.js +30 -0
- package/apps/runtime/dist/widgets/step.js +192 -0
- package/apps/web/dist/ai-labels/ai-black.svg +20 -0
- package/apps/web/dist/ai-labels/ai-generated-black.svg +31 -0
- package/apps/web/dist/ai-labels/ai-generated-white.svg +32 -0
- package/apps/web/dist/ai-labels/ai-modified-black.svg +30 -0
- package/apps/web/dist/ai-labels/ai-modified-white.svg +31 -0
- package/apps/web/dist/ai-labels/ai-white.svg +21 -0
- package/apps/web/dist/assets/ChangelogDialog-O00vEnbm.js +1 -0
- package/apps/web/dist/assets/ChatPanel-CH9ry0Hp.js +1 -0
- package/apps/web/dist/assets/CreditsDialog-DRzecwUw.js +1 -0
- package/apps/web/dist/assets/EditorPage-BRnBf02Q.js +2 -0
- package/apps/web/dist/assets/FlowPreview-DDOj8IAH.js +1 -0
- package/apps/web/dist/assets/HomePage-CAGTTG3N.js +1 -0
- package/apps/web/dist/assets/ImportWizard-0RRrAnX3.js +1 -0
- package/apps/web/dist/assets/LocalRuntime-BrP-ENHg.css +1 -0
- package/apps/web/dist/assets/LocalRuntime-C-TBYrzs.js +16 -0
- package/apps/web/dist/assets/NewWizardPage-kI90h3_9.js +2 -0
- package/apps/web/dist/assets/PublicRunner-CKRDeIVd.js +1 -0
- package/apps/web/dist/assets/RunnerView-Rc4H8wYH.js +2 -0
- package/apps/web/dist/assets/SettingsPage-CESMuZxq.js +2 -0
- package/apps/web/dist/assets/SetupPage-D1rrYU14.js +1 -0
- package/apps/web/dist/assets/SharePage-COTAmOgh.js +1 -0
- package/apps/web/dist/assets/api-BY28cjGY.js +10 -0
- package/apps/web/dist/assets/arrow-left-UpjOBfQp.js +1 -0
- package/apps/web/dist/assets/arrow-right-CucQycEy.js +1 -0
- package/apps/web/dist/assets/changelog-p3wsaDDS.js +1 -0
- package/apps/web/dist/assets/check-Bjx41xbB.js +1 -0
- package/apps/web/dist/assets/createLucideIcon-DBu2Ovxj.js +1 -0
- package/apps/web/dist/assets/definition-cy7uvY5L.js +55 -0
- package/apps/web/dist/assets/engenty-CWIFpgKq.js +1 -0
- package/apps/web/dist/assets/esm-D1OEhjTK.js +7 -0
- package/apps/web/dist/assets/external-link-CRg6DVdO.js +1 -0
- package/apps/web/dist/assets/fluffy-engenty-CJ3wCQgT.js +456 -0
- package/apps/web/dist/assets/index-CQ_q9iMO.css +1 -0
- package/apps/web/dist/assets/index-D0gxh90t.js +10 -0
- package/apps/web/dist/assets/jsx-runtime-Dk72oS4N.js +1 -0
- package/apps/web/dist/assets/meta-BbSdtTUa.js +1 -0
- package/apps/web/dist/assets/mic-CeqQ89Dj.js +1 -0
- package/apps/web/dist/assets/oss-credits-cPuZUFHD.js +1 -0
- package/apps/web/dist/assets/outputs-D6pxH6ve.js +69 -0
- package/apps/web/dist/assets/plus-HA210wXA.js +1 -0
- package/apps/web/dist/assets/preload-helper-CNEI7N0N.js +1 -0
- package/apps/web/dist/assets/qr-scanner-worker.min-CJaXo3yu.js +98 -0
- package/apps/web/dist/assets/qr-scanner.min-C_UI0gH-.js +1 -0
- package/apps/web/dist/assets/type-BzYgVWKL.js +1 -0
- package/apps/web/dist/assets/ui-Ddwl35A6.js +1 -0
- package/apps/web/dist/assets/upload-DsgLfQ3U.js +1 -0
- package/apps/web/dist/assets/video-Dk1fuTDl.js +1 -0
- package/apps/web/dist/assets/wand-sparkles-Bf97fs8T.js +1 -0
- package/apps/web/dist/embed.js +102 -0
- package/apps/web/dist/favicon.svg +1 -0
- package/apps/web/dist/icons/apple-touch-icon.png +0 -0
- package/apps/web/dist/icons/icon-192.png +0 -0
- package/apps/web/dist/icons/icon-512.png +0 -0
- package/apps/web/dist/icons/icon-maskable-512.png +0 -0
- package/apps/web/dist/index.html +46 -0
- package/apps/web/dist/install.sh +532 -0
- package/apps/web/dist/manifest.webmanifest +20 -0
- package/apps/web/dist/sw.js +15 -0
- package/bin/wizards.mjs +13 -0
- package/node_modules/@engenty-wizards/shared/dist/connectors.d.ts +77 -0
- package/node_modules/@engenty-wizards/shared/dist/connectors.js +2 -0
- package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +1415 -0
- package/node_modules/@engenty-wizards/shared/dist/definition.js +762 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.d.ts +5 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-format.js +132 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.d.ts +11 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns-value.js +209 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.d.ts +532 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.js +216 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.d.ts +3 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/index.js +3 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.d.ts +14 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-lexical.js +166 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.d.ts +33 -0
- package/node_modules/@engenty-wizards/shared/dist/engenty/search-index/catalog-rank.js +99 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.d.ts +35 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-entry.js +86 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-search.d.ts +20 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace-search.js +133 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +298 -0
- package/node_modules/@engenty-wizards/shared/dist/marketplace.js +211 -0
- package/node_modules/@engenty-wizards/shared/dist/merge.d.ts +7 -0
- package/node_modules/@engenty-wizards/shared/dist/merge.js +40 -0
- package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +74 -0
- package/node_modules/@engenty-wizards/shared/dist/projects.js +96 -0
- package/node_modules/@engenty-wizards/shared/dist/run.d.ts +219 -0
- package/node_modules/@engenty-wizards/shared/dist/run.js +1 -0
- package/node_modules/@engenty-wizards/shared/dist/store.d.ts +100 -0
- package/node_modules/@engenty-wizards/shared/dist/store.js +44 -0
- package/node_modules/@engenty-wizards/shared/dist/workspace.d.ts +16 -0
- package/node_modules/@engenty-wizards/shared/dist/workspace.js +51 -0
- package/node_modules/@engenty-wizards/shared/package.json +10 -0
- package/package.json +62 -0
- package/plugin/.claude-plugin/plugin.json +9 -0
- package/plugin/.mcp.json +8 -0
- package/plugin/commands/wizard.md +8 -0
- package/plugin/skills/build-wizard/SKILL.md +27 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-declared import sources: CSV upload (always) plus connections that can
|
|
3
|
+
* produce tabular rows for a domain (secrets / contacts / team).
|
|
4
|
+
*/
|
|
5
|
+
/** File-capable connectors shared by secrets / contacts / team. */
|
|
6
|
+
export const FILE_CONNECTION_IMPORT_SOURCES = [
|
|
7
|
+
{
|
|
8
|
+
kind: "connection",
|
|
9
|
+
connectorId: "google-drive",
|
|
10
|
+
domains: ["secrets", "contacts", "team"],
|
|
11
|
+
requiresCapability: "files",
|
|
12
|
+
fetchMode: "pick_file",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
kind: "connection",
|
|
16
|
+
connectorId: "microsoft-onedrive",
|
|
17
|
+
domains: ["secrets", "contacts", "team"],
|
|
18
|
+
requiresCapability: "files",
|
|
19
|
+
fetchMode: "pick_file",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
kind: "connection",
|
|
23
|
+
connectorId: "local-files",
|
|
24
|
+
domains: ["secrets", "contacts", "team"],
|
|
25
|
+
requiresCapability: "files",
|
|
26
|
+
fetchMode: "pick_file",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
kind: "connection",
|
|
30
|
+
connectorId: "s3",
|
|
31
|
+
domains: ["secrets", "contacts", "team"],
|
|
32
|
+
requiresCapability: "files",
|
|
33
|
+
fetchMode: "pick_file",
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
/** Typed CRM / people connectors (contacts domain only). */
|
|
37
|
+
export const TYPED_CONNECTION_IMPORT_SOURCES = [
|
|
38
|
+
{
|
|
39
|
+
kind: "connection",
|
|
40
|
+
connectorId: "google-contacts",
|
|
41
|
+
domains: ["contacts"],
|
|
42
|
+
requiresCapability: "action",
|
|
43
|
+
fetchMode: "list_records",
|
|
44
|
+
listActionId: "list_contacts",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
kind: "connection",
|
|
48
|
+
connectorId: "hubspot",
|
|
49
|
+
domains: ["contacts"],
|
|
50
|
+
requiresCapability: "action",
|
|
51
|
+
fetchMode: "list_records",
|
|
52
|
+
listActionId: "list_contacts",
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
export const ALL_CONNECTION_IMPORT_SOURCES = [
|
|
56
|
+
...FILE_CONNECTION_IMPORT_SOURCES,
|
|
57
|
+
...TYPED_CONNECTION_IMPORT_SOURCES,
|
|
58
|
+
];
|
|
59
|
+
/** Sources registered for a module domain (file + typed). */
|
|
60
|
+
export function connectionImportSourcesForDomain(domain, extras = []) {
|
|
61
|
+
const base = domain === "contacts"
|
|
62
|
+
? ALL_CONNECTION_IMPORT_SOURCES
|
|
63
|
+
: FILE_CONNECTION_IMPORT_SOURCES;
|
|
64
|
+
const merged = [...base, ...extras];
|
|
65
|
+
const byId = new Map();
|
|
66
|
+
for (const source of merged) {
|
|
67
|
+
if (source.domains.includes(domain)) {
|
|
68
|
+
byId.set(source.connectorId, source);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return [...byId.values()];
|
|
72
|
+
}
|
|
73
|
+
/** MIME / extension filter for importable connection files. */
|
|
74
|
+
export function isImportableConnectionFile(entry) {
|
|
75
|
+
if (entry.kind !== "file") {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
const mime = (entry.mimeType ?? "").toLowerCase();
|
|
79
|
+
if (mime === "text/csv" ||
|
|
80
|
+
mime === "text/tab-separated-values" ||
|
|
81
|
+
mime === "text/plain" ||
|
|
82
|
+
mime === "application/vnd.google-apps.spreadsheet") {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
const lower = entry.name.toLowerCase();
|
|
86
|
+
return (lower.endsWith(".csv") || lower.endsWith(".tsv") || lower.endsWith(".txt"));
|
|
87
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
export function parseCSV(csvContent) {
|
|
2
|
+
const delimiter = detectDelimiter(csvContent);
|
|
3
|
+
const rows = parseCSVRows(csvContent, delimiter);
|
|
4
|
+
if (rows.length === 0) {
|
|
5
|
+
throw new Error("CSV file is empty");
|
|
6
|
+
}
|
|
7
|
+
const headers = rows[0];
|
|
8
|
+
const dataRows = rows.slice(1);
|
|
9
|
+
return { headers, rows: dataRows, totalRows: dataRows.length };
|
|
10
|
+
}
|
|
11
|
+
function pushField(row, field, quoted) {
|
|
12
|
+
// Quoted fields keep interior whitespace; unquoted fields are trimmed.
|
|
13
|
+
row.push(quoted ? field : field.trim());
|
|
14
|
+
}
|
|
15
|
+
/** Parse delimited text into a raw matrix (no header/data split). */
|
|
16
|
+
export function parseCSVRows(csvContent, delimiter) {
|
|
17
|
+
const rows = [];
|
|
18
|
+
let currentRow = [];
|
|
19
|
+
let currentField = "";
|
|
20
|
+
let inQuotes = false;
|
|
21
|
+
let fieldWasQuoted = false;
|
|
22
|
+
let i = 0;
|
|
23
|
+
while (i < csvContent.length) {
|
|
24
|
+
const char = csvContent[i];
|
|
25
|
+
const nextChar = csvContent[i + 1];
|
|
26
|
+
if (char === '"') {
|
|
27
|
+
if (inQuotes && nextChar === '"') {
|
|
28
|
+
currentField += '"';
|
|
29
|
+
i += 2;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
inQuotes = !inQuotes;
|
|
33
|
+
fieldWasQuoted = true;
|
|
34
|
+
// Delimiter quotes are not part of the cell value (RFC 4180 / Sheets TSV).
|
|
35
|
+
i++;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (char === delimiter && !inQuotes) {
|
|
39
|
+
pushField(currentRow, currentField, fieldWasQuoted);
|
|
40
|
+
currentField = "";
|
|
41
|
+
fieldWasQuoted = false;
|
|
42
|
+
i++;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if ((char === "\n" || (char === "\r" && nextChar === "\n")) && !inQuotes) {
|
|
46
|
+
if (char === "\r" && nextChar === "\n") {
|
|
47
|
+
i += 2;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
i++;
|
|
51
|
+
}
|
|
52
|
+
pushField(currentRow, currentField, fieldWasQuoted);
|
|
53
|
+
if (currentRow.length > 0 &&
|
|
54
|
+
currentRow.some((f) => f.trim().length > 0)) {
|
|
55
|
+
rows.push(currentRow);
|
|
56
|
+
}
|
|
57
|
+
currentRow = [];
|
|
58
|
+
currentField = "";
|
|
59
|
+
fieldWasQuoted = false;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
currentField += char;
|
|
63
|
+
i++;
|
|
64
|
+
}
|
|
65
|
+
if (currentField.length > 0 || currentRow.length > 0) {
|
|
66
|
+
pushField(currentRow, currentField, fieldWasQuoted);
|
|
67
|
+
if (currentRow.length > 0 && currentRow.some((f) => f.trim().length > 0)) {
|
|
68
|
+
rows.push(currentRow);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return rows;
|
|
72
|
+
}
|
|
73
|
+
export function detectDelimiter(csvContent) {
|
|
74
|
+
let firstRow = "";
|
|
75
|
+
let inQuotes = false;
|
|
76
|
+
for (let i = 0; i < csvContent.length; i++) {
|
|
77
|
+
const char = csvContent[i];
|
|
78
|
+
const nextChar = csvContent[i + 1];
|
|
79
|
+
if (char === '"') {
|
|
80
|
+
if (inQuotes && nextChar === '"') {
|
|
81
|
+
firstRow += char;
|
|
82
|
+
i++;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
inQuotes = !inQuotes;
|
|
86
|
+
firstRow += char;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if ((char === "\n" || (char === "\r" && nextChar === "\n")) && !inQuotes) {
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
firstRow += char;
|
|
93
|
+
}
|
|
94
|
+
let commaCount = 0;
|
|
95
|
+
let semicolonCount = 0;
|
|
96
|
+
let tabCount = 0;
|
|
97
|
+
inQuotes = false;
|
|
98
|
+
for (let i = 0; i < firstRow.length; i++) {
|
|
99
|
+
const char = firstRow[i];
|
|
100
|
+
const nextChar = firstRow[i + 1];
|
|
101
|
+
if (char === '"') {
|
|
102
|
+
if (inQuotes && nextChar === '"') {
|
|
103
|
+
i++;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
inQuotes = !inQuotes;
|
|
107
|
+
}
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (!inQuotes) {
|
|
111
|
+
if (char === ",") {
|
|
112
|
+
commaCount++;
|
|
113
|
+
}
|
|
114
|
+
if (char === ";") {
|
|
115
|
+
semicolonCount++;
|
|
116
|
+
}
|
|
117
|
+
if (char === "\t") {
|
|
118
|
+
tabCount++;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (semicolonCount > commaCount && semicolonCount > tabCount) {
|
|
123
|
+
return ";";
|
|
124
|
+
}
|
|
125
|
+
if (tabCount > commaCount) {
|
|
126
|
+
return "\t";
|
|
127
|
+
}
|
|
128
|
+
return ",";
|
|
129
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Escape a single CSV/TSV field for the given delimiter. */
|
|
2
|
+
export function escapeDelimitedField(value, delimiter) {
|
|
3
|
+
if (value.includes(delimiter) ||
|
|
4
|
+
value.includes('"') ||
|
|
5
|
+
value.includes("\n") ||
|
|
6
|
+
value.includes("\r")) {
|
|
7
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
/** Serialize a header + data matrix to delimited text (LF endings). */
|
|
12
|
+
export function serializeDelimitedMatrix(headers, rows, delimiter) {
|
|
13
|
+
const lines = [
|
|
14
|
+
headers.map((h) => escapeDelimitedField(h, delimiter)).join(delimiter),
|
|
15
|
+
...rows.map((row) => headers
|
|
16
|
+
.map((_, index) => escapeDelimitedField(row[index] ?? "", delimiter))
|
|
17
|
+
.join(delimiter)),
|
|
18
|
+
];
|
|
19
|
+
return `${lines.join("\n")}\n`;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read limits, per sheet.
|
|
3
|
+
*
|
|
4
|
+
* Parsing is not the cost — unzipping the file is, and that is paid whatever we
|
|
5
|
+
* do with it. These exist so one pathological sheet cannot hold a million
|
|
6
|
+
* strings in memory. When a limit bites, the sheet says so; it never trims in
|
|
7
|
+
* silence.
|
|
8
|
+
*/
|
|
9
|
+
export const XLSX_MAX_ROWS = 10_000;
|
|
10
|
+
export const XLSX_MAX_COLUMNS = 256;
|
|
11
|
+
/** True when the sheet holds more than was read. */
|
|
12
|
+
export function isXlsxSheetTruncated(sheet) {
|
|
13
|
+
return (sheet.sourceRowCount > sheet.matrix.rows.length ||
|
|
14
|
+
sheet.sourceColumnCount > sheet.matrix.columns.length);
|
|
15
|
+
}
|
|
16
|
+
/** 0-based index → spreadsheet column letters: 0 → `A`, 26 → `AA`. */
|
|
17
|
+
export function columnLetter(index) {
|
|
18
|
+
let remaining = index;
|
|
19
|
+
let letters = "";
|
|
20
|
+
do {
|
|
21
|
+
letters = String.fromCharCode(65 + (remaining % 26)) + letters;
|
|
22
|
+
remaining = Math.floor(remaining / 26) - 1;
|
|
23
|
+
} while (remaining >= 0);
|
|
24
|
+
return letters;
|
|
25
|
+
}
|
|
26
|
+
/** Excel stores naive datetimes; exceljs hands them back as UTC instants. */
|
|
27
|
+
function formatDate(value) {
|
|
28
|
+
if (Number.isNaN(value.getTime())) {
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
const date = value.toISOString().slice(0, 10);
|
|
32
|
+
const time = value.toISOString().slice(11, 16);
|
|
33
|
+
return time === "00:00" ? date : `${date} ${time}`;
|
|
34
|
+
}
|
|
35
|
+
function isDate(value) {
|
|
36
|
+
return value instanceof Date;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* One property off a value that may not be an object.
|
|
40
|
+
*
|
|
41
|
+
* A plain reader rather than a type guard: exceljs models a cell as a union of
|
|
42
|
+
* a dozen shapes, and narrowing that union one key at a time fights the
|
|
43
|
+
* compiler for no benefit — every branch below wants the same "is this key
|
|
44
|
+
* here, and what is in it" question answered.
|
|
45
|
+
*/
|
|
46
|
+
function prop(value, key) {
|
|
47
|
+
return typeof value === "object" && value !== null
|
|
48
|
+
? value[key]
|
|
49
|
+
: undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A cell as the text Excel would show in it.
|
|
53
|
+
*
|
|
54
|
+
* The formula case is the one with a decision in it: a workbook carries the
|
|
55
|
+
* last computed result alongside the formula, and that cached value is what
|
|
56
|
+
* Excel displays. When a file was written by a tool that never calculated, the
|
|
57
|
+
* result is missing — then the formula itself is shown, because a blank cell
|
|
58
|
+
* would claim the sheet is empty where it is merely uncomputed.
|
|
59
|
+
*/
|
|
60
|
+
export function xlsxCellText(value) {
|
|
61
|
+
if (value === null || value === undefined) {
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
if (typeof value === "string") {
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
// Excel shows booleans uppercase, and so does anything reading its CSV.
|
|
68
|
+
if (typeof value === "boolean") {
|
|
69
|
+
return value ? "TRUE" : "FALSE";
|
|
70
|
+
}
|
|
71
|
+
if (typeof value === "number") {
|
|
72
|
+
return String(value);
|
|
73
|
+
}
|
|
74
|
+
if (isDate(value)) {
|
|
75
|
+
return formatDate(value);
|
|
76
|
+
}
|
|
77
|
+
const error = prop(value, "error");
|
|
78
|
+
if (error !== undefined) {
|
|
79
|
+
return String(error);
|
|
80
|
+
}
|
|
81
|
+
const richText = prop(value, "richText");
|
|
82
|
+
if (Array.isArray(richText)) {
|
|
83
|
+
return richText.map((run) => String(prop(run, "text") ?? "")).join("");
|
|
84
|
+
}
|
|
85
|
+
const formula = prop(value, "formula") ?? prop(value, "sharedFormula");
|
|
86
|
+
if (formula !== undefined) {
|
|
87
|
+
const result = prop(value, "result");
|
|
88
|
+
if (result !== undefined && result !== null) {
|
|
89
|
+
return xlsxCellText(result);
|
|
90
|
+
}
|
|
91
|
+
return `=${String(formula)}`;
|
|
92
|
+
}
|
|
93
|
+
// A hyperlink renders as its label; the target is not text the sheet shows.
|
|
94
|
+
const text = prop(value, "text");
|
|
95
|
+
if (text !== undefined) {
|
|
96
|
+
return String(text);
|
|
97
|
+
}
|
|
98
|
+
const hyperlink = prop(value, "hyperlink");
|
|
99
|
+
if (hyperlink !== undefined) {
|
|
100
|
+
return String(hyperlink);
|
|
101
|
+
}
|
|
102
|
+
return String(value);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* exceljs ships as CommonJS, so the namespace hides under `default` in some
|
|
106
|
+
* builds and is the module object itself in others.
|
|
107
|
+
*/
|
|
108
|
+
function unwrap(mod) {
|
|
109
|
+
const candidate = prop(mod, "default") ?? mod;
|
|
110
|
+
return (prop(candidate, "Workbook")
|
|
111
|
+
? candidate
|
|
112
|
+
: mod);
|
|
113
|
+
}
|
|
114
|
+
function readSheet(worksheet, mergeType) {
|
|
115
|
+
// `rowCount` and `columnCount` are computed getters that walk every row —
|
|
116
|
+
// reading either one inside the scan turns a 5ms pass into a 60s one.
|
|
117
|
+
const sourceRowCount = worksheet.rowCount;
|
|
118
|
+
const sourceColumnCount = worksheet.columnCount;
|
|
119
|
+
const height = Math.min(sourceRowCount, XLSX_MAX_ROWS);
|
|
120
|
+
const width = Math.min(sourceColumnCount, XLSX_MAX_COLUMNS);
|
|
121
|
+
const rows = [];
|
|
122
|
+
for (let rowIndex = 1; rowIndex <= height; rowIndex++) {
|
|
123
|
+
const line = new Array(width).fill("");
|
|
124
|
+
worksheet.getRow(rowIndex).eachCell({ includeEmpty: true }, (cell, col) => {
|
|
125
|
+
if (col > width) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
// A merged range repeats the master's value in every cell it covers.
|
|
129
|
+
// Written out as-is, one banner becomes three; only the master keeps it.
|
|
130
|
+
line[col - 1] = cell.type === mergeType ? "" : xlsxCellText(cell.value);
|
|
131
|
+
});
|
|
132
|
+
rows.push(line);
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
hidden: worksheet.state !== "visible",
|
|
136
|
+
matrix: {
|
|
137
|
+
columns: Array.from({ length: width }, (_, index) => columnLetter(index)),
|
|
138
|
+
// A worksheet has no delimiter. It gets one only because the matrix is
|
|
139
|
+
// also what "copy as text" serializes through.
|
|
140
|
+
delimiter: ",",
|
|
141
|
+
raggedRows: 0,
|
|
142
|
+
rows,
|
|
143
|
+
},
|
|
144
|
+
name: worksheet.name,
|
|
145
|
+
sourceColumnCount,
|
|
146
|
+
sourceRowCount,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** Bytes → sheets. Rejects with exceljs's own error when the file is not xlsx. */
|
|
150
|
+
export async function readXlsxWorkbook(data) {
|
|
151
|
+
const excel = unwrap(await import("exceljs"));
|
|
152
|
+
const workbook = new excel.Workbook();
|
|
153
|
+
const buffer = data instanceof Uint8Array
|
|
154
|
+
? data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength)
|
|
155
|
+
: data;
|
|
156
|
+
await workbook.xlsx.load(buffer);
|
|
157
|
+
const mergeType = excel.ValueType.Merge;
|
|
158
|
+
return { sheets: workbook.worksheets.map((ws) => readSheet(ws, mergeType)) };
|
|
159
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document Converter — Provider interface.
|
|
3
|
+
*
|
|
4
|
+
* Following the banking provider architecture:
|
|
5
|
+
* - Abstract interface defines the contract
|
|
6
|
+
* - Concrete providers implement for specific services
|
|
7
|
+
* - Facade class selects the right provider
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** Empty HTML sentinel between page bodies. Must be explicitly closed (not `/>`). */
|
|
2
|
+
export const PAGE_BREAK_TAG = "page-break";
|
|
3
|
+
function escapeAttr(value) {
|
|
4
|
+
return value.replaceAll("&", "&").replaceAll('"', """);
|
|
5
|
+
}
|
|
6
|
+
/** `<page-break number="12" total="240"></page-break>` */
|
|
7
|
+
export function formatPageBreak(attrs) {
|
|
8
|
+
const parts = [`number="${attrs.number}"`];
|
|
9
|
+
if (typeof attrs.total === "number" && attrs.total > 0) {
|
|
10
|
+
parts.push(`total="${attrs.total}"`);
|
|
11
|
+
}
|
|
12
|
+
const printed = attrs.printed?.trim();
|
|
13
|
+
if (printed) {
|
|
14
|
+
parts.push(`printed="${escapeAttr(printed)}"`);
|
|
15
|
+
}
|
|
16
|
+
return `<${PAGE_BREAK_TAG} ${parts.join(" ")}></${PAGE_BREAK_TAG}>`;
|
|
17
|
+
}
|
|
18
|
+
export function joinPagesWithBreaks(pages, total) {
|
|
19
|
+
const resolvedTotal = total && total > 0 ? total : pages.length;
|
|
20
|
+
const parts = [];
|
|
21
|
+
for (const page of pages) {
|
|
22
|
+
const markdown = page.markdown.trim();
|
|
23
|
+
if (!markdown) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
parts.push(formatPageBreak({
|
|
27
|
+
number: page.number,
|
|
28
|
+
total: resolvedTotal,
|
|
29
|
+
printed: page.printed,
|
|
30
|
+
}));
|
|
31
|
+
parts.push(markdown);
|
|
32
|
+
}
|
|
33
|
+
return parts.join("\n\n").trim();
|
|
34
|
+
}
|
|
35
|
+
/** Join per-page parser output, falling back to a concatenated blob. */
|
|
36
|
+
export function markdownFromPagedParseResult(input) {
|
|
37
|
+
const slices = input.pages.map((page, index) => ({
|
|
38
|
+
number: page.number ?? index + 1,
|
|
39
|
+
markdown: (page.markdown ?? page.text ?? "").trim(),
|
|
40
|
+
...(page.printed?.trim() ? { printed: page.printed.trim() } : {}),
|
|
41
|
+
}));
|
|
42
|
+
const joined = joinPagesWithBreaks(slices, input.total ?? (input.pages.length > 0 ? input.pages.length : undefined));
|
|
43
|
+
return joined || (input.fallback ?? "").trim();
|
|
44
|
+
}
|
|
45
|
+
const PAGE_BREAK_RE = /<page-break\b([^>]*)><\/page-break>/gi;
|
|
46
|
+
function parseAttrs(raw) {
|
|
47
|
+
const attrs = {};
|
|
48
|
+
const re = /([a-zA-Z_:][\w:.-]*)\s*=\s*"([^"]*)"/g;
|
|
49
|
+
for (const match of raw.matchAll(re)) {
|
|
50
|
+
const name = match[1];
|
|
51
|
+
const value = match[2];
|
|
52
|
+
if (name && value != null) {
|
|
53
|
+
attrs[name] = value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return attrs;
|
|
57
|
+
}
|
|
58
|
+
/** Split sidecar markdown on page-break sentinels. Untagged text is one page. */
|
|
59
|
+
export function splitMarkdownByPageBreaks(markdown) {
|
|
60
|
+
const source = markdown.trim();
|
|
61
|
+
if (!source) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
const matches = [...source.matchAll(PAGE_BREAK_RE)];
|
|
65
|
+
if (matches.length === 0) {
|
|
66
|
+
return [{ markdown: source, number: 1 }];
|
|
67
|
+
}
|
|
68
|
+
const pages = [];
|
|
69
|
+
for (let index = 0; index < matches.length; index++) {
|
|
70
|
+
const match = matches[index];
|
|
71
|
+
if (!match || match.index == null) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const start = match.index + match[0].length;
|
|
75
|
+
const end = matches[index + 1]?.index ?? source.length;
|
|
76
|
+
const body = source.slice(start, end).trim();
|
|
77
|
+
if (!body) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const attrs = parseAttrs(match[1] ?? "");
|
|
81
|
+
const number = Number.parseInt(attrs.number ?? "", 10);
|
|
82
|
+
const total = Number.parseInt(attrs.total ?? "", 10);
|
|
83
|
+
const printed = attrs.printed?.trim();
|
|
84
|
+
pages.push({
|
|
85
|
+
markdown: body,
|
|
86
|
+
number: Number.isFinite(number) && number > 0 ? number : index + 1,
|
|
87
|
+
...(printed ? { printed } : {}),
|
|
88
|
+
...(Number.isFinite(total) && total > 0 ? { total } : {}),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return pages;
|
|
92
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local provider — Uses pdf-parse for PDFs and mammoth for DOCX.
|
|
3
|
+
*
|
|
4
|
+
* No external API calls needed. Good as fallback.
|
|
5
|
+
*/
|
|
6
|
+
import { htmlToMarkdown } from "../../../shims/web-ingest.js";
|
|
7
|
+
import { markdownFromPagedParseResult } from "../../page-break.js";
|
|
8
|
+
const SUPPORTED_TYPES = [
|
|
9
|
+
"application/pdf",
|
|
10
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
11
|
+
"application/msword",
|
|
12
|
+
"text/plain",
|
|
13
|
+
"text/markdown",
|
|
14
|
+
];
|
|
15
|
+
export class LocalProvider {
|
|
16
|
+
id = "local";
|
|
17
|
+
name = "Local (pdf-parse + mammoth)";
|
|
18
|
+
supportedTypes = SUPPORTED_TYPES;
|
|
19
|
+
canConvert(mimeType) {
|
|
20
|
+
return SUPPORTED_TYPES.includes(mimeType);
|
|
21
|
+
}
|
|
22
|
+
async convert(data, filename, mimeType, _options) {
|
|
23
|
+
let markdown = "";
|
|
24
|
+
const metadata = {};
|
|
25
|
+
if (mimeType === "application/pdf") {
|
|
26
|
+
const { PDFParse } = await import("pdf-parse");
|
|
27
|
+
const buffer = Buffer.from(data);
|
|
28
|
+
const parser = new PDFParse({ data: buffer });
|
|
29
|
+
try {
|
|
30
|
+
const textResult = await parser.getText({ pageJoiner: "" });
|
|
31
|
+
const infoResult = await parser.getInfo();
|
|
32
|
+
markdown = markdownFromPagedParseResult({
|
|
33
|
+
fallback: textResult.text,
|
|
34
|
+
pages: textResult.pages.map((page) => ({
|
|
35
|
+
number: page.num,
|
|
36
|
+
text: page.text,
|
|
37
|
+
})),
|
|
38
|
+
total: textResult.total,
|
|
39
|
+
});
|
|
40
|
+
metadata.page_count = textResult.total;
|
|
41
|
+
const info = infoResult.info;
|
|
42
|
+
metadata.title = info?.Title;
|
|
43
|
+
metadata.author = info?.Author;
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await parser.destroy();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else if (mimeType ===
|
|
50
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" ||
|
|
51
|
+
mimeType === "application/msword") {
|
|
52
|
+
const mammoth = await import("mammoth");
|
|
53
|
+
const buffer = Buffer.from(data);
|
|
54
|
+
const result = await mammoth.convertToHtml({ buffer });
|
|
55
|
+
// Simple HTML to markdown conversion (basic)
|
|
56
|
+
markdown = htmlToMarkdown(result.value);
|
|
57
|
+
}
|
|
58
|
+
else if (mimeType === "text/plain" || mimeType === "text/markdown") {
|
|
59
|
+
markdown = new TextDecoder().decode(data);
|
|
60
|
+
}
|
|
61
|
+
metadata.word_count = markdown.split(/\s+/).filter(Boolean).length;
|
|
62
|
+
return {
|
|
63
|
+
markdown,
|
|
64
|
+
metadata,
|
|
65
|
+
source: {
|
|
66
|
+
filename,
|
|
67
|
+
mime_type: mimeType,
|
|
68
|
+
size_bytes: data.byteLength,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { documentTypeSchema } from "./shared.js";
|
|
3
|
+
/**
|
|
4
|
+
* Document classifier schema — lightweight extraction for routing.
|
|
5
|
+
* Determines document type + metadata before full extraction.
|
|
6
|
+
*/
|
|
7
|
+
export const classifierSchema = z.object({
|
|
8
|
+
document_type: documentTypeSchema.describe("Classify this document: 'invoice' (bill requesting payment), 'receipt' (proof of payment), or 'other' (non-financial)."),
|
|
9
|
+
title: z
|
|
10
|
+
.string()
|
|
11
|
+
.nullable()
|
|
12
|
+
.describe("A descriptive, meaningful title for this document. Include key identifying information like document number, company names, dates. Examples: 'Invoice INV-2024-001 from Acme Corp', 'Receipt from Starbucks 2024-03-15'. Do NOT use generic names."),
|
|
13
|
+
summary: z
|
|
14
|
+
.string()
|
|
15
|
+
.nullable()
|
|
16
|
+
.describe("A brief, one-sentence summary of the document's main purpose or content."),
|
|
17
|
+
tags: z
|
|
18
|
+
.array(z.string())
|
|
19
|
+
.max(5)
|
|
20
|
+
.nullable()
|
|
21
|
+
.describe("Up to 5 relevant keywords for classifying and searching (e.g., 'Invoice', 'Acme Corp', 'Consulting')."),
|
|
22
|
+
date: z
|
|
23
|
+
.string()
|
|
24
|
+
.nullable()
|
|
25
|
+
.describe("The most relevant date in ISO 8601 format (YYYY-MM-DD) — issue date, purchase date, etc."),
|
|
26
|
+
language: z
|
|
27
|
+
.string()
|
|
28
|
+
.nullable()
|
|
29
|
+
.describe("The language of the document (e.g., 'english', 'german', 'french')"),
|
|
30
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { documentTypeDescription, documentTypeSchema, lineItemSchema, taxTypeSchema, } from "./shared.js";
|
|
3
|
+
/**
|
|
4
|
+
* Incoming invoice extraction schema.
|
|
5
|
+
* Uses Zod `.describe()` annotations as LLM instructions.
|
|
6
|
+
* Designed for multi-modal OCR extraction via Mistral/Gemini.
|
|
7
|
+
*/
|
|
8
|
+
export const invoiceSchema = z.object({
|
|
9
|
+
document_type: documentTypeSchema.describe(documentTypeDescription),
|
|
10
|
+
invoice_number: z
|
|
11
|
+
.string()
|
|
12
|
+
.nullable()
|
|
13
|
+
.describe("Unique identifier for the invoice (e.g., RE-2024-001)"),
|
|
14
|
+
invoice_date: z
|
|
15
|
+
.string()
|
|
16
|
+
.nullable()
|
|
17
|
+
.describe("Date of invoice in ISO 8601 format (YYYY-MM-DD)"),
|
|
18
|
+
due_date: z
|
|
19
|
+
.string()
|
|
20
|
+
.nullable()
|
|
21
|
+
.describe("Payment due date in ISO 8601 format (YYYY-MM-DD)"),
|
|
22
|
+
total_amount: z
|
|
23
|
+
.number()
|
|
24
|
+
.nullable()
|
|
25
|
+
.describe("Total amount for the invoice in EUR. Null if document_type is 'other'."),
|
|
26
|
+
subtotal_amount: z.number().nullable().describe("Subtotal amount before tax"),
|
|
27
|
+
tax_amount: z.number().nullable().describe("Tax amount for the invoice"),
|
|
28
|
+
tax_rate: z
|
|
29
|
+
.number()
|
|
30
|
+
.nullable()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("Tax rate as a percentage value (e.g., 20 for 20%)"),
|
|
33
|
+
tax_type: taxTypeSchema
|
|
34
|
+
.nullable()
|
|
35
|
+
.describe("The type of tax applied: VAT, Sales Tax, GST, etc. Infer from country/context if not specified."),
|
|
36
|
+
vendor_name: z
|
|
37
|
+
.string()
|
|
38
|
+
.nullable()
|
|
39
|
+
.describe("The legal registered business name of the company issuing the invoice. Look for names with entity types like 'Inc.', 'Ltd', 'GmbH', 'e.U.', etc. Prioritize the name issuing the invoice, not subsidiaries."),
|
|
40
|
+
vendor_address: z
|
|
41
|
+
.string()
|
|
42
|
+
.nullable()
|
|
43
|
+
.describe("Complete address of the vendor"),
|
|
44
|
+
vendor_email: z.string().nullable().describe("Email of the vendor/seller"),
|
|
45
|
+
vendor_website: z
|
|
46
|
+
.string()
|
|
47
|
+
.nullable()
|
|
48
|
+
.describe("Root domain of the vendor (e.g., 'example.com'). Infer from email if not explicit."),
|
|
49
|
+
vendor_vat_id: z
|
|
50
|
+
.string()
|
|
51
|
+
.nullable()
|
|
52
|
+
.describe("VAT ID of the vendor (e.g., ATU12345678, DE123456789). Look for UID, USt-IdNr., or similar."),
|
|
53
|
+
customer_name: z
|
|
54
|
+
.string()
|
|
55
|
+
.nullable()
|
|
56
|
+
.describe("Name of the customer/buyer (the recipient of this invoice)"),
|
|
57
|
+
customer_address: z
|
|
58
|
+
.string()
|
|
59
|
+
.nullable()
|
|
60
|
+
.describe("Complete address of the customer"),
|
|
61
|
+
line_items: z
|
|
62
|
+
.array(lineItemSchema)
|
|
63
|
+
.describe("Array of items/services listed in the invoice"),
|
|
64
|
+
payment_instructions: z
|
|
65
|
+
.string()
|
|
66
|
+
.nullable()
|
|
67
|
+
.describe("Payment terms, bank details, or instructions (IBAN, BIC, etc.)"),
|
|
68
|
+
notes: z.string().nullable().describe("Additional notes or comments"),
|
|
69
|
+
language: z
|
|
70
|
+
.string()
|
|
71
|
+
.nullable()
|
|
72
|
+
.describe("The language of the document (e.g., 'english', 'german', 'french')"),
|
|
73
|
+
});
|