aiex-cli 0.0.2-beta.2 → 0.0.2-beta.4
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/cli.mjs +295 -218
- package/dist/{doctor-collector-BhNgLdrJ.mjs → doctor-collector-DoJqOYMT.mjs} +1 -1
- package/dist/index.mjs +1 -1
- package/dist/web/assets/AISettings-BgwAdAIK.js +346 -0
- package/dist/web/assets/ExtractRunner-BxI-y6zS.js +1 -0
- package/dist/web/assets/{ExtractionViewer-D7tghmR-.js → ExtractionViewer-Dxgbk3y5.js} +1 -1
- package/dist/web/assets/{JsonSchemaEditor-DXhYW-Un.js → JsonSchemaEditor-ul3bZNBq.js} +3 -3
- package/dist/web/assets/{api-client-CIC2X8_4.js → api-client-BwMoRXRu.js} +1 -1
- package/dist/web/assets/{cssMode-CCz1uj8b.js → cssMode-BJcNHjlk.js} +1 -1
- package/dist/web/assets/{editor.main-DOue-nGf.js → editor.main-DQNDtAJT.js} +2 -2
- package/dist/web/assets/{freemarker2-C87H7V8i.js → freemarker2-S3U7WteK.js} +1 -1
- package/dist/web/assets/{handlebars-TLnoktZW.js → handlebars-BrE9AAwL.js} +1 -1
- package/dist/web/assets/{html-Rewbtgcp.js → html-C6Vb0qjf.js} +1 -1
- package/dist/web/assets/{htmlMode-Cr9y3YUi.js → htmlMode-D6ZrqWr1.js} +1 -1
- package/dist/web/assets/{index-FPVIOydC.js → index-e8dWRIEv.js} +7 -7
- package/dist/web/assets/{javascript-BO8DPECx.js → javascript-DB-UTK4i.js} +1 -1
- package/dist/web/assets/{jsonMode-B78m_Y1l.js → jsonMode-w2VFiNNs.js} +1 -1
- package/dist/web/assets/{liquid-CDp_8YUE.js → liquid-1XTLVrg3.js} +1 -1
- package/dist/web/assets/{mdx-CeR1GULE.js → mdx-C4k_4MX5.js} +1 -1
- package/dist/web/assets/{monaco.contribution-tCitzj1_.js → monaco.contribution-DrrjJ0Xr.js} +2 -2
- package/dist/web/assets/{python-DWmB1hQ6.js → python-DU-NBP37.js} +1 -1
- package/dist/web/assets/{razor-BVk762Lq.js → razor-CDS0MJZV.js} +1 -1
- package/dist/web/assets/select-Dj2p-fw_.js +439 -0
- package/dist/web/assets/{tsMode-Gjs5D1gt.js → tsMode-ClDl0-oy.js} +1 -1
- package/dist/web/assets/{typescript-Cw6YtwrM.js → typescript-DVPndl3f.js} +1 -1
- package/dist/web/assets/{xml-guZq0YZJ.js → xml-ZTAdiNZS.js} +1 -1
- package/dist/web/assets/{yaml-B9TbU-LX.js → yaml-4WO-VI9I.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/AISettings-DU-jBPOf.js +0 -205
- package/dist/web/assets/ExtractRunner-CzfLlCCf.js +0 -1
- package/dist/web/assets/baseinput-B7PU5-38.js +0 -2
- package/dist/web/assets/checkbox-CCQwMfLd.js +0 -142
- package/dist/web/assets/select-DKPPF403.js +0 -438
- /package/dist/web/assets/{DataBrowser-DQwOvooY.js → DataBrowser-CLOlYw5B.js} +0 -0
- /package/dist/web/assets/{abap-C3UM4cME.js → abap-CFuyUYKP.js} +0 -0
- /package/dist/web/assets/{apex-BQBZvQmN.js → apex-Ctq_xcrv.js} +0 -0
- /package/dist/web/assets/{azcli-Dn9Awrok.js → azcli-BBQSVn-C.js} +0 -0
- /package/dist/web/assets/{bat-JgEezSDo.js → bat-DbnqAfvr.js} +0 -0
- /package/dist/web/assets/{bicep-vcQeC7wE.js → bicep-BtDlIXop.js} +0 -0
- /package/dist/web/assets/{cameligo-C0cr0T3L.js → cameligo-BLeJgKTj.js} +0 -0
- /package/dist/web/assets/{clojure-Brc1-rbW.js → clojure-aZUQIUKP.js} +0 -0
- /package/dist/web/assets/{coffee-BiZYU83a.js → coffee-Secadq9U.js} +0 -0
- /package/dist/web/assets/{cpp-ikWHCInz.js → cpp-JicRPTRv.js} +0 -0
- /package/dist/web/assets/{csharp-BRWs_LfH.js → csharp-C7NSOZyj.js} +0 -0
- /package/dist/web/assets/{csp-CcAumoJw.js → csp-CIje7830.js} +0 -0
- /package/dist/web/assets/{css-BZm6paiA.js → css-G0bm1q_M.js} +0 -0
- /package/dist/web/assets/{cypher-CDQMONdb.js → cypher-CldD5D0u.js} +0 -0
- /package/dist/web/assets/{dart-Ci4SZdF1.js → dart-DIK3l8YT.js} +0 -0
- /package/dist/web/assets/{dockerfile-BV0tAr-M.js → dockerfile-czxaGh2L.js} +0 -0
- /package/dist/web/assets/{ecl-CP7nM2KN.js → ecl-BqdYhwmw.js} +0 -0
- /package/dist/web/assets/{editor.api-BU_q4v8i.js → editor.api-DrogPInQ.js} +0 -0
- /package/dist/web/assets/{elixir-GcA6wFiI.js → elixir-m52LePTW.js} +0 -0
- /package/dist/web/assets/{flow9-CIb9youF.js → flow9-B5QJ9GvZ.js} +0 -0
- /package/dist/web/assets/{fsharp-BVaBE4co.js → fsharp-Bsj2_cCa.js} +0 -0
- /package/dist/web/assets/{go-Bbqf306x.js → go-BqOR3oKA.js} +0 -0
- /package/dist/web/assets/{graphql-DJPrC4l-.js → graphql-B8qEHPdi.js} +0 -0
- /package/dist/web/assets/{hcl-QyfWVWpM.js → hcl-DWuCE4v-.js} +0 -0
- /package/dist/web/assets/{ini-CgstZeS8.js → ini-Qq7k0Z4_.js} +0 -0
- /package/dist/web/assets/{java-D4AG88ZY.js → java-BYPjirKp.js} +0 -0
- /package/dist/web/assets/{julia-CN8U9648.js → julia-BDPeJze-.js} +0 -0
- /package/dist/web/assets/{kotlin-gNNgpJhY.js → kotlin-Cn6ib1e9.js} +0 -0
- /package/dist/web/assets/{less-C3SY2L8t.js → less-CJaXZ051.js} +0 -0
- /package/dist/web/assets/{lexon-CznnqzUX.js → lexon-8Vqfm7H_.js} +0 -0
- /package/dist/web/assets/{lua-f3xyJgy5.js → lua-CvR2zKQJ.js} +0 -0
- /package/dist/web/assets/{m3-Cl7J89p-.js → m3-B_srJ0-W.js} +0 -0
- /package/dist/web/assets/{markdown-Bv2fnzzT.js → markdown-BLHPl-_K.js} +0 -0
- /package/dist/web/assets/{mips-D6rXUTWa.js → mips-DVyJ6qEt.js} +0 -0
- /package/dist/web/assets/{msdax-Bb1N2x5J.js → msdax-CSgWECQy.js} +0 -0
- /package/dist/web/assets/{mysql-DXSr6oD7.js → mysql-DgAobqZA.js} +0 -0
- /package/dist/web/assets/{objective-c-CEJiVkDa.js → objective-c-YsnCzZhx.js} +0 -0
- /package/dist/web/assets/{pascal-BtkMEIba.js → pascal-DBRbVM1J.js} +0 -0
- /package/dist/web/assets/{pascaligo-C7FAwqk7.js → pascaligo-DGMAqea9.js} +0 -0
- /package/dist/web/assets/{perl-D9kqkBbN.js → perl-BbO9hyuY.js} +0 -0
- /package/dist/web/assets/{pgsql-BjGTBL1W.js → pgsql-C-hxeXjm.js} +0 -0
- /package/dist/web/assets/{php-BN0c0noA.js → php-CNUtuIOY.js} +0 -0
- /package/dist/web/assets/{pla-B94QTqOt.js → pla-kg11R4PY.js} +0 -0
- /package/dist/web/assets/{postiats-DH91dqBs.js → postiats-B1z9yYod.js} +0 -0
- /package/dist/web/assets/{powerquery-D7P0oUen.js → powerquery-B7uH8tJZ.js} +0 -0
- /package/dist/web/assets/{powershell-CCVHmJax.js → powershell-C4XFI11Z.js} +0 -0
- /package/dist/web/assets/{protobuf-BIP7pixC.js → protobuf-BcOV_0Q2.js} +0 -0
- /package/dist/web/assets/{pug-DcbLK7HH.js → pug-68xbfbza.js} +0 -0
- /package/dist/web/assets/{qsharp-B-VY_WOG.js → qsharp-BrGH6SSV.js} +0 -0
- /package/dist/web/assets/{r-DwRtsJsj.js → r--OWX2YhF.js} +0 -0
- /package/dist/web/assets/{redis-CaW0tkwu.js → redis-BOXumJdj.js} +0 -0
- /package/dist/web/assets/{redshift-3tS8G0ME.js → redshift-8U3qVUZv.js} +0 -0
- /package/dist/web/assets/{restructuredtext-_TNyGyK0.js → restructuredtext-D6puF6Gd.js} +0 -0
- /package/dist/web/assets/{ruby-A-MwVfO4.js → ruby-g_KUrR8T.js} +0 -0
- /package/dist/web/assets/{rust-oemlUIvG.js → rust-Dm8AnzU3.js} +0 -0
- /package/dist/web/assets/{sb-BDZuaI3W.js → sb-D_ts6T0n.js} +0 -0
- /package/dist/web/assets/{scala-Bfo2loK4.js → scala-C6NOuwmJ.js} +0 -0
- /package/dist/web/assets/{scheme-N2eo7rjB.js → scheme-CPooyhAN.js} +0 -0
- /package/dist/web/assets/{scss-vjjSCTgN.js → scss-DUEUJROR.js} +0 -0
- /package/dist/web/assets/{shell-Bfb9Yq6w.js → shell-kdqtsGKx.js} +0 -0
- /package/dist/web/assets/{solidity-C9RbukzG.js → solidity-CnMA-U-d.js} +0 -0
- /package/dist/web/assets/{sophia-DWV_MWOg.js → sophia-BKvc9daj.js} +0 -0
- /package/dist/web/assets/{sparql-iMXILWhh.js → sparql-Bh3XvRxY.js} +0 -0
- /package/dist/web/assets/{sql-CJDj31JM.js → sql-CRPVrMOO.js} +0 -0
- /package/dist/web/assets/{st-BG9AQ1OO.js → st-DBvoSKfh.js} +0 -0
- /package/dist/web/assets/{swift-B579DvHm.js → swift-B8QEexRZ.js} +0 -0
- /package/dist/web/assets/{systemverilog-BNgaF3ZX.js → systemverilog-CBeOTblq.js} +0 -0
- /package/dist/web/assets/{tcl-grdtJiUA.js → tcl-DR5kknHN.js} +0 -0
- /package/dist/web/assets/{twig-JAsFXBZw.js → twig-5OXXSkT1.js} +0 -0
- /package/dist/web/assets/{typespec-D3hIQXEU.js → typespec-cVMWW5z1.js} +0 -0
- /package/dist/web/assets/{vb-H38jRcEz.js → vb-DRjqfs-G.js} +0 -0
- /package/dist/web/assets/{wgsl-BC5Grc5r.js → wgsl-B5lRvHwm.js} +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as version, T as formatDoctorDiagnosticsJson, _ as createConfig, a as parseJsonSchema, b as name, c as getDefaultAIConfig, d as DEFAULT_MARKITDOWN_CONFIG, f as DEFAULT_MINERU_CONFIG, g as AIConfigSchema, h as PLACEHOLDER_TEXT, i as JsonSchemaDefinitionSchema, l as readAIConfig, m as PLACEHOLDER_SCHEMA, n as createMigrationConfig, o as toSnakeCase, p as DEFAULT_PROMPT_CONFIG, s as generateDrizzleSchema, t as collectDoctorDiagnostics, u as writeAIConfig, v as seedConfig, w as doctorDiagnosticsTableRows, x as package_default, y as description } from "./doctor-collector-
|
|
1
|
+
import { S as version, T as formatDoctorDiagnosticsJson, _ as createConfig, a as parseJsonSchema, b as name, c as getDefaultAIConfig, d as DEFAULT_MARKITDOWN_CONFIG, f as DEFAULT_MINERU_CONFIG, g as AIConfigSchema, h as PLACEHOLDER_TEXT, i as JsonSchemaDefinitionSchema, l as readAIConfig, m as PLACEHOLDER_SCHEMA, n as createMigrationConfig, o as toSnakeCase, p as DEFAULT_PROMPT_CONFIG, s as generateDrizzleSchema, t as collectDoctorDiagnostics, u as writeAIConfig, v as seedConfig, w as doctorDiagnosticsTableRows, x as package_default, y as description } from "./doctor-collector-DoJqOYMT.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import os from "node:os";
|
|
@@ -23,9 +23,10 @@ import { jsonrepair } from "jsonrepair";
|
|
|
23
23
|
import fs$1 from "node:fs";
|
|
24
24
|
import Database from "better-sqlite3";
|
|
25
25
|
import { glob, globSync } from "tinyglobby";
|
|
26
|
+
import { Client, extractNotionId } from "@notionhq/client";
|
|
27
|
+
import { Buffer } from "node:buffer";
|
|
26
28
|
import { execa } from "execa";
|
|
27
29
|
import { extractText, getDocumentProxy, getMeta } from "unpdf";
|
|
28
|
-
import { Buffer } from "node:buffer";
|
|
29
30
|
import { execFile } from "node:child_process";
|
|
30
31
|
import { promisify } from "node:util";
|
|
31
32
|
import { serve } from "@hono/node-server";
|
|
@@ -33,7 +34,6 @@ import open from "open";
|
|
|
33
34
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
34
35
|
import { Hono } from "hono";
|
|
35
36
|
import { cors } from "hono/cors";
|
|
36
|
-
import { Client, extractNotionId } from "@notionhq/client";
|
|
37
37
|
import { zValidator } from "@hono/zod-validator";
|
|
38
38
|
import { Kysely, SqliteDialect, sql } from "kysely";
|
|
39
39
|
|
|
@@ -13487,6 +13487,208 @@ async function deleteExtractionAuditRecord(aiexDir, id) {
|
|
|
13487
13487
|
return true;
|
|
13488
13488
|
}
|
|
13489
13489
|
|
|
13490
|
+
//#endregion
|
|
13491
|
+
//#region src/core/notion-sink.ts
|
|
13492
|
+
const RICH_TEXT_LIMIT = 2e3;
|
|
13493
|
+
const UUID_RE = /^[0-9a-f]{32}$/i;
|
|
13494
|
+
const HYPHENATED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
13495
|
+
function truncateText(value) {
|
|
13496
|
+
return value.length > RICH_TEXT_LIMIT ? value.slice(0, RICH_TEXT_LIMIT) : value;
|
|
13497
|
+
}
|
|
13498
|
+
function stringifyValue(value) {
|
|
13499
|
+
if (value === null || value === void 0) return "";
|
|
13500
|
+
if (typeof value === "string") return value;
|
|
13501
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
13502
|
+
return JSON.stringify(value);
|
|
13503
|
+
}
|
|
13504
|
+
function asNumber(value) {
|
|
13505
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
13506
|
+
if (typeof value === "string" && value.trim()) {
|
|
13507
|
+
const parsed = Number(value);
|
|
13508
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
13509
|
+
}
|
|
13510
|
+
return null;
|
|
13511
|
+
}
|
|
13512
|
+
function asBoolean(value) {
|
|
13513
|
+
if (typeof value === "boolean") return value;
|
|
13514
|
+
if (typeof value === "number") return value !== 0;
|
|
13515
|
+
if (typeof value === "string") {
|
|
13516
|
+
const normalized = value.trim().toLowerCase();
|
|
13517
|
+
return [
|
|
13518
|
+
"true",
|
|
13519
|
+
"yes",
|
|
13520
|
+
"1",
|
|
13521
|
+
"y"
|
|
13522
|
+
].includes(normalized);
|
|
13523
|
+
}
|
|
13524
|
+
return !!value;
|
|
13525
|
+
}
|
|
13526
|
+
function asDateStart(value) {
|
|
13527
|
+
if (value instanceof Date && !Number.isNaN(value.getTime())) return value.toISOString();
|
|
13528
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
13529
|
+
const date = new Date(value);
|
|
13530
|
+
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
13531
|
+
}
|
|
13532
|
+
if (typeof value === "string" && value.trim()) {
|
|
13533
|
+
const ms = Date.parse(value);
|
|
13534
|
+
if (Number.isNaN(ms)) return null;
|
|
13535
|
+
return new Date(ms).toISOString();
|
|
13536
|
+
}
|
|
13537
|
+
return null;
|
|
13538
|
+
}
|
|
13539
|
+
function asStringArray(value) {
|
|
13540
|
+
if (Array.isArray(value)) return value.map((item) => stringifyValue(item).trim()).filter(Boolean);
|
|
13541
|
+
const text$1 = stringifyValue(value).trim();
|
|
13542
|
+
return text$1 ? [text$1] : [];
|
|
13543
|
+
}
|
|
13544
|
+
function buildPropertyValue(type, value) {
|
|
13545
|
+
const text$1 = truncateText(stringifyValue(value));
|
|
13546
|
+
switch (type) {
|
|
13547
|
+
case "title": return { title: text$1 ? [{ text: { content: text$1 } }] : [] };
|
|
13548
|
+
case "rich_text": return { rich_text: text$1 ? [{ text: { content: text$1 } }] : [] };
|
|
13549
|
+
case "number": return { number: asNumber(value) };
|
|
13550
|
+
case "checkbox": return { checkbox: asBoolean(value) };
|
|
13551
|
+
case "date": {
|
|
13552
|
+
const start = asDateStart(value);
|
|
13553
|
+
return { date: start ? { start } : null };
|
|
13554
|
+
}
|
|
13555
|
+
case "select": {
|
|
13556
|
+
const name$1 = stringifyValue(value).trim();
|
|
13557
|
+
return { select: name$1 ? { name: name$1 } : null };
|
|
13558
|
+
}
|
|
13559
|
+
case "multi_select": return { multi_select: asStringArray(value).map((name$1) => ({ name: name$1 })) };
|
|
13560
|
+
case "url": return { url: text$1 || null };
|
|
13561
|
+
case "email": return { email: text$1 || null };
|
|
13562
|
+
case "phone_number": return { phone_number: text$1 || null };
|
|
13563
|
+
default: return null;
|
|
13564
|
+
}
|
|
13565
|
+
}
|
|
13566
|
+
function findTitleProperty(properties, preferred) {
|
|
13567
|
+
if (preferred && properties[preferred]?.type === "title") return preferred;
|
|
13568
|
+
return Object.entries(properties).find(([, property]) => property?.type === "title")?.[0] ?? null;
|
|
13569
|
+
}
|
|
13570
|
+
function hyphenateDatabaseId(value) {
|
|
13571
|
+
const id = value.replace(/-/g, "");
|
|
13572
|
+
if (!UUID_RE.test(id)) return value;
|
|
13573
|
+
return `${id.slice(0, 8)}-${id.slice(8, 12)}-${id.slice(12, 16)}-${id.slice(16, 20)}-${id.slice(20)}`;
|
|
13574
|
+
}
|
|
13575
|
+
function parseNotionDatabaseId(value) {
|
|
13576
|
+
const input = value.trim();
|
|
13577
|
+
if (!input) return "";
|
|
13578
|
+
const extracted = extractNotionId(input);
|
|
13579
|
+
if (extracted) return extracted;
|
|
13580
|
+
if (HYPHENATED_UUID_RE.test(input)) return input;
|
|
13581
|
+
if (UUID_RE.test(input)) return hyphenateDatabaseId(input);
|
|
13582
|
+
return input;
|
|
13583
|
+
}
|
|
13584
|
+
function normalizeFieldName(value) {
|
|
13585
|
+
return value.normalize("NFKC").toLowerCase().replace(/[^\p{Letter}\p{Number}]+/gu, "");
|
|
13586
|
+
}
|
|
13587
|
+
function buildMatchKeys(field) {
|
|
13588
|
+
return [
|
|
13589
|
+
field.name,
|
|
13590
|
+
field.title,
|
|
13591
|
+
field.description
|
|
13592
|
+
].filter((value) => !!value?.trim()).map(normalizeFieldName).filter(Boolean);
|
|
13593
|
+
}
|
|
13594
|
+
function suggestFieldMap(schemaFields, databaseProperties) {
|
|
13595
|
+
const propertyByKey = /* @__PURE__ */ new Map();
|
|
13596
|
+
for (const propertyName of Object.keys(databaseProperties)) propertyByKey.set(normalizeFieldName(propertyName), propertyName);
|
|
13597
|
+
const fieldMap = {};
|
|
13598
|
+
for (const field of schemaFields) for (const key of buildMatchKeys(field)) {
|
|
13599
|
+
const propertyName = propertyByKey.get(key);
|
|
13600
|
+
if (propertyName) {
|
|
13601
|
+
fieldMap[field.name] = propertyName;
|
|
13602
|
+
break;
|
|
13603
|
+
}
|
|
13604
|
+
}
|
|
13605
|
+
return fieldMap;
|
|
13606
|
+
}
|
|
13607
|
+
function hasProperties(value) {
|
|
13608
|
+
return !!value && typeof value === "object" && !!value.properties && typeof value.properties === "object";
|
|
13609
|
+
}
|
|
13610
|
+
function firstDataSourceId(database) {
|
|
13611
|
+
return (Array.isArray(database?.data_sources) ? database.data_sources : []).find((source) => typeof source?.id === "string" && source.id.trim())?.id;
|
|
13612
|
+
}
|
|
13613
|
+
async function resolveNotionDataSource(notion, inputId) {
|
|
13614
|
+
const id = parseNotionDatabaseId(inputId);
|
|
13615
|
+
if (!id) throw new Error("Notion database or data source URL/ID is required.");
|
|
13616
|
+
try {
|
|
13617
|
+
const dataSource$1 = await notion.dataSources.retrieve({ data_source_id: id });
|
|
13618
|
+
if (hasProperties(dataSource$1)) return {
|
|
13619
|
+
databaseId: typeof dataSource$1.parent?.database_id === "string" ? dataSource$1.parent.database_id : id,
|
|
13620
|
+
dataSourceId: dataSource$1.id ?? id,
|
|
13621
|
+
properties: dataSource$1.properties,
|
|
13622
|
+
parent: { data_source_id: dataSource$1.id ?? id }
|
|
13623
|
+
};
|
|
13624
|
+
} catch {}
|
|
13625
|
+
const database = await notion.databases.retrieve({ database_id: id });
|
|
13626
|
+
const dataSourceId = firstDataSourceId(database);
|
|
13627
|
+
if (!dataSourceId) throw new Error("No data source found for this Notion database. Copy the data source link from Notion, or share the source database with the integration.");
|
|
13628
|
+
const dataSource = await notion.dataSources.retrieve({ data_source_id: dataSourceId });
|
|
13629
|
+
if (!hasProperties(dataSource)) throw new Error("Notion data source did not return properties. Make sure it is shared with the integration and is not a linked data source.");
|
|
13630
|
+
return {
|
|
13631
|
+
databaseId: database.id ?? id,
|
|
13632
|
+
dataSourceId: dataSource.id ?? dataSourceId,
|
|
13633
|
+
properties: dataSource.properties,
|
|
13634
|
+
parent: { data_source_id: dataSource.id ?? dataSourceId }
|
|
13635
|
+
};
|
|
13636
|
+
}
|
|
13637
|
+
async function inspectNotionDatabase(input) {
|
|
13638
|
+
if (!input.token.trim()) throw new Error("Notion integration token is required.");
|
|
13639
|
+
const id = parseNotionDatabaseId(input.databaseId);
|
|
13640
|
+
if (!id) throw new Error("Notion database or data source URL/ID is required.");
|
|
13641
|
+
const resolved = await resolveNotionDataSource(new Client({ auth: input.token }), id);
|
|
13642
|
+
const databaseProperties = resolved.properties;
|
|
13643
|
+
const titleProperty = findTitleProperty(databaseProperties) ?? void 0;
|
|
13644
|
+
return {
|
|
13645
|
+
databaseId: resolved.databaseId,
|
|
13646
|
+
dataSourceId: resolved.dataSourceId,
|
|
13647
|
+
titleProperty,
|
|
13648
|
+
properties: Object.entries(databaseProperties).map(([name$1, property]) => ({
|
|
13649
|
+
name: name$1,
|
|
13650
|
+
type: property?.type ?? "unknown"
|
|
13651
|
+
})).sort((a, b) => a.name.localeCompare(b.name)),
|
|
13652
|
+
suggestedFieldMap: suggestFieldMap(input.schemaFields, databaseProperties)
|
|
13653
|
+
};
|
|
13654
|
+
}
|
|
13655
|
+
function validateNotionConfig(config) {
|
|
13656
|
+
if (!config?.enabled) return "Notion export is not enabled. Configure Notion settings first.";
|
|
13657
|
+
if (!config.token.trim()) return "Notion integration token is required.";
|
|
13658
|
+
return null;
|
|
13659
|
+
}
|
|
13660
|
+
async function writeNotionPage(config, schemaName, data) {
|
|
13661
|
+
const configError = validateNotionConfig(config);
|
|
13662
|
+
if (configError) throw new Error(configError);
|
|
13663
|
+
const notionConfig = config;
|
|
13664
|
+
const schemaConfig = notionConfig.schemas[schemaName];
|
|
13665
|
+
if (!schemaConfig) throw new Error(`Notion database is not configured for schema "${schemaName}".`);
|
|
13666
|
+
if (!schemaConfig.databaseId.trim()) throw new Error(`Notion database ID is required for schema "${schemaName}".`);
|
|
13667
|
+
const notion = new Client({ auth: notionConfig.token });
|
|
13668
|
+
const resolved = await resolveNotionDataSource(notion, schemaConfig.databaseId);
|
|
13669
|
+
const databaseProperties = resolved.properties;
|
|
13670
|
+
const fieldMap = schemaConfig.fieldMap ?? {};
|
|
13671
|
+
const properties = {};
|
|
13672
|
+
for (const [sourceField, sourceValue] of Object.entries(data)) {
|
|
13673
|
+
const notionPropertyName = fieldMap[sourceField] ?? sourceField;
|
|
13674
|
+
const notionProperty = databaseProperties[notionPropertyName];
|
|
13675
|
+
if (!notionProperty) continue;
|
|
13676
|
+
const propertyValue = buildPropertyValue(notionProperty.type, sourceValue);
|
|
13677
|
+
if (propertyValue) properties[notionPropertyName] = propertyValue;
|
|
13678
|
+
}
|
|
13679
|
+
const titleProperty = findTitleProperty(databaseProperties, schemaConfig.titleProperty);
|
|
13680
|
+
if (titleProperty && !properties[titleProperty]) properties[titleProperty] = buildPropertyValue("title", schemaName);
|
|
13681
|
+
if (Object.keys(properties).length === 0) throw new Error("No extracted fields matched Notion database properties.");
|
|
13682
|
+
return {
|
|
13683
|
+
pageId: (await notion.pages.create({
|
|
13684
|
+
parent: resolved.parent,
|
|
13685
|
+
properties
|
|
13686
|
+
})).id,
|
|
13687
|
+
databaseId: resolved.databaseId,
|
|
13688
|
+
dataSourceId: resolved.dataSourceId
|
|
13689
|
+
};
|
|
13690
|
+
}
|
|
13691
|
+
|
|
13490
13692
|
//#endregion
|
|
13491
13693
|
//#region src/core/pdf-converter/external.ts
|
|
13492
13694
|
function applyTemplate(value, context) {
|
|
@@ -13527,7 +13729,7 @@ function formatCommandError(error, command$1) {
|
|
|
13527
13729
|
}
|
|
13528
13730
|
async function countPdfPages(input) {
|
|
13529
13731
|
try {
|
|
13530
|
-
return (await getDocumentProxy(input)).numPages;
|
|
13732
|
+
return (await getDocumentProxy(Buffer.isBuffer(input) ? new Uint8Array(input) : input)).numPages;
|
|
13531
13733
|
} catch {
|
|
13532
13734
|
return 0;
|
|
13533
13735
|
}
|
|
@@ -13681,6 +13883,17 @@ const SUPPORTED_EXTENSIONS = new Set([
|
|
|
13681
13883
|
const PDF_EXT_RE = /\.pdf$/i;
|
|
13682
13884
|
const JSON_EXT_RE$1 = /\.json$/;
|
|
13683
13885
|
const SUPPORTED_FILE_PATTERN = `*.{${[...SUPPORTED_EXTENSIONS].join(",")}}`;
|
|
13886
|
+
async function syncResultToNotion(aiConfig, schemaName, data) {
|
|
13887
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) throw new Error("Extraction result is not an object and cannot be written to Notion.");
|
|
13888
|
+
const page = await writeNotionPage(aiConfig.notion, schemaName, data);
|
|
13889
|
+
return [{
|
|
13890
|
+
databaseId: page.databaseId,
|
|
13891
|
+
pageId: page.pageId
|
|
13892
|
+
}];
|
|
13893
|
+
}
|
|
13894
|
+
function shouldSyncNotion(aiConfig, schemaName) {
|
|
13895
|
+
return !!aiConfig.notion?.enabled && !!aiConfig.notion.schemas?.[schemaName]?.databaseId?.trim();
|
|
13896
|
+
}
|
|
13684
13897
|
async function ensureDatabaseReady(dbPath, schema) {
|
|
13685
13898
|
try {
|
|
13686
13899
|
await fs.access(dbPath);
|
|
@@ -13872,11 +14085,28 @@ async function processOneFile(aiexDir, config, aiConfig, schemaName, filePath, m
|
|
|
13872
14085
|
insert: options?.insert
|
|
13873
14086
|
});
|
|
13874
14087
|
if (r.success) {
|
|
14088
|
+
let notionPages;
|
|
14089
|
+
if (shouldSyncNotion(aiConfig, schemaName)) try {
|
|
14090
|
+
notionPages = await syncResultToNotion(aiConfig, schemaName, r.data);
|
|
14091
|
+
consola.success(`Synced to Notion: ${notionPages.length} page(s)`);
|
|
14092
|
+
} catch (error) {
|
|
14093
|
+
await updateExtractionAuditRecord(aiexDir, audit.id, {
|
|
14094
|
+
status: "failed",
|
|
14095
|
+
outputPath: r.outputPath,
|
|
14096
|
+
outputName: r.outputPath ? path.basename(r.outputPath) : void 0,
|
|
14097
|
+
tablesInserted: r.tablesInserted,
|
|
14098
|
+
tokensUsed: r.tokensUsed,
|
|
14099
|
+
error: error instanceof Error ? error.message : String(error)
|
|
14100
|
+
});
|
|
14101
|
+
consola.error(`Notion sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
14102
|
+
return false;
|
|
14103
|
+
}
|
|
13875
14104
|
await updateExtractionAuditRecord(aiexDir, audit.id, {
|
|
13876
14105
|
status: "succeeded",
|
|
13877
14106
|
outputPath: r.outputPath,
|
|
13878
14107
|
outputName: r.outputPath ? path.basename(r.outputPath) : void 0,
|
|
13879
14108
|
tablesInserted: r.tablesInserted,
|
|
14109
|
+
notionPages,
|
|
13880
14110
|
tokensUsed: r.tokensUsed
|
|
13881
14111
|
});
|
|
13882
14112
|
consola.success(`Processed: ${path.basename(filePath)}`);
|
|
@@ -13941,6 +14171,15 @@ function getIdArg(args) {
|
|
|
13941
14171
|
const positional = args._;
|
|
13942
14172
|
return Array.isArray(positional) && typeof positional[0] === "string" ? positional[0] : "";
|
|
13943
14173
|
}
|
|
14174
|
+
function isExtractSubCommand(rawArgs) {
|
|
14175
|
+
if (!Array.isArray(rawArgs)) return false;
|
|
14176
|
+
return rawArgs.some((arg) => typeof arg === "string" && [
|
|
14177
|
+
"history",
|
|
14178
|
+
"show",
|
|
14179
|
+
"retry",
|
|
14180
|
+
"rm"
|
|
14181
|
+
].includes(arg));
|
|
14182
|
+
}
|
|
13944
14183
|
function formatSource(source) {
|
|
13945
14184
|
return source.type === "file" ? source.fileName || "file" : "text";
|
|
13946
14185
|
}
|
|
@@ -13984,11 +14223,33 @@ async function runAuditedSingleExtraction(input) {
|
|
|
13984
14223
|
});
|
|
13985
14224
|
return false;
|
|
13986
14225
|
}
|
|
14226
|
+
let notionPages;
|
|
14227
|
+
if (input.aiConfig.notion?.enabled && input.aiConfig.notion.schemas?.[input.schemaName]?.databaseId?.trim()) try {
|
|
14228
|
+
if (!result.data || typeof result.data !== "object" || Array.isArray(result.data)) throw new Error("Extraction result is not an object and cannot be written to Notion.");
|
|
14229
|
+
const page = await writeNotionPage(input.aiConfig.notion, input.schemaName, result.data);
|
|
14230
|
+
notionPages = [{
|
|
14231
|
+
databaseId: page.databaseId,
|
|
14232
|
+
pageId: page.pageId
|
|
14233
|
+
}];
|
|
14234
|
+
consola.success(`Synced to Notion: ${notionPages.length} page(s)`);
|
|
14235
|
+
} catch (error) {
|
|
14236
|
+
await updateExtractionAuditRecord(input.aiexDir, audit.id, {
|
|
14237
|
+
status: "failed",
|
|
14238
|
+
outputPath: result.outputPath,
|
|
14239
|
+
outputName: result.outputPath ? path.basename(result.outputPath) : void 0,
|
|
14240
|
+
tablesInserted: result.tablesInserted,
|
|
14241
|
+
tokensUsed: result.tokensUsed,
|
|
14242
|
+
error: error instanceof Error ? error.message : String(error)
|
|
14243
|
+
});
|
|
14244
|
+
consola.error(`Notion sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
14245
|
+
return false;
|
|
14246
|
+
}
|
|
13987
14247
|
await updateExtractionAuditRecord(input.aiexDir, audit.id, {
|
|
13988
14248
|
status: "succeeded",
|
|
13989
14249
|
outputPath: result.outputPath,
|
|
13990
14250
|
outputName: result.outputPath ? path.basename(result.outputPath) : void 0,
|
|
13991
14251
|
tablesInserted: result.tablesInserted,
|
|
14252
|
+
notionPages,
|
|
13992
14253
|
tokensUsed: result.tokensUsed
|
|
13993
14254
|
});
|
|
13994
14255
|
return true;
|
|
@@ -14166,7 +14427,8 @@ const extractCommand = defineCommand({
|
|
|
14166
14427
|
default: false
|
|
14167
14428
|
}
|
|
14168
14429
|
},
|
|
14169
|
-
async run({ args }) {
|
|
14430
|
+
async run({ args, rawArgs }) {
|
|
14431
|
+
if (isExtractSubCommand(rawArgs)) return;
|
|
14170
14432
|
intro(pc.inverse(" aiex extract "));
|
|
14171
14433
|
const config = createMigrationConfig(process.cwd());
|
|
14172
14434
|
const aiexDir = path.dirname(config.schemaPath);
|
|
@@ -14300,7 +14562,18 @@ async function runInteractive(aiexDir, config, aiConfig, modelOverride) {
|
|
|
14300
14562
|
cancel("Cancelled");
|
|
14301
14563
|
return false;
|
|
14302
14564
|
}
|
|
14303
|
-
return (
|
|
14565
|
+
return runAuditedSingleExtraction({
|
|
14566
|
+
aiexDir,
|
|
14567
|
+
config,
|
|
14568
|
+
aiConfig,
|
|
14569
|
+
schemaName,
|
|
14570
|
+
text: textContent,
|
|
14571
|
+
source: {
|
|
14572
|
+
type: "text",
|
|
14573
|
+
text: textContent
|
|
14574
|
+
},
|
|
14575
|
+
modelOverride
|
|
14576
|
+
});
|
|
14304
14577
|
} else if (inputSource === "file") {
|
|
14305
14578
|
const filePathStr = await text({
|
|
14306
14579
|
message: "Enter file path:",
|
|
@@ -14315,7 +14588,20 @@ async function runInteractive(aiexDir, config, aiConfig, modelOverride) {
|
|
|
14315
14588
|
const fp = filePathStr;
|
|
14316
14589
|
try {
|
|
14317
14590
|
const input = await readExtractFileInput(fp, aiConfig);
|
|
14318
|
-
return (
|
|
14591
|
+
return runAuditedSingleExtraction({
|
|
14592
|
+
aiexDir,
|
|
14593
|
+
config,
|
|
14594
|
+
aiConfig,
|
|
14595
|
+
schemaName,
|
|
14596
|
+
text: input.text,
|
|
14597
|
+
filePath: input.filePath,
|
|
14598
|
+
source: {
|
|
14599
|
+
type: "file",
|
|
14600
|
+
filePath: fp,
|
|
14601
|
+
fileName: path.basename(fp)
|
|
14602
|
+
},
|
|
14603
|
+
modelOverride
|
|
14604
|
+
});
|
|
14319
14605
|
} catch (e) {
|
|
14320
14606
|
consola.error(`Cannot read file: ${fp} — ${e instanceof Error ? e.message : String(e)}`);
|
|
14321
14607
|
return false;
|
|
@@ -14521,213 +14807,6 @@ const schemaCommand = defineCommand({
|
|
|
14521
14807
|
}
|
|
14522
14808
|
});
|
|
14523
14809
|
|
|
14524
|
-
//#endregion
|
|
14525
|
-
//#region src/core/notion-sink.ts
|
|
14526
|
-
const RICH_TEXT_LIMIT = 2e3;
|
|
14527
|
-
const UUID_RE = /^[0-9a-f]{32}$/i;
|
|
14528
|
-
const HYPHENATED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14529
|
-
function truncateText(value) {
|
|
14530
|
-
return value.length > RICH_TEXT_LIMIT ? value.slice(0, RICH_TEXT_LIMIT) : value;
|
|
14531
|
-
}
|
|
14532
|
-
function stringifyValue(value) {
|
|
14533
|
-
if (value === null || value === void 0) return "";
|
|
14534
|
-
if (typeof value === "string") return value;
|
|
14535
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
14536
|
-
return JSON.stringify(value);
|
|
14537
|
-
}
|
|
14538
|
-
function asNumber(value) {
|
|
14539
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
14540
|
-
if (typeof value === "string" && value.trim()) {
|
|
14541
|
-
const parsed = Number(value);
|
|
14542
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
14543
|
-
}
|
|
14544
|
-
return null;
|
|
14545
|
-
}
|
|
14546
|
-
function asBoolean(value) {
|
|
14547
|
-
if (typeof value === "boolean") return value;
|
|
14548
|
-
if (typeof value === "number") return value !== 0;
|
|
14549
|
-
if (typeof value === "string") {
|
|
14550
|
-
const normalized = value.trim().toLowerCase();
|
|
14551
|
-
return [
|
|
14552
|
-
"true",
|
|
14553
|
-
"yes",
|
|
14554
|
-
"1",
|
|
14555
|
-
"y"
|
|
14556
|
-
].includes(normalized);
|
|
14557
|
-
}
|
|
14558
|
-
return !!value;
|
|
14559
|
-
}
|
|
14560
|
-
function asDateStart(value) {
|
|
14561
|
-
if (value instanceof Date && !Number.isNaN(value.getTime())) return value.toISOString();
|
|
14562
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
14563
|
-
const date = new Date(value);
|
|
14564
|
-
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
14565
|
-
}
|
|
14566
|
-
if (typeof value === "string" && value.trim()) {
|
|
14567
|
-
const ms = Date.parse(value);
|
|
14568
|
-
if (Number.isNaN(ms)) return null;
|
|
14569
|
-
return new Date(ms).toISOString();
|
|
14570
|
-
}
|
|
14571
|
-
return null;
|
|
14572
|
-
}
|
|
14573
|
-
function asStringArray(value) {
|
|
14574
|
-
if (Array.isArray(value)) return value.map((item) => stringifyValue(item).trim()).filter(Boolean);
|
|
14575
|
-
const text$1 = stringifyValue(value).trim();
|
|
14576
|
-
return text$1 ? [text$1] : [];
|
|
14577
|
-
}
|
|
14578
|
-
function buildPropertyValue(type, value) {
|
|
14579
|
-
const text$1 = truncateText(stringifyValue(value));
|
|
14580
|
-
switch (type) {
|
|
14581
|
-
case "title": return { title: text$1 ? [{ text: { content: text$1 } }] : [] };
|
|
14582
|
-
case "rich_text": return { rich_text: text$1 ? [{ text: { content: text$1 } }] : [] };
|
|
14583
|
-
case "number": return { number: asNumber(value) };
|
|
14584
|
-
case "checkbox": return { checkbox: asBoolean(value) };
|
|
14585
|
-
case "date": {
|
|
14586
|
-
const start = asDateStart(value);
|
|
14587
|
-
return { date: start ? { start } : null };
|
|
14588
|
-
}
|
|
14589
|
-
case "select": {
|
|
14590
|
-
const name$1 = stringifyValue(value).trim();
|
|
14591
|
-
return { select: name$1 ? { name: name$1 } : null };
|
|
14592
|
-
}
|
|
14593
|
-
case "multi_select": return { multi_select: asStringArray(value).map((name$1) => ({ name: name$1 })) };
|
|
14594
|
-
case "url": return { url: text$1 || null };
|
|
14595
|
-
case "email": return { email: text$1 || null };
|
|
14596
|
-
case "phone_number": return { phone_number: text$1 || null };
|
|
14597
|
-
default: return null;
|
|
14598
|
-
}
|
|
14599
|
-
}
|
|
14600
|
-
function findTitleProperty(properties, preferred) {
|
|
14601
|
-
if (preferred && properties[preferred]?.type === "title") return preferred;
|
|
14602
|
-
return Object.entries(properties).find(([, property]) => property?.type === "title")?.[0] ?? null;
|
|
14603
|
-
}
|
|
14604
|
-
function hyphenateDatabaseId(value) {
|
|
14605
|
-
const id = value.replace(/-/g, "");
|
|
14606
|
-
if (!UUID_RE.test(id)) return value;
|
|
14607
|
-
return `${id.slice(0, 8)}-${id.slice(8, 12)}-${id.slice(12, 16)}-${id.slice(16, 20)}-${id.slice(20)}`;
|
|
14608
|
-
}
|
|
14609
|
-
function parseNotionDatabaseId(value) {
|
|
14610
|
-
const input = value.trim();
|
|
14611
|
-
if (!input) return "";
|
|
14612
|
-
const extracted = extractNotionId(input);
|
|
14613
|
-
if (extracted) return extracted;
|
|
14614
|
-
if (HYPHENATED_UUID_RE.test(input)) return input;
|
|
14615
|
-
if (UUID_RE.test(input)) return hyphenateDatabaseId(input);
|
|
14616
|
-
return input;
|
|
14617
|
-
}
|
|
14618
|
-
function normalizeFieldName(value) {
|
|
14619
|
-
return value.normalize("NFKC").toLowerCase().replace(/[^\p{Letter}\p{Number}]+/gu, "");
|
|
14620
|
-
}
|
|
14621
|
-
function buildMatchKeys(field) {
|
|
14622
|
-
return [
|
|
14623
|
-
field.name,
|
|
14624
|
-
field.title,
|
|
14625
|
-
field.description
|
|
14626
|
-
].filter((value) => !!value?.trim()).map(normalizeFieldName).filter(Boolean);
|
|
14627
|
-
}
|
|
14628
|
-
function suggestFieldMap(schemaFields, databaseProperties) {
|
|
14629
|
-
const propertyByKey = /* @__PURE__ */ new Map();
|
|
14630
|
-
for (const propertyName of Object.keys(databaseProperties)) propertyByKey.set(normalizeFieldName(propertyName), propertyName);
|
|
14631
|
-
const fieldMap = {};
|
|
14632
|
-
for (const field of schemaFields) for (const key of buildMatchKeys(field)) {
|
|
14633
|
-
const propertyName = propertyByKey.get(key);
|
|
14634
|
-
if (propertyName) {
|
|
14635
|
-
fieldMap[field.name] = propertyName;
|
|
14636
|
-
break;
|
|
14637
|
-
}
|
|
14638
|
-
}
|
|
14639
|
-
return fieldMap;
|
|
14640
|
-
}
|
|
14641
|
-
function hasProperties(value) {
|
|
14642
|
-
return !!value && typeof value === "object" && !!value.properties && typeof value.properties === "object";
|
|
14643
|
-
}
|
|
14644
|
-
function firstDataSourceId(database) {
|
|
14645
|
-
return (Array.isArray(database?.data_sources) ? database.data_sources : []).find((source) => typeof source?.id === "string" && source.id.trim())?.id;
|
|
14646
|
-
}
|
|
14647
|
-
async function resolveNotionDataSource(notion, inputId) {
|
|
14648
|
-
const id = parseNotionDatabaseId(inputId);
|
|
14649
|
-
if (!id) throw new Error("Notion database or data source URL/ID is required.");
|
|
14650
|
-
try {
|
|
14651
|
-
const dataSource$1 = await notion.dataSources.retrieve({ data_source_id: id });
|
|
14652
|
-
if (hasProperties(dataSource$1)) return {
|
|
14653
|
-
databaseId: typeof dataSource$1.parent?.database_id === "string" ? dataSource$1.parent.database_id : id,
|
|
14654
|
-
dataSourceId: dataSource$1.id ?? id,
|
|
14655
|
-
properties: dataSource$1.properties,
|
|
14656
|
-
parent: { data_source_id: dataSource$1.id ?? id }
|
|
14657
|
-
};
|
|
14658
|
-
} catch {}
|
|
14659
|
-
const database = await notion.databases.retrieve({ database_id: id });
|
|
14660
|
-
if (hasProperties(database)) return {
|
|
14661
|
-
databaseId: database.id ?? id,
|
|
14662
|
-
properties: database.properties,
|
|
14663
|
-
parent: { database_id: database.id ?? id }
|
|
14664
|
-
};
|
|
14665
|
-
const dataSourceId = firstDataSourceId(database);
|
|
14666
|
-
if (!dataSourceId) throw new Error("No data source found for this Notion database. Copy the data source link from Notion, or share the source database with the integration.");
|
|
14667
|
-
const dataSource = await notion.dataSources.retrieve({ data_source_id: dataSourceId });
|
|
14668
|
-
if (!hasProperties(dataSource)) throw new Error("Notion data source did not return properties. Make sure it is shared with the integration and is not a linked data source.");
|
|
14669
|
-
return {
|
|
14670
|
-
databaseId: database.id ?? id,
|
|
14671
|
-
dataSourceId: dataSource.id ?? dataSourceId,
|
|
14672
|
-
properties: dataSource.properties,
|
|
14673
|
-
parent: { data_source_id: dataSource.id ?? dataSourceId }
|
|
14674
|
-
};
|
|
14675
|
-
}
|
|
14676
|
-
async function inspectNotionDatabase(input) {
|
|
14677
|
-
if (!input.token.trim()) throw new Error("Notion integration token is required.");
|
|
14678
|
-
const id = parseNotionDatabaseId(input.databaseId);
|
|
14679
|
-
if (!id) throw new Error("Notion database or data source URL/ID is required.");
|
|
14680
|
-
const resolved = await resolveNotionDataSource(new Client({ auth: input.token }), id);
|
|
14681
|
-
const databaseProperties = resolved.properties;
|
|
14682
|
-
const titleProperty = findTitleProperty(databaseProperties) ?? void 0;
|
|
14683
|
-
return {
|
|
14684
|
-
databaseId: resolved.databaseId,
|
|
14685
|
-
dataSourceId: resolved.dataSourceId,
|
|
14686
|
-
titleProperty,
|
|
14687
|
-
properties: Object.entries(databaseProperties).map(([name$1, property]) => ({
|
|
14688
|
-
name: name$1,
|
|
14689
|
-
type: property?.type ?? "unknown"
|
|
14690
|
-
})).sort((a, b) => a.name.localeCompare(b.name)),
|
|
14691
|
-
suggestedFieldMap: suggestFieldMap(input.schemaFields, databaseProperties)
|
|
14692
|
-
};
|
|
14693
|
-
}
|
|
14694
|
-
function validateNotionConfig(config) {
|
|
14695
|
-
if (!config?.enabled) return "Notion export is not enabled. Configure Notion settings first.";
|
|
14696
|
-
if (!config.token.trim()) return "Notion integration token is required.";
|
|
14697
|
-
return null;
|
|
14698
|
-
}
|
|
14699
|
-
async function writeNotionPage(config, schemaName, data) {
|
|
14700
|
-
const configError = validateNotionConfig(config);
|
|
14701
|
-
if (configError) throw new Error(configError);
|
|
14702
|
-
const notionConfig = config;
|
|
14703
|
-
const schemaConfig = notionConfig.schemas[schemaName];
|
|
14704
|
-
if (!schemaConfig) throw new Error(`Notion database is not configured for schema "${schemaName}".`);
|
|
14705
|
-
if (!schemaConfig.databaseId.trim()) throw new Error(`Notion database ID is required for schema "${schemaName}".`);
|
|
14706
|
-
const notion = new Client({ auth: notionConfig.token });
|
|
14707
|
-
const resolved = await resolveNotionDataSource(notion, schemaConfig.databaseId);
|
|
14708
|
-
const databaseProperties = resolved.properties;
|
|
14709
|
-
const fieldMap = schemaConfig.fieldMap ?? {};
|
|
14710
|
-
const properties = {};
|
|
14711
|
-
for (const [sourceField, sourceValue] of Object.entries(data)) {
|
|
14712
|
-
const notionPropertyName = fieldMap[sourceField] ?? sourceField;
|
|
14713
|
-
const notionProperty = databaseProperties[notionPropertyName];
|
|
14714
|
-
if (!notionProperty) continue;
|
|
14715
|
-
const propertyValue = buildPropertyValue(notionProperty.type, sourceValue);
|
|
14716
|
-
if (propertyValue) properties[notionPropertyName] = propertyValue;
|
|
14717
|
-
}
|
|
14718
|
-
const titleProperty = findTitleProperty(databaseProperties, schemaConfig.titleProperty);
|
|
14719
|
-
if (titleProperty && !properties[titleProperty]) properties[titleProperty] = buildPropertyValue("title", Object.entries(data).find(([, value]) => typeof value === "string" && value.trim())?.[1] ?? schemaName);
|
|
14720
|
-
if (Object.keys(properties).length === 0) throw new Error("No extracted fields matched Notion database properties.");
|
|
14721
|
-
return {
|
|
14722
|
-
pageId: (await notion.pages.create({
|
|
14723
|
-
parent: resolved.parent,
|
|
14724
|
-
properties
|
|
14725
|
-
})).id,
|
|
14726
|
-
databaseId: resolved.databaseId,
|
|
14727
|
-
dataSourceId: resolved.dataSourceId
|
|
14728
|
-
};
|
|
14729
|
-
}
|
|
14730
|
-
|
|
14731
14810
|
//#endregion
|
|
14732
14811
|
//#region src/server/routes/ai.ts
|
|
14733
14812
|
const JSON_EXT_RE = /\.json$/i;
|
|
@@ -15113,7 +15192,7 @@ async function executeAuditedExtraction(input) {
|
|
|
15113
15192
|
});
|
|
15114
15193
|
}
|
|
15115
15194
|
const notionPages = [];
|
|
15116
|
-
if (input.
|
|
15195
|
+
if (aiConfig.notion?.enabled && aiConfig.notion.schemas?.[input.schemaName]?.databaseId?.trim()) try {
|
|
15117
15196
|
if (!result.data || typeof result.data !== "object" || Array.isArray(result.data)) throw new Error("Extraction result is not an object and cannot be written to Notion.");
|
|
15118
15197
|
notionPages.push(await writeNotionPage(aiConfig.notion, input.schemaName, result.data));
|
|
15119
15198
|
} catch (error) {
|
|
@@ -15168,7 +15247,6 @@ function extractRoutes(config) {
|
|
|
15168
15247
|
const schemaName = getFormString(body.schema);
|
|
15169
15248
|
const text$1 = getFormString(body.text);
|
|
15170
15249
|
const modelName = getFormString(body.model);
|
|
15171
|
-
const syncNotion = getFormString(body.notion) === "true";
|
|
15172
15250
|
const file = getFormFile(body.file);
|
|
15173
15251
|
if (!schemaName) return c.json({
|
|
15174
15252
|
success: false,
|
|
@@ -15209,8 +15287,7 @@ function extractRoutes(config) {
|
|
|
15209
15287
|
schemaName,
|
|
15210
15288
|
text: text$1,
|
|
15211
15289
|
filePath,
|
|
15212
|
-
modelName
|
|
15213
|
-
syncNotion
|
|
15290
|
+
modelName
|
|
15214
15291
|
});
|
|
15215
15292
|
} catch (error) {
|
|
15216
15293
|
return c.json({
|
|
@@ -65,7 +65,7 @@ function doctorDiagnosticsTableRows(d) {
|
|
|
65
65
|
//#endregion
|
|
66
66
|
//#region package.json
|
|
67
67
|
var name = "aiex-cli";
|
|
68
|
-
var version = "0.0.2-beta.
|
|
68
|
+
var version = "0.0.2-beta.4";
|
|
69
69
|
var description = "JSON Schema → SQLite with AI-powered data extraction";
|
|
70
70
|
var package_default = {
|
|
71
71
|
name,
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { C as buildDoctorDiagnostics, T as formatDoctorDiagnosticsJson, a as parseJsonSchema, i as JsonSchemaDefinitionSchema, n as createMigrationConfig, r as generateDrizzleConfig, s as generateDrizzleSchema, t as collectDoctorDiagnostics, w as doctorDiagnosticsTableRows } from "./doctor-collector-
|
|
1
|
+
import { C as buildDoctorDiagnostics, T as formatDoctorDiagnosticsJson, a as parseJsonSchema, i as JsonSchemaDefinitionSchema, n as createMigrationConfig, r as generateDrizzleConfig, s as generateDrizzleSchema, t as collectDoctorDiagnostics, w as doctorDiagnosticsTableRows } from "./doctor-collector-DoJqOYMT.mjs";
|
|
2
2
|
|
|
3
3
|
export { JsonSchemaDefinitionSchema, buildDoctorDiagnostics, collectDoctorDiagnostics, createMigrationConfig, doctorDiagnosticsTableRows, formatDoctorDiagnosticsJson, generateDrizzleConfig, generateDrizzleSchema, parseJsonSchema };
|