@hasna/cloud 0.1.4 → 0.1.6

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/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # @hasna/cloud
2
+
3
+ Shared cloud infrastructure — database adapter (SQLite + PostgreSQL), sync engine, feedback system, unified dotfile config
4
+
5
+ [![npm](https://img.shields.io/npm/v/@hasna/cloud)](https://www.npmjs.com/package/@hasna/cloud)
6
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install -g @hasna/cloud
12
+ ```
13
+
14
+ ## CLI Usage
15
+
16
+ ```bash
17
+ cloud --help
18
+ ```
19
+
20
+ - `cloud setup`
21
+ - `cloud status`
22
+ - `cloud sync push`
23
+ - `cloud sync pull`
24
+ - `cloud feedback`
25
+ - `cloud migrate`
26
+
27
+ ## MCP Server
28
+
29
+ ```bash
30
+ cloud-mcp
31
+ ```
32
+
33
+ 4 tools available.
34
+
35
+ ## License
36
+
37
+ Apache-2.0 -- see [LICENSE](LICENSE)
package/dist/adapter.d.ts CHANGED
@@ -26,6 +26,8 @@ export declare class SqliteAdapter implements DbAdapter {
26
26
  get(sql: string, ...params: any[]): any;
27
27
  all(sql: string, ...params: any[]): any[];
28
28
  exec(sql: string): void;
29
+ /** Passthrough to bun:sqlite's .query() for compatibility with code that uses db.query() */
30
+ query(sql: string): import("bun:sqlite").Statement<unknown, import("bun:sqlite").SQLQueryBindings[] | [null] | [string] | [number] | [bigint] | [false] | [true] | [Uint8Array<ArrayBufferLike>] | [Uint8ClampedArray<ArrayBufferLike>] | [Uint16Array<ArrayBufferLike>] | [Uint32Array<ArrayBufferLike>] | [Int8Array<ArrayBufferLike>] | [Int16Array<ArrayBufferLike>] | [Int32Array<ArrayBufferLike>] | [BigUint64Array<ArrayBufferLike>] | [BigInt64Array<ArrayBufferLike>] | [Float16Array<ArrayBufferLike>] | [Float32Array<ArrayBufferLike>] | [Float64Array<ArrayBufferLike>] | [Record<string, string | number | bigint | boolean | NodeJS.TypedArray<ArrayBufferLike> | null>]>;
29
31
  prepare(sql: string): PreparedStatement;
30
32
  close(): void;
31
33
  transaction<T>(fn: () => T): T;
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
package/dist/cli/index.js CHANGED
@@ -11026,6 +11026,9 @@ class SqliteAdapter {
11026
11026
  exec(sql) {
11027
11027
  this.db.exec(sql);
11028
11028
  }
11029
+ query(sql) {
11030
+ return this.db.query(sql);
11031
+ }
11029
11032
  prepare(sql) {
11030
11033
  const stmt = this.db.prepare(sql);
11031
11034
  return {
@@ -11334,13 +11337,56 @@ function heuristicOrder(tables) {
11334
11337
  });
11335
11338
  return sorted;
11336
11339
  }
11340
+ function getSqlitePrimaryKeys(adapter, table) {
11341
+ try {
11342
+ const cols = adapter.all(`PRAGMA table_info("${table}")`);
11343
+ const pkCols = cols.filter((c) => c.pk > 0).sort((a, b) => a.pk - b.pk).map((c) => c.name);
11344
+ return pkCols;
11345
+ } catch {
11346
+ return [];
11347
+ }
11348
+ }
11349
+ async function getPgPrimaryKeys(adapter, table) {
11350
+ try {
11351
+ const rows = await adapter.all(`
11352
+ SELECT kcu.column_name, kcu.ordinal_position
11353
+ FROM information_schema.table_constraints tc
11354
+ JOIN information_schema.key_column_usage kcu
11355
+ ON tc.constraint_name = kcu.constraint_name
11356
+ AND tc.table_schema = kcu.table_schema
11357
+ WHERE tc.constraint_type = 'PRIMARY KEY'
11358
+ AND tc.table_schema = 'public'
11359
+ AND tc.table_name = '${table}'
11360
+ ORDER BY kcu.ordinal_position
11361
+ `);
11362
+ return rows.map((r) => r.column_name);
11363
+ } catch {
11364
+ return [];
11365
+ }
11366
+ }
11367
+ async function detectPrimaryKeys(adapter, table) {
11368
+ if (isAsyncAdapter(adapter)) {
11369
+ return getPgPrimaryKeys(adapter, table);
11370
+ }
11371
+ return getSqlitePrimaryKeys(adapter, table);
11372
+ }
11373
+ async function resolvePrimaryKeys(source, target, table, pkOption) {
11374
+ if (pkOption) {
11375
+ return Array.isArray(pkOption) ? pkOption : [pkOption];
11376
+ }
11377
+ let pks = await detectPrimaryKeys(source, table);
11378
+ if (pks.length === 0) {
11379
+ pks = await detectPrimaryKeys(target, table);
11380
+ }
11381
+ return pks;
11382
+ }
11337
11383
  async function syncTransfer(source, target, options, _direction) {
11338
11384
  const {
11339
11385
  tables,
11340
11386
  onProgress,
11341
11387
  batchSize = 100,
11342
11388
  conflictColumn = "updated_at",
11343
- primaryKey = "id"
11389
+ primaryKey: pkOption
11344
11390
  } = options;
11345
11391
  const results = [];
11346
11392
  for (let i = 0;i < tables.length; i++) {
@@ -11375,10 +11421,45 @@ async function syncTransfer(source, target, options, _direction) {
11375
11421
  results.push(result);
11376
11422
  continue;
11377
11423
  }
11424
+ const pkColumns = await resolvePrimaryKeys(source, target, table, pkOption);
11378
11425
  const columns = Object.keys(rows[0]);
11379
- const hasPrimaryKey = columns.includes(primaryKey);
11380
- if (!hasPrimaryKey) {
11381
- result.errors.push(`Table "${table}" has no "${primaryKey}" column — skipping`);
11426
+ if (pkColumns.length === 0) {
11427
+ result.errors.push(`Table "${table}" has no primary key — inserting without conflict handling`);
11428
+ onProgress?.({
11429
+ table,
11430
+ phase: "writing",
11431
+ rowsRead: result.rowsRead,
11432
+ rowsWritten: 0,
11433
+ totalTables: tables.length,
11434
+ currentTableIndex: i
11435
+ });
11436
+ for (let offset = 0;offset < rows.length; offset += batchSize) {
11437
+ const batch = rows.slice(offset, offset + batchSize);
11438
+ try {
11439
+ if (isAsyncAdapter(target)) {
11440
+ await batchInsertPg(target, table, columns, batch);
11441
+ } else {
11442
+ batchInsertSqlite(target, table, columns, batch);
11443
+ }
11444
+ result.rowsWritten += batch.length;
11445
+ } catch (err) {
11446
+ result.errors.push(`Batch at offset ${offset}: ${err?.message ?? String(err)}`);
11447
+ }
11448
+ }
11449
+ onProgress?.({
11450
+ table,
11451
+ phase: "done",
11452
+ rowsRead: result.rowsRead,
11453
+ rowsWritten: result.rowsWritten,
11454
+ totalTables: tables.length,
11455
+ currentTableIndex: i
11456
+ });
11457
+ results.push(result);
11458
+ continue;
11459
+ }
11460
+ const missingPks = pkColumns.filter((pk) => !columns.includes(pk));
11461
+ if (missingPks.length > 0) {
11462
+ result.errors.push(`Table "${table}" missing PK columns in data: ${missingPks.join(", ")} — skipping`);
11382
11463
  results.push(result);
11383
11464
  continue;
11384
11465
  }
@@ -11390,14 +11471,14 @@ async function syncTransfer(source, target, options, _direction) {
11390
11471
  totalTables: tables.length,
11391
11472
  currentTableIndex: i
11392
11473
  });
11393
- const updateCols = columns.filter((c) => c !== primaryKey);
11474
+ const updateCols = columns.filter((c) => !pkColumns.includes(c));
11394
11475
  for (let offset = 0;offset < rows.length; offset += batchSize) {
11395
11476
  const batch = rows.slice(offset, offset + batchSize);
11396
11477
  try {
11397
11478
  if (isAsyncAdapter(target)) {
11398
- await batchUpsertPg(target, table, columns, updateCols, primaryKey, batch);
11479
+ await batchUpsertPg(target, table, columns, updateCols, pkColumns, batch);
11399
11480
  } else {
11400
- batchUpsertSqlite(target, table, columns, updateCols, primaryKey, batch);
11481
+ batchUpsertSqlite(target, table, columns, updateCols, pkColumns, batch);
11401
11482
  }
11402
11483
  result.rowsWritten += batch.length;
11403
11484
  } catch (err) {
@@ -11427,7 +11508,7 @@ async function syncTransfer(source, target, options, _direction) {
11427
11508
  }
11428
11509
  return results;
11429
11510
  }
11430
- async function batchUpsertPg(target, table, columns, updateCols, primaryKey, batch) {
11511
+ async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, batch) {
11431
11512
  if (batch.length === 0)
11432
11513
  return;
11433
11514
  const colList = columns.map((c) => `"${c}"`).join(", ");
@@ -11435,20 +11516,43 @@ async function batchUpsertPg(target, table, columns, updateCols, primaryKey, bat
11435
11516
  const offset = rowIdx * columns.length;
11436
11517
  return `(${columns.map((_2, colIdx) => `$${offset + colIdx + 1}`).join(", ")})`;
11437
11518
  }).join(", ");
11438
- const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKey}" = EXCLUDED."${primaryKey}"`;
11519
+ const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
11520
+ const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
11439
11521
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
11440
- ON CONFLICT ("${primaryKey}") DO UPDATE SET ${setClause}`;
11522
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
11441
11523
  const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
11442
11524
  await target.run(sql, ...params);
11443
11525
  }
11444
- function batchUpsertSqlite(target, table, columns, updateCols, primaryKey, batch) {
11526
+ function batchUpsertSqlite(target, table, columns, updateCols, primaryKeys, batch) {
11445
11527
  if (batch.length === 0)
11446
11528
  return;
11447
11529
  const colList = columns.map((c) => `"${c}"`).join(", ");
11448
11530
  const valuePlaceholders = batch.map(() => `(${columns.map(() => "?").join(", ")})`).join(", ");
11449
- const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKey}" = EXCLUDED."${primaryKey}"`;
11531
+ const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
11532
+ const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
11450
11533
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
11451
- ON CONFLICT ("${primaryKey}") DO UPDATE SET ${setClause}`;
11534
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
11535
+ const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
11536
+ target.run(sql, ...params);
11537
+ }
11538
+ async function batchInsertPg(target, table, columns, batch) {
11539
+ if (batch.length === 0)
11540
+ return;
11541
+ const colList = columns.map((c) => `"${c}"`).join(", ");
11542
+ const valuePlaceholders = batch.map((_, rowIdx) => {
11543
+ const offset = rowIdx * columns.length;
11544
+ return `(${columns.map((_2, colIdx) => `$${offset + colIdx + 1}`).join(", ")})`;
11545
+ }).join(", ");
11546
+ const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}`;
11547
+ const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
11548
+ await target.run(sql, ...params);
11549
+ }
11550
+ function batchInsertSqlite(target, table, columns, batch) {
11551
+ if (batch.length === 0)
11552
+ return;
11553
+ const colList = columns.map((c) => `"${c}"`).join(", ");
11554
+ const valuePlaceholders = batch.map(() => `(${columns.map(() => "?").join(", ")})`).join(", ");
11555
+ const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}`;
11452
11556
  const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
11453
11557
  target.run(sql, ...params);
11454
11558
  }
@@ -11639,6 +11743,9 @@ class SqliteAdapter2 {
11639
11743
  exec(sql) {
11640
11744
  this.db.exec(sql);
11641
11745
  }
11746
+ query(sql) {
11747
+ return this.db.query(sql);
11748
+ }
11642
11749
  prepare(sql) {
11643
11750
  const stmt = this.db.prepare(sql);
11644
11751
  return {
package/dist/index.js CHANGED
@@ -5007,6 +5007,9 @@ class SqliteAdapter {
5007
5007
  exec(sql) {
5008
5008
  this.db.exec(sql);
5009
5009
  }
5010
+ query(sql) {
5011
+ return this.db.query(sql);
5012
+ }
5010
5013
  prepare(sql) {
5011
5014
  const stmt = this.db.prepare(sql);
5012
5015
  return {
@@ -9386,13 +9389,56 @@ function heuristicOrder(tables) {
9386
9389
  });
9387
9390
  return sorted;
9388
9391
  }
9392
+ function getSqlitePrimaryKeys(adapter, table) {
9393
+ try {
9394
+ const cols = adapter.all(`PRAGMA table_info("${table}")`);
9395
+ const pkCols = cols.filter((c) => c.pk > 0).sort((a, b) => a.pk - b.pk).map((c) => c.name);
9396
+ return pkCols;
9397
+ } catch {
9398
+ return [];
9399
+ }
9400
+ }
9401
+ async function getPgPrimaryKeys(adapter, table) {
9402
+ try {
9403
+ const rows = await adapter.all(`
9404
+ SELECT kcu.column_name, kcu.ordinal_position
9405
+ FROM information_schema.table_constraints tc
9406
+ JOIN information_schema.key_column_usage kcu
9407
+ ON tc.constraint_name = kcu.constraint_name
9408
+ AND tc.table_schema = kcu.table_schema
9409
+ WHERE tc.constraint_type = 'PRIMARY KEY'
9410
+ AND tc.table_schema = 'public'
9411
+ AND tc.table_name = '${table}'
9412
+ ORDER BY kcu.ordinal_position
9413
+ `);
9414
+ return rows.map((r) => r.column_name);
9415
+ } catch {
9416
+ return [];
9417
+ }
9418
+ }
9419
+ async function detectPrimaryKeys(adapter, table) {
9420
+ if (isAsyncAdapter(adapter)) {
9421
+ return getPgPrimaryKeys(adapter, table);
9422
+ }
9423
+ return getSqlitePrimaryKeys(adapter, table);
9424
+ }
9425
+ async function resolvePrimaryKeys(source, target, table, pkOption) {
9426
+ if (pkOption) {
9427
+ return Array.isArray(pkOption) ? pkOption : [pkOption];
9428
+ }
9429
+ let pks = await detectPrimaryKeys(source, table);
9430
+ if (pks.length === 0) {
9431
+ pks = await detectPrimaryKeys(target, table);
9432
+ }
9433
+ return pks;
9434
+ }
9389
9435
  async function syncTransfer(source, target, options, _direction) {
9390
9436
  const {
9391
9437
  tables,
9392
9438
  onProgress,
9393
9439
  batchSize = 100,
9394
9440
  conflictColumn = "updated_at",
9395
- primaryKey = "id"
9441
+ primaryKey: pkOption
9396
9442
  } = options;
9397
9443
  const results = [];
9398
9444
  for (let i = 0;i < tables.length; i++) {
@@ -9427,10 +9473,45 @@ async function syncTransfer(source, target, options, _direction) {
9427
9473
  results.push(result);
9428
9474
  continue;
9429
9475
  }
9476
+ const pkColumns = await resolvePrimaryKeys(source, target, table, pkOption);
9430
9477
  const columns = Object.keys(rows[0]);
9431
- const hasPrimaryKey = columns.includes(primaryKey);
9432
- if (!hasPrimaryKey) {
9433
- result.errors.push(`Table "${table}" has no "${primaryKey}" column — skipping`);
9478
+ if (pkColumns.length === 0) {
9479
+ result.errors.push(`Table "${table}" has no primary key — inserting without conflict handling`);
9480
+ onProgress?.({
9481
+ table,
9482
+ phase: "writing",
9483
+ rowsRead: result.rowsRead,
9484
+ rowsWritten: 0,
9485
+ totalTables: tables.length,
9486
+ currentTableIndex: i
9487
+ });
9488
+ for (let offset = 0;offset < rows.length; offset += batchSize) {
9489
+ const batch = rows.slice(offset, offset + batchSize);
9490
+ try {
9491
+ if (isAsyncAdapter(target)) {
9492
+ await batchInsertPg(target, table, columns, batch);
9493
+ } else {
9494
+ batchInsertSqlite(target, table, columns, batch);
9495
+ }
9496
+ result.rowsWritten += batch.length;
9497
+ } catch (err) {
9498
+ result.errors.push(`Batch at offset ${offset}: ${err?.message ?? String(err)}`);
9499
+ }
9500
+ }
9501
+ onProgress?.({
9502
+ table,
9503
+ phase: "done",
9504
+ rowsRead: result.rowsRead,
9505
+ rowsWritten: result.rowsWritten,
9506
+ totalTables: tables.length,
9507
+ currentTableIndex: i
9508
+ });
9509
+ results.push(result);
9510
+ continue;
9511
+ }
9512
+ const missingPks = pkColumns.filter((pk) => !columns.includes(pk));
9513
+ if (missingPks.length > 0) {
9514
+ result.errors.push(`Table "${table}" missing PK columns in data: ${missingPks.join(", ")} — skipping`);
9434
9515
  results.push(result);
9435
9516
  continue;
9436
9517
  }
@@ -9442,14 +9523,14 @@ async function syncTransfer(source, target, options, _direction) {
9442
9523
  totalTables: tables.length,
9443
9524
  currentTableIndex: i
9444
9525
  });
9445
- const updateCols = columns.filter((c) => c !== primaryKey);
9526
+ const updateCols = columns.filter((c) => !pkColumns.includes(c));
9446
9527
  for (let offset = 0;offset < rows.length; offset += batchSize) {
9447
9528
  const batch = rows.slice(offset, offset + batchSize);
9448
9529
  try {
9449
9530
  if (isAsyncAdapter(target)) {
9450
- await batchUpsertPg(target, table, columns, updateCols, primaryKey, batch);
9531
+ await batchUpsertPg(target, table, columns, updateCols, pkColumns, batch);
9451
9532
  } else {
9452
- batchUpsertSqlite(target, table, columns, updateCols, primaryKey, batch);
9533
+ batchUpsertSqlite(target, table, columns, updateCols, pkColumns, batch);
9453
9534
  }
9454
9535
  result.rowsWritten += batch.length;
9455
9536
  } catch (err) {
@@ -9479,7 +9560,7 @@ async function syncTransfer(source, target, options, _direction) {
9479
9560
  }
9480
9561
  return results;
9481
9562
  }
9482
- async function batchUpsertPg(target, table, columns, updateCols, primaryKey, batch) {
9563
+ async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, batch) {
9483
9564
  if (batch.length === 0)
9484
9565
  return;
9485
9566
  const colList = columns.map((c) => `"${c}"`).join(", ");
@@ -9487,20 +9568,43 @@ async function batchUpsertPg(target, table, columns, updateCols, primaryKey, bat
9487
9568
  const offset = rowIdx * columns.length;
9488
9569
  return `(${columns.map((_2, colIdx) => `$${offset + colIdx + 1}`).join(", ")})`;
9489
9570
  }).join(", ");
9490
- const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKey}" = EXCLUDED."${primaryKey}"`;
9571
+ const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
9572
+ const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
9491
9573
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
9492
- ON CONFLICT ("${primaryKey}") DO UPDATE SET ${setClause}`;
9574
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
9493
9575
  const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
9494
9576
  await target.run(sql, ...params);
9495
9577
  }
9496
- function batchUpsertSqlite(target, table, columns, updateCols, primaryKey, batch) {
9578
+ function batchUpsertSqlite(target, table, columns, updateCols, primaryKeys, batch) {
9497
9579
  if (batch.length === 0)
9498
9580
  return;
9499
9581
  const colList = columns.map((c) => `"${c}"`).join(", ");
9500
9582
  const valuePlaceholders = batch.map(() => `(${columns.map(() => "?").join(", ")})`).join(", ");
9501
- const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKey}" = EXCLUDED."${primaryKey}"`;
9583
+ const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
9584
+ const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
9502
9585
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
9503
- ON CONFLICT ("${primaryKey}") DO UPDATE SET ${setClause}`;
9586
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
9587
+ const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
9588
+ target.run(sql, ...params);
9589
+ }
9590
+ async function batchInsertPg(target, table, columns, batch) {
9591
+ if (batch.length === 0)
9592
+ return;
9593
+ const colList = columns.map((c) => `"${c}"`).join(", ");
9594
+ const valuePlaceholders = batch.map((_, rowIdx) => {
9595
+ const offset = rowIdx * columns.length;
9596
+ return `(${columns.map((_2, colIdx) => `$${offset + colIdx + 1}`).join(", ")})`;
9597
+ }).join(", ");
9598
+ const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}`;
9599
+ const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
9600
+ await target.run(sql, ...params);
9601
+ }
9602
+ function batchInsertSqlite(target, table, columns, batch) {
9603
+ if (batch.length === 0)
9604
+ return;
9605
+ const colList = columns.map((c) => `"${c}"`).join(", ");
9606
+ const valuePlaceholders = batch.map(() => `(${columns.map(() => "?").join(", ")})`).join(", ");
9607
+ const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}`;
9504
9608
  const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
9505
9609
  target.run(sql, ...params);
9506
9610
  }
package/dist/mcp/index.js CHANGED
@@ -24430,6 +24430,9 @@ class SqliteAdapter {
24430
24430
  exec(sql) {
24431
24431
  this.db.exec(sql);
24432
24432
  }
24433
+ query(sql) {
24434
+ return this.db.query(sql);
24435
+ }
24433
24436
  prepare(sql) {
24434
24437
  const stmt = this.db.prepare(sql);
24435
24438
  return {
@@ -24733,13 +24736,56 @@ function heuristicOrder(tables) {
24733
24736
  });
24734
24737
  return sorted;
24735
24738
  }
24739
+ function getSqlitePrimaryKeys(adapter, table) {
24740
+ try {
24741
+ const cols = adapter.all(`PRAGMA table_info("${table}")`);
24742
+ const pkCols = cols.filter((c) => c.pk > 0).sort((a, b) => a.pk - b.pk).map((c) => c.name);
24743
+ return pkCols;
24744
+ } catch {
24745
+ return [];
24746
+ }
24747
+ }
24748
+ async function getPgPrimaryKeys(adapter, table) {
24749
+ try {
24750
+ const rows = await adapter.all(`
24751
+ SELECT kcu.column_name, kcu.ordinal_position
24752
+ FROM information_schema.table_constraints tc
24753
+ JOIN information_schema.key_column_usage kcu
24754
+ ON tc.constraint_name = kcu.constraint_name
24755
+ AND tc.table_schema = kcu.table_schema
24756
+ WHERE tc.constraint_type = 'PRIMARY KEY'
24757
+ AND tc.table_schema = 'public'
24758
+ AND tc.table_name = '${table}'
24759
+ ORDER BY kcu.ordinal_position
24760
+ `);
24761
+ return rows.map((r) => r.column_name);
24762
+ } catch {
24763
+ return [];
24764
+ }
24765
+ }
24766
+ async function detectPrimaryKeys(adapter, table) {
24767
+ if (isAsyncAdapter(adapter)) {
24768
+ return getPgPrimaryKeys(adapter, table);
24769
+ }
24770
+ return getSqlitePrimaryKeys(adapter, table);
24771
+ }
24772
+ async function resolvePrimaryKeys(source, target, table, pkOption) {
24773
+ if (pkOption) {
24774
+ return Array.isArray(pkOption) ? pkOption : [pkOption];
24775
+ }
24776
+ let pks = await detectPrimaryKeys(source, table);
24777
+ if (pks.length === 0) {
24778
+ pks = await detectPrimaryKeys(target, table);
24779
+ }
24780
+ return pks;
24781
+ }
24736
24782
  async function syncTransfer(source, target, options, _direction) {
24737
24783
  const {
24738
24784
  tables,
24739
24785
  onProgress,
24740
24786
  batchSize = 100,
24741
24787
  conflictColumn = "updated_at",
24742
- primaryKey = "id"
24788
+ primaryKey: pkOption
24743
24789
  } = options;
24744
24790
  const results = [];
24745
24791
  for (let i = 0;i < tables.length; i++) {
@@ -24774,10 +24820,45 @@ async function syncTransfer(source, target, options, _direction) {
24774
24820
  results.push(result);
24775
24821
  continue;
24776
24822
  }
24823
+ const pkColumns = await resolvePrimaryKeys(source, target, table, pkOption);
24777
24824
  const columns = Object.keys(rows[0]);
24778
- const hasPrimaryKey = columns.includes(primaryKey);
24779
- if (!hasPrimaryKey) {
24780
- result.errors.push(`Table "${table}" has no "${primaryKey}" column — skipping`);
24825
+ if (pkColumns.length === 0) {
24826
+ result.errors.push(`Table "${table}" has no primary key — inserting without conflict handling`);
24827
+ onProgress?.({
24828
+ table,
24829
+ phase: "writing",
24830
+ rowsRead: result.rowsRead,
24831
+ rowsWritten: 0,
24832
+ totalTables: tables.length,
24833
+ currentTableIndex: i
24834
+ });
24835
+ for (let offset = 0;offset < rows.length; offset += batchSize) {
24836
+ const batch = rows.slice(offset, offset + batchSize);
24837
+ try {
24838
+ if (isAsyncAdapter(target)) {
24839
+ await batchInsertPg(target, table, columns, batch);
24840
+ } else {
24841
+ batchInsertSqlite(target, table, columns, batch);
24842
+ }
24843
+ result.rowsWritten += batch.length;
24844
+ } catch (err) {
24845
+ result.errors.push(`Batch at offset ${offset}: ${err?.message ?? String(err)}`);
24846
+ }
24847
+ }
24848
+ onProgress?.({
24849
+ table,
24850
+ phase: "done",
24851
+ rowsRead: result.rowsRead,
24852
+ rowsWritten: result.rowsWritten,
24853
+ totalTables: tables.length,
24854
+ currentTableIndex: i
24855
+ });
24856
+ results.push(result);
24857
+ continue;
24858
+ }
24859
+ const missingPks = pkColumns.filter((pk) => !columns.includes(pk));
24860
+ if (missingPks.length > 0) {
24861
+ result.errors.push(`Table "${table}" missing PK columns in data: ${missingPks.join(", ")} — skipping`);
24781
24862
  results.push(result);
24782
24863
  continue;
24783
24864
  }
@@ -24789,14 +24870,14 @@ async function syncTransfer(source, target, options, _direction) {
24789
24870
  totalTables: tables.length,
24790
24871
  currentTableIndex: i
24791
24872
  });
24792
- const updateCols = columns.filter((c) => c !== primaryKey);
24873
+ const updateCols = columns.filter((c) => !pkColumns.includes(c));
24793
24874
  for (let offset = 0;offset < rows.length; offset += batchSize) {
24794
24875
  const batch = rows.slice(offset, offset + batchSize);
24795
24876
  try {
24796
24877
  if (isAsyncAdapter(target)) {
24797
- await batchUpsertPg(target, table, columns, updateCols, primaryKey, batch);
24878
+ await batchUpsertPg(target, table, columns, updateCols, pkColumns, batch);
24798
24879
  } else {
24799
- batchUpsertSqlite(target, table, columns, updateCols, primaryKey, batch);
24880
+ batchUpsertSqlite(target, table, columns, updateCols, pkColumns, batch);
24800
24881
  }
24801
24882
  result.rowsWritten += batch.length;
24802
24883
  } catch (err) {
@@ -24826,7 +24907,7 @@ async function syncTransfer(source, target, options, _direction) {
24826
24907
  }
24827
24908
  return results;
24828
24909
  }
24829
- async function batchUpsertPg(target, table, columns, updateCols, primaryKey, batch) {
24910
+ async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, batch) {
24830
24911
  if (batch.length === 0)
24831
24912
  return;
24832
24913
  const colList = columns.map((c) => `"${c}"`).join(", ");
@@ -24834,20 +24915,43 @@ async function batchUpsertPg(target, table, columns, updateCols, primaryKey, bat
24834
24915
  const offset = rowIdx * columns.length;
24835
24916
  return `(${columns.map((_2, colIdx) => `$${offset + colIdx + 1}`).join(", ")})`;
24836
24917
  }).join(", ");
24837
- const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKey}" = EXCLUDED."${primaryKey}"`;
24918
+ const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
24919
+ const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
24838
24920
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
24839
- ON CONFLICT ("${primaryKey}") DO UPDATE SET ${setClause}`;
24921
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
24840
24922
  const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
24841
24923
  await target.run(sql, ...params);
24842
24924
  }
24843
- function batchUpsertSqlite(target, table, columns, updateCols, primaryKey, batch) {
24925
+ function batchUpsertSqlite(target, table, columns, updateCols, primaryKeys, batch) {
24844
24926
  if (batch.length === 0)
24845
24927
  return;
24846
24928
  const colList = columns.map((c) => `"${c}"`).join(", ");
24847
24929
  const valuePlaceholders = batch.map(() => `(${columns.map(() => "?").join(", ")})`).join(", ");
24848
- const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKey}" = EXCLUDED."${primaryKey}"`;
24930
+ const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
24931
+ const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
24849
24932
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
24850
- ON CONFLICT ("${primaryKey}") DO UPDATE SET ${setClause}`;
24933
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
24934
+ const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
24935
+ target.run(sql, ...params);
24936
+ }
24937
+ async function batchInsertPg(target, table, columns, batch) {
24938
+ if (batch.length === 0)
24939
+ return;
24940
+ const colList = columns.map((c) => `"${c}"`).join(", ");
24941
+ const valuePlaceholders = batch.map((_, rowIdx) => {
24942
+ const offset = rowIdx * columns.length;
24943
+ return `(${columns.map((_2, colIdx) => `$${offset + colIdx + 1}`).join(", ")})`;
24944
+ }).join(", ");
24945
+ const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}`;
24946
+ const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
24947
+ await target.run(sql, ...params);
24948
+ }
24949
+ function batchInsertSqlite(target, table, columns, batch) {
24950
+ if (batch.length === 0)
24951
+ return;
24952
+ const colList = columns.map((c) => `"${c}"`).join(", ");
24953
+ const valuePlaceholders = batch.map(() => `(${columns.map(() => "?").join(", ")})`).join(", ");
24954
+ const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}`;
24851
24955
  const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
24852
24956
  target.run(sql, ...params);
24853
24957
  }
@@ -25012,6 +25116,9 @@ class SqliteAdapter2 {
25012
25116
  exec(sql) {
25013
25117
  this.db.exec(sql);
25014
25118
  }
25119
+ query(sql) {
25120
+ return this.db.query(sql);
25121
+ }
25015
25122
  prepare(sql) {
25016
25123
  const stmt = this.db.prepare(sql);
25017
25124
  return {
package/dist/sync.d.ts CHANGED
@@ -18,8 +18,12 @@ export interface SyncOptions {
18
18
  batchSize?: number;
19
19
  /** Conflict resolution column (default: "updated_at"). Newest wins. */
20
20
  conflictColumn?: string;
21
- /** Primary key column name (default: "id"). */
22
- primaryKey?: string;
21
+ /**
22
+ * Primary key column name(s). Can be a single column string or an array
23
+ * for composite primary keys (default: auto-detected from the database).
24
+ * If not provided and auto-detection fails, falls back to "id".
25
+ */
26
+ primaryKey?: string | string[];
23
27
  }
24
28
  export interface SyncResult {
25
29
  table: string;
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAMnD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;AAEpE,MAAM,WAAW,WAAW;IAC1B,sBAAsB;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,kCAAkC;IAClC,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAMD;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,EAAE,CAAC,CAGvB;AAMD;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,EAAE,CAAC,CAGvB;AAmWD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,EAAE,CAKxD;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAKxE"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAMnD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;AAEpE,MAAM,WAAW,WAAW;IAC1B,sBAAsB;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,kCAAkC;IAClC,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAMD;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,EAAE,CAAC,CAGvB;AAMD;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,EAAE,CAAC,CAGvB;AAoiBD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,EAAE,CAKxD;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAKxE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/cloud",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Shared cloud infrastructure \u2014 database adapter (SQLite + PostgreSQL), sync engine, feedback system, unified dotfile config",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",