@hasna/contacts 0.6.18 → 0.6.20

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.
@@ -61,14 +61,14 @@ import { join, relative } from "path";
61
61
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
62
62
  import { homedir as homedir2 } from "os";
63
63
  import { join as join2 } from "path";
64
- import { readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
65
- import { join as join3 } from "path";
66
- import { homedir as homedir3 } from "os";
64
+ import { readdirSync as readdirSync3, existsSync as existsSync6 } from "fs";
65
+ import { join as join6 } from "path";
66
+ import { homedir as homedir5 } from "os";
67
67
  import { hostname } from "os";
68
- import { homedir as homedir4 } from "os";
69
- import { join as join4 } from "path";
70
- import { join as join6, dirname } from "path";
71
- import { homedir as homedir5, platform } from "os";
68
+ import { homedir as homedir3 } from "os";
69
+ import { join as join3 } from "path";
70
+ import { join as join5, dirname } from "path";
71
+ import { homedir as homedir4, platform } from "os";
72
72
  function __accessProp2(key) {
73
73
  return this[key];
74
74
  }
@@ -996,11 +996,11 @@ function isSyncExcludedTable(table) {
996
996
  return SYNC_EXCLUDED_TABLE_PATTERNS.some((p) => p.test(table));
997
997
  }
998
998
  function discoverServices() {
999
- const dataDir = join3(homedir3(), ".hasna");
1000
- if (!existsSync3(dataDir))
999
+ const dataDir = join6(homedir5(), ".hasna");
1000
+ if (!existsSync6(dataDir))
1001
1001
  return [];
1002
1002
  try {
1003
- const entries = readdirSync2(dataDir, { withFileTypes: true });
1003
+ const entries = readdirSync3(dataDir, { withFileTypes: true });
1004
1004
  return entries.filter((e) => {
1005
1005
  if (!e.isDirectory())
1006
1006
  return false;
@@ -1012,30 +1012,30 @@ function discoverServices() {
1012
1012
  return [];
1013
1013
  }
1014
1014
  }
1015
- function discoverSyncableServices() {
1015
+ function discoverSyncableServices2() {
1016
1016
  const local = discoverServices();
1017
1017
  const pgSet = new Set(KNOWN_PG_SERVICES);
1018
1018
  return local.filter((s) => pgSet.has(s));
1019
1019
  }
1020
1020
  function getServiceDbPath(service) {
1021
- const dataDir = join3(homedir3(), ".hasna", service);
1022
- if (!existsSync3(dataDir))
1021
+ const dataDir = join6(homedir5(), ".hasna", service);
1022
+ if (!existsSync6(dataDir))
1023
1023
  return null;
1024
1024
  const candidates = [
1025
- join3(dataDir, `${service}.db`),
1026
- join3(dataDir, "data.db"),
1027
- join3(dataDir, "database.db")
1025
+ join6(dataDir, `${service}.db`),
1026
+ join6(dataDir, "data.db"),
1027
+ join6(dataDir, "database.db")
1028
1028
  ];
1029
1029
  try {
1030
- const files = readdirSync2(dataDir);
1030
+ const files = readdirSync3(dataDir);
1031
1031
  for (const f of files) {
1032
1032
  if (f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm")) {
1033
- candidates.push(join3(dataDir, f));
1033
+ candidates.push(join6(dataDir, f));
1034
1034
  }
1035
1035
  }
1036
1036
  } catch {}
1037
1037
  for (const p of candidates) {
1038
- if (existsSync3(p))
1038
+ if (existsSync6(p))
1039
1039
  return p;
1040
1040
  }
1041
1041
  return null;
@@ -1342,9 +1342,9 @@ async function syncTransfer(source, target, options, _direction) {
1342
1342
  const batch = rows.slice(offset, offset + batchSize);
1343
1343
  try {
1344
1344
  if (isAsyncAdapter(target)) {
1345
- await batchUpsertPg(target, table, columns, updateCols, pkColumns, batch, columns.includes(conflictColumn) ? conflictColumn : undefined);
1345
+ await batchUpsertPg(target, table, columns, updateCols, pkColumns, batch);
1346
1346
  } else {
1347
- batchUpsertSqlite(target, table, columns, updateCols, pkColumns, batch, columns.includes(conflictColumn) ? conflictColumn : undefined);
1347
+ batchUpsertSqlite(target, table, columns, updateCols, pkColumns, batch);
1348
1348
  }
1349
1349
  result.rowsWritten += batch.length;
1350
1350
  } catch (err) {
@@ -1391,7 +1391,7 @@ async function syncTransfer(source, target, options, _direction) {
1391
1391
  }
1392
1392
  return results;
1393
1393
  }
1394
- async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, batch, conflictColumn) {
1394
+ async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, batch) {
1395
1395
  if (batch.length === 0)
1396
1396
  return;
1397
1397
  const colList = columns.map((c) => `"${c}"`).join(", ");
@@ -1401,22 +1401,20 @@ async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, ba
1401
1401
  }).join(", ");
1402
1402
  const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
1403
1403
  const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
1404
- const whereClause = conflictColumn && updateCols.includes(conflictColumn) ? ` WHERE "${table}"."${conflictColumn}" IS NULL OR EXCLUDED."${conflictColumn}" >= "${table}"."${conflictColumn}"` : "";
1405
1404
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
1406
- ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}${whereClause}`;
1405
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
1407
1406
  const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
1408
1407
  await target.run(sql, ...params);
1409
1408
  }
1410
- function batchUpsertSqlite(target, table, columns, updateCols, primaryKeys, batch, conflictColumn) {
1409
+ function batchUpsertSqlite(target, table, columns, updateCols, primaryKeys, batch) {
1411
1410
  if (batch.length === 0)
1412
1411
  return;
1413
1412
  const colList = columns.map((c) => `"${c}"`).join(", ");
1414
1413
  const valuePlaceholders = batch.map(() => `(${columns.map(() => "?").join(", ")})`).join(", ");
1415
1414
  const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
1416
1415
  const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
1417
- const whereClause = conflictColumn && updateCols.includes(conflictColumn) ? ` WHERE "${table}"."${conflictColumn}" IS NULL OR EXCLUDED."${conflictColumn}" >= "${table}"."${conflictColumn}"` : "";
1418
1416
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
1419
- ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}${whereClause}`;
1417
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
1420
1418
  const params = batch.flatMap((row) => columns.map((c) => coerceForSqlite(row[c])));
1421
1419
  target.run(sql, ...params);
1422
1420
  }
@@ -1641,7 +1639,7 @@ class SyncProgressTracker {
1641
1639
  }
1642
1640
  }
1643
1641
  }
1644
- function registerCloudTools(server, serviceName, opts = {}) {
1642
+ function registerCloudTools(server, serviceName) {
1645
1643
  server.tool(`${serviceName}_cloud_status`, "Show cloud configuration and connection health", {}, async () => {
1646
1644
  const config = getCloudConfig();
1647
1645
  const lines = [
@@ -1674,13 +1672,8 @@ function registerCloudTools(server, serviceName, opts = {}) {
1674
1672
  isError: true
1675
1673
  };
1676
1674
  }
1677
- const local = new SqliteAdapter(opts.dbPath ?? getDbPath(serviceName));
1675
+ const local = new SqliteAdapter(getDbPath(serviceName));
1678
1676
  const cloud = new PgAdapterAsync(getConnectionString(serviceName));
1679
- if (opts.migrations?.length) {
1680
- for (const sql of opts.migrations) {
1681
- await cloud.run(sql);
1682
- }
1683
- }
1684
1677
  const tableList = tablesStr ? tablesStr.split(",").map((t) => t.trim()) : listSqliteTables(local);
1685
1678
  const results = await syncPush(local, cloud, { tables: tableList });
1686
1679
  local.close();
@@ -1702,7 +1695,7 @@ function registerCloudTools(server, serviceName, opts = {}) {
1702
1695
  isError: true
1703
1696
  };
1704
1697
  }
1705
- const local = new SqliteAdapter(opts.dbPath ?? getDbPath(serviceName));
1698
+ const local = new SqliteAdapter(getDbPath(serviceName));
1706
1699
  const cloud = new PgAdapterAsync(getConnectionString(serviceName));
1707
1700
  let tableList;
1708
1701
  if (tablesStr) {
@@ -10007,7 +10000,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
10007
10000
  __export2(exports_discover, {
10008
10001
  isSyncExcludedTable: () => isSyncExcludedTable,
10009
10002
  getServiceDbPath: () => getServiceDbPath,
10010
- discoverSyncableServices: () => discoverSyncableServices,
10003
+ discoverSyncableServices: () => discoverSyncableServices2,
10011
10004
  discoverServices: () => discoverServices,
10012
10005
  SYNC_EXCLUDED_TABLE_PATTERNS: () => SYNC_EXCLUDED_TABLE_PATTERNS,
10013
10006
  KNOWN_PG_SERVICES: () => KNOWN_PG_SERVICES
@@ -10062,15 +10055,13 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
10062
10055
  init_config();
10063
10056
  init_config();
10064
10057
  init_dotfile();
10065
- init_adapter();
10066
10058
  init_config();
10067
- init_discover();
10068
- AUTO_SYNC_CONFIG_PATH = join4(homedir4(), ".hasna", "cloud", "config.json");
10059
+ AUTO_SYNC_CONFIG_PATH = join3(homedir3(), ".hasna", "cloud", "config.json");
10069
10060
  init_config();
10070
10061
  init_adapter();
10071
10062
  init_dotfile();
10072
10063
  init_config();
10073
- CONFIG_DIR2 = join6(homedir5(), ".hasna", "cloud");
10064
+ CONFIG_DIR2 = join5(homedir4(), ".hasna", "cloud");
10074
10065
  init_adapter();
10075
10066
  init_config();
10076
10067
  init_discover();
@@ -10084,18 +10075,18 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
10084
10075
  });
10085
10076
 
10086
10077
  // src/db/database.ts
10087
- import { copyFileSync as copyFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync3, statSync } from "fs";
10088
- import { dirname as dirname2, join as join5, resolve } from "path";
10078
+ import { copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync2, statSync } from "fs";
10079
+ import { dirname as dirname2, join as join4, resolve } from "path";
10089
10080
  function getDataDir2() {
10090
10081
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
10091
- const newDir = join5(home, ".hasna", "contacts");
10092
- const oldDir = join5(home, ".contacts");
10093
- if (existsSync4(oldDir) && !existsSync4(newDir)) {
10082
+ const newDir = join4(home, ".hasna", "contacts");
10083
+ const oldDir = join4(home, ".contacts");
10084
+ if (existsSync3(oldDir) && !existsSync3(newDir)) {
10094
10085
  mkdirSync3(newDir, { recursive: true });
10095
- for (const file of readdirSync3(oldDir)) {
10096
- const oldPath = join5(oldDir, file);
10086
+ for (const file of readdirSync2(oldDir)) {
10087
+ const oldPath = join4(oldDir, file);
10097
10088
  if (statSync(oldPath).isFile()) {
10098
- copyFileSync2(oldPath, join5(newDir, file));
10089
+ copyFileSync2(oldPath, join4(newDir, file));
10099
10090
  }
10100
10091
  }
10101
10092
  }
@@ -10107,13 +10098,13 @@ function getDbPath2() {
10107
10098
  return process.env["HASNA_CONTACTS_DB_PATH"];
10108
10099
  if (process.env["CONTACTS_DB_PATH"])
10109
10100
  return process.env["CONTACTS_DB_PATH"];
10110
- return join5(getDataDir2(), "contacts.db");
10101
+ return join4(getDataDir2(), "contacts.db");
10111
10102
  }
10112
10103
  function ensureDir(filePath) {
10113
10104
  if (filePath === ":memory:")
10114
10105
  return;
10115
10106
  const dir = dirname2(resolve(filePath));
10116
- if (!existsSync4(dir))
10107
+ if (!existsSync3(dir))
10117
10108
  mkdirSync3(dir, { recursive: true });
10118
10109
  }
10119
10110
  function getDatabase(path) {
@@ -17933,8 +17924,8 @@ var init_events = __esm(() => {
17933
17924
  // src/server/serve.ts
17934
17925
  init_database();
17935
17926
  init_contacts();
17936
- import { existsSync as existsSync11 } from "fs";
17937
- import { join as join11 } from "path";
17927
+ import { existsSync as existsSync12 } from "fs";
17928
+ import { join as join12 } from "path";
17938
17929
 
17939
17930
  // src/db/companies.ts
17940
17931
  init_types2();
@@ -18755,11 +18746,11 @@ async function exportContacts(format, contacts) {
18755
18746
 
18756
18747
  // src/lib/images.ts
18757
18748
  init_database();
18758
- import { existsSync as existsSync6, mkdirSync as mkdirSync5, copyFileSync as copyFileSync3, unlinkSync, readdirSync as readdirSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
18749
+ import { existsSync as existsSync5, mkdirSync as mkdirSync5, copyFileSync as copyFileSync3, unlinkSync, readdirSync as readdirSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
18759
18750
  import { join as join7, extname, basename } from "path";
18760
18751
  var IMAGES_DIR = join7(getDataDir2(), "images");
18761
18752
  function ensureImagesDir() {
18762
- if (!existsSync6(IMAGES_DIR))
18753
+ if (!existsSync5(IMAGES_DIR))
18763
18754
  mkdirSync5(IMAGES_DIR, { recursive: true });
18764
18755
  }
18765
18756
  function getImagesDir() {
@@ -18777,14 +18768,14 @@ function saveImage(entityId, source, options) {
18777
18768
  writeFileSync2(join7(IMAGES_DIR, filename2), data);
18778
18769
  return filename2;
18779
18770
  }
18780
- if (!existsSync6(source) && /^[A-Za-z0-9+/=\n\r]+$/.test(source.trim()) && source.length > 100) {
18771
+ if (!existsSync5(source) && /^[A-Za-z0-9+/=\n\r]+$/.test(source.trim()) && source.length > 100) {
18781
18772
  const ext2 = options?.format || "jpg";
18782
18773
  const data = Buffer.from(source.trim(), "base64");
18783
18774
  const filename2 = `${entityId}.${ext2}`;
18784
18775
  writeFileSync2(join7(IMAGES_DIR, filename2), data);
18785
18776
  return filename2;
18786
18777
  }
18787
- if (!existsSync6(source)) {
18778
+ if (!existsSync5(source)) {
18788
18779
  throw new Error(`Image file not found: ${source}`);
18789
18780
  }
18790
18781
  const ext = extname(source).slice(1).toLowerCase() || "jpg";
@@ -18798,7 +18789,7 @@ function saveImage(entityId, source, options) {
18798
18789
  }
18799
18790
  function getImagePath(entityId) {
18800
18791
  ensureImagesDir();
18801
- const files = readdirSync5(IMAGES_DIR);
18792
+ const files = readdirSync4(IMAGES_DIR);
18802
18793
  const match = files.find((f) => f.startsWith(`${entityId}.`));
18803
18794
  return match ? join7(IMAGES_DIR, match) : null;
18804
18795
  }
@@ -18813,7 +18804,7 @@ function getImageAsBase64(entityId) {
18813
18804
  }
18814
18805
  function deleteImage(entityId) {
18815
18806
  ensureImagesDir();
18816
- const files = readdirSync5(IMAGES_DIR);
18807
+ const files = readdirSync4(IMAGES_DIR);
18817
18808
  let deleted = false;
18818
18809
  for (const f of files) {
18819
18810
  if (f.startsWith(`${entityId}.`)) {
@@ -22149,7 +22140,7 @@ class JSONSchemaGenerator {
22149
22140
  if (val === undefined) {
22150
22141
  if (this.unrepresentable === "throw") {
22151
22142
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
22152
- } else {}
22143
+ }
22153
22144
  } else if (typeof val === "bigint") {
22154
22145
  if (this.unrepresentable === "throw") {
22155
22146
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -24705,7 +24696,7 @@ function startMcpHttpServer(options) {
24705
24696
 
24706
24697
  // src/mcp/index.ts
24707
24698
  import { readFileSync as readFileSync6 } from "fs";
24708
- import { join as join10 } from "path";
24699
+ import { join as join11 } from "path";
24709
24700
 
24710
24701
  // node_modules/zod/v3/external.js
24711
24702
  var exports_external2 = {};
@@ -32371,7 +32362,7 @@ class StdioServerTransport {
32371
32362
  init_dist();
32372
32363
 
32373
32364
  // src/lib/connector.ts
32374
- import { join as join8 } from "path";
32365
+ import { join as join9 } from "path";
32375
32366
  import { existsSync as existsSync7, readFileSync as readFileSync3 } from "fs";
32376
32367
  import { homedir as homedir6 } from "os";
32377
32368
 
@@ -32441,9 +32432,9 @@ async function runConnector(name, args, opts = {}) {
32441
32432
  }
32442
32433
  function getConnectorTokenPath(name, profile = "default") {
32443
32434
  const bases = [
32444
- join8(homedir6(), ".connectors", `connect-${name}`, "profiles", profile, "tokens.json"),
32445
- join8(homedir6(), ".connect", `connect-${name}`, "profiles", profile, "tokens.json"),
32446
- join8(homedir6(), ".connect", `connect-${name}`, "tokens.json")
32435
+ join9(homedir6(), ".connectors", `connect-${name}`, "profiles", profile, "tokens.json"),
32436
+ join9(homedir6(), ".connect", `connect-${name}`, "profiles", profile, "tokens.json"),
32437
+ join9(homedir6(), ".connect", `connect-${name}`, "tokens.json")
32447
32438
  ];
32448
32439
  for (const p of bases) {
32449
32440
  if (existsSync7(p))
@@ -35440,13 +35431,13 @@ function getCoverageGaps(companyId, db) {
35440
35431
 
35441
35432
  // src/lib/vault.ts
35442
35433
  init_database();
35443
- import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2 } from "fs";
35444
- import { join as join9 } from "path";
35434
+ import { existsSync as existsSync9, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2 } from "fs";
35435
+ import { join as join10 } from "path";
35445
35436
  import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync, createHash } from "crypto";
35446
35437
  var VAULT_DIR = getDataDir2();
35447
- var VAULT_CONFIG = join9(VAULT_DIR, "vault.json");
35448
- var VAULT_SESSION = join9(VAULT_DIR, ".vault-session");
35449
- var DOCUMENTS_DIR = join9(VAULT_DIR, "documents");
35438
+ var VAULT_CONFIG = join10(VAULT_DIR, "vault.json");
35439
+ var VAULT_SESSION = join10(VAULT_DIR, ".vault-session");
35440
+ var DOCUMENTS_DIR = join10(VAULT_DIR, "documents");
35450
35441
  var SESSION_TTL_MS = 30 * 60 * 1000;
35451
35442
  var _derivedKey = null;
35452
35443
  function deriveKey(passphrase, salt) {
@@ -35460,7 +35451,7 @@ function saveSession(key) {
35460
35451
  writeFileSync3(VAULT_SESSION, JSON.stringify(session), { mode: 384 });
35461
35452
  }
35462
35453
  function loadSession() {
35463
- if (!existsSync8(VAULT_SESSION))
35454
+ if (!existsSync9(VAULT_SESSION))
35464
35455
  return null;
35465
35456
  try {
35466
35457
  const session = JSON.parse(readFileSync4(VAULT_SESSION, "utf-8"));
@@ -35477,14 +35468,14 @@ function loadSession() {
35477
35468
  }
35478
35469
  function clearSession() {
35479
35470
  try {
35480
- if (existsSync8(VAULT_SESSION))
35471
+ if (existsSync9(VAULT_SESSION))
35481
35472
  unlinkSync2(VAULT_SESSION);
35482
35473
  } catch {}
35483
35474
  }
35484
35475
  function initVault(passphrase) {
35485
- if (!existsSync8(VAULT_DIR))
35476
+ if (!existsSync9(VAULT_DIR))
35486
35477
  mkdirSync6(VAULT_DIR, { recursive: true });
35487
- if (!existsSync8(DOCUMENTS_DIR))
35478
+ if (!existsSync9(DOCUMENTS_DIR))
35488
35479
  mkdirSync6(DOCUMENTS_DIR, { recursive: true });
35489
35480
  const salt = randomBytes(32);
35490
35481
  const key = deriveKey(passphrase, salt);
@@ -35495,10 +35486,10 @@ function initVault(passphrase) {
35495
35486
  saveSession(key);
35496
35487
  }
35497
35488
  function isVaultInitialized() {
35498
- return existsSync8(VAULT_CONFIG);
35489
+ return existsSync9(VAULT_CONFIG);
35499
35490
  }
35500
35491
  function unlockVault(passphrase) {
35501
- if (!existsSync8(VAULT_CONFIG))
35492
+ if (!existsSync9(VAULT_CONFIG))
35502
35493
  throw new Error("Vault not initialized. Run 'contacts vault init' first.");
35503
35494
  const config2 = JSON.parse(readFileSync4(VAULT_CONFIG, "utf-8"));
35504
35495
  const salt = Buffer.from(config2.salt, "hex");
@@ -35555,10 +35546,10 @@ function decrypt(ciphertext, iv) {
35555
35546
  return decrypted;
35556
35547
  }
35557
35548
  function storeFile(sourcePath, entityId) {
35558
- if (!existsSync8(DOCUMENTS_DIR))
35549
+ if (!existsSync9(DOCUMENTS_DIR))
35559
35550
  mkdirSync6(DOCUMENTS_DIR, { recursive: true });
35560
35551
  const ext = sourcePath.split(".").pop() || "bin";
35561
- const destPath = join9(DOCUMENTS_DIR, `${entityId}.${ext}`);
35552
+ const destPath = join10(DOCUMENTS_DIR, `${entityId}.${ext}`);
35562
35553
  const data = readFileSync4(sourcePath);
35563
35554
  writeFileSync3(destPath, data);
35564
35555
  return destPath;
@@ -35566,7 +35557,7 @@ function storeFile(sourcePath, entityId) {
35566
35557
 
35567
35558
  // src/db/documents.ts
35568
35559
  init_database();
35569
- import { existsSync as existsSync9, unlinkSync as unlinkSync3 } from "fs";
35560
+ import { existsSync as existsSync10, unlinkSync as unlinkSync3 } from "fs";
35570
35561
  var DOCUMENT_TYPES = [
35571
35562
  "passport",
35572
35563
  "national_id",
@@ -35623,7 +35614,7 @@ function listDocuments(contactId, db) {
35623
35614
  function deleteDocument(id, db) {
35624
35615
  const _db2 = db || getDatabase();
35625
35616
  const row = _db2.query(`SELECT encrypted_file_path FROM contact_documents WHERE id = ?`).get(id);
35626
- if (row?.encrypted_file_path && existsSync9(row.encrypted_file_path)) {
35617
+ if (row?.encrypted_file_path && existsSync10(row.encrypted_file_path)) {
35627
35618
  try {
35628
35619
  unlinkSync3(row.encrypted_file_path);
35629
35620
  } catch {}
@@ -35741,7 +35732,7 @@ function deleteHealthData(contactId, db) {
35741
35732
  }
35742
35733
 
35743
35734
  // src/lib/document-scanner.ts
35744
- import { readFileSync as readFileSync5, existsSync as existsSync10 } from "fs";
35735
+ import { readFileSync as readFileSync5, existsSync as existsSync11 } from "fs";
35745
35736
  import { extname as extname2 } from "path";
35746
35737
  async function scanDocument(imageSource, docType) {
35747
35738
  const apiKey = process.env["OPENAI_API_KEY"];
@@ -35751,7 +35742,7 @@ async function scanDocument(imageSource, docType) {
35751
35742
  let imageData;
35752
35743
  if (imageSource.startsWith("data:image/")) {
35753
35744
  imageData = imageSource;
35754
- } else if (existsSync10(imageSource)) {
35745
+ } else if (existsSync11(imageSource)) {
35755
35746
  const buffer = readFileSync5(imageSource);
35756
35747
  const ext = extname2(imageSource).slice(1).toLowerCase();
35757
35748
  const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "png" ? "image/png" : ext === "webp" ? "image/webp" : ext === "gif" ? "image/gif" : "image/jpeg";
@@ -38012,7 +38003,7 @@ function registerContactsTools(server) {
38012
38003
  // src/mcp/index.ts
38013
38004
  function getServerVersion() {
38014
38005
  try {
38015
- const packageJsonPath = join10(import.meta.dir, "..", "..", "package.json");
38006
+ const packageJsonPath = join11(import.meta.dir, "..", "..", "package.json");
38016
38007
  const pkg = JSON.parse(readFileSync6(packageJsonPath, "utf8"));
38017
38008
  return pkg.version ?? "0.0.0";
38018
38009
  } catch {
@@ -38048,7 +38039,7 @@ if (isDirectRun) {
38048
38039
  }
38049
38040
 
38050
38041
  // src/server/serve.ts
38051
- var DASHBOARD_DIST = join11(import.meta.dir, "../../dashboard/dist");
38042
+ var DASHBOARD_DIST = join12(import.meta.dir, "../../dashboard/dist");
38052
38043
  function json3(data, status = 200) {
38053
38044
  return new Response(JSON.stringify(data), {
38054
38045
  status,
@@ -38263,7 +38254,7 @@ function handleDocumentFiles(req, segments) {
38263
38254
  if (sub === "file") {
38264
38255
  const db = getDatabase();
38265
38256
  const row = db.query(`SELECT encrypted_file_path FROM contact_documents WHERE id = ?`).get(docId);
38266
- if (!row?.encrypted_file_path || !existsSync11(row.encrypted_file_path)) {
38257
+ if (!row?.encrypted_file_path || !existsSync12(row.encrypted_file_path)) {
38267
38258
  return new Response("No file attachment", { status: 404 });
38268
38259
  }
38269
38260
  return new Response(Bun.file(row.encrypted_file_path), {
@@ -38278,7 +38269,7 @@ async function handleImages(req, _url2, segments) {
38278
38269
  return apiError("Entity ID required");
38279
38270
  if (req.method === "GET") {
38280
38271
  const imagePath = getImagePath(entityId);
38281
- if (!imagePath || !existsSync11(imagePath)) {
38272
+ if (!imagePath || !existsSync12(imagePath)) {
38282
38273
  return new Response(null, { status: 404, headers: { "Content-Type": "text/plain" } });
38283
38274
  }
38284
38275
  return new Response(Bun.file(imagePath), {
@@ -38294,7 +38285,7 @@ async function handleImages(req, _url2, segments) {
38294
38285
  return apiError("No image file in form data");
38295
38286
  const ext = file.name?.split(".").pop() || "jpg";
38296
38287
  const buffer = Buffer.from(await file.arrayBuffer());
38297
- const tmpPath = join11(getImagesDir(), `_upload_${entityId}.${ext}`);
38288
+ const tmpPath = join12(getImagesDir(), `_upload_${entityId}.${ext}`);
38298
38289
  const { writeFileSync: wfs } = await import("fs");
38299
38290
  wfs(tmpPath, buffer);
38300
38291
  try {
@@ -38325,7 +38316,7 @@ async function handleImages(req, _url2, segments) {
38325
38316
  return apiError("Method not allowed", 405);
38326
38317
  }
38327
38318
  function serveStaticFile(filePath) {
38328
- if (!existsSync11(filePath))
38319
+ if (!existsSync12(filePath))
38329
38320
  return null;
38330
38321
  return new Response(Bun.file(filePath));
38331
38322
  }
@@ -38381,8 +38372,8 @@ function startServer(port) {
38381
38372
  response = apiError("Not found", 404);
38382
38373
  }
38383
38374
  } else {
38384
- const filePath = join11(DASHBOARD_DIST, url.pathname === "/" ? "index.html" : url.pathname);
38385
- response = serveStaticFile(filePath) ?? serveStaticFile(join11(DASHBOARD_DIST, "index.html")) ?? new Response("Not Found", { status: 404 });
38375
+ const filePath = join12(DASHBOARD_DIST, url.pathname === "/" ? "index.html" : url.pathname);
38376
+ response = serveStaticFile(filePath) ?? serveStaticFile(join12(DASHBOARD_DIST, "index.html")) ?? new Response("Not Found", { status: 404 });
38386
38377
  }
38387
38378
  } catch (err) {
38388
38379
  console.error("Request error:", err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/contacts",
3
- "version": "0.6.18",
3
+ "version": "0.6.20",
4
4
  "description": "Contact management for AI coding agents — CLI + MCP + Web",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -61,7 +61,8 @@
61
61
  "author": "Andrei Hasna <andrei@hasna.com>",
62
62
  "license": "Apache-2.0",
63
63
  "dependencies": {
64
- "@hasna/cloud": "^0.1.24",
64
+ "@hasna/cloud": "0.1.24",
65
+ "@hasna/events": "^0.1.6",
65
66
  "@modelcontextprotocol/sdk": "^1.12.1",
66
67
  "chalk": "^5.4.1",
67
68
  "commander": "^13.1.0",