@hasna/cloud 0.1.3 → 0.1.5
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/adapter.d.ts +2 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/auto-sync.d.ts +57 -0
- package/dist/auto-sync.d.ts.map +1 -0
- package/dist/cli/index.js +176 -154
- package/dist/cli-helpers.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +726 -63
- package/dist/mcp/index.js +173 -151
- package/dist/mcp-helpers.d.ts.map +1 -1
- package/dist/sync-conflicts.d.ts +76 -0
- package/dist/sync-conflicts.d.ts.map +1 -0
- package/dist/sync-incremental.d.ts +62 -0
- package/dist/sync-incremental.d.ts.map +1 -0
- package/dist/sync-progress.d.ts +68 -0
- package/dist/sync-progress.d.ts.map +1 -0
- package/dist/sync.d.ts +10 -9
- package/dist/sync.d.ts.map +1 -1
- package/package.json +1 -1
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;
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -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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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { DbAdapter } from "./adapter.js";
|
|
2
|
+
export interface AutoSyncConfig {
|
|
3
|
+
auto_sync_on_start: boolean;
|
|
4
|
+
auto_sync_on_stop: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface AutoSyncContext {
|
|
7
|
+
serviceName: string;
|
|
8
|
+
local: DbAdapter;
|
|
9
|
+
remote: DbAdapter;
|
|
10
|
+
tables: string[];
|
|
11
|
+
config: AutoSyncConfig;
|
|
12
|
+
}
|
|
13
|
+
export interface AutoSyncResult {
|
|
14
|
+
event: "start" | "stop";
|
|
15
|
+
direction: "pull" | "push";
|
|
16
|
+
success: boolean;
|
|
17
|
+
tables_synced: number;
|
|
18
|
+
total_rows_synced: number;
|
|
19
|
+
errors: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Read auto-sync configuration from `~/.hasna/cloud/config.json`.
|
|
23
|
+
* Falls back to defaults if the file does not exist or is malformed.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getAutoSyncConfig(): AutoSyncConfig;
|
|
26
|
+
/**
|
|
27
|
+
* Set up auto-sync hooks for a service's MCP server.
|
|
28
|
+
*
|
|
29
|
+
* - On connect: if `auto_sync_on_start` and mode is `hybrid` or `cloud`,
|
|
30
|
+
* pull from cloud to local.
|
|
31
|
+
* - On disconnect/SIGTERM: if `auto_sync_on_stop` and mode is `hybrid` or `cloud`,
|
|
32
|
+
* push from local to cloud.
|
|
33
|
+
*
|
|
34
|
+
* @param serviceName - The service identifier.
|
|
35
|
+
* @param server - The MCP server instance (any object with `onconnect`/`ondisconnect` events).
|
|
36
|
+
* @param local - The local database adapter.
|
|
37
|
+
* @param remote - The remote database adapter.
|
|
38
|
+
* @param tables - Tables to sync.
|
|
39
|
+
* @returns An object with methods to manually trigger start/stop syncs.
|
|
40
|
+
*/
|
|
41
|
+
export declare function setupAutoSync(serviceName: string, server: any, local: DbAdapter, remote: DbAdapter, tables: string[]): {
|
|
42
|
+
syncOnStart: () => AutoSyncResult | null;
|
|
43
|
+
syncOnStop: () => AutoSyncResult | null;
|
|
44
|
+
config: AutoSyncConfig;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Enable auto-sync for a service. Simplified entry point that services
|
|
48
|
+
* can call with minimal configuration.
|
|
49
|
+
*
|
|
50
|
+
* @param serviceName - The service name (used for logging context).
|
|
51
|
+
* @param mcpServer - The MCP server instance.
|
|
52
|
+
* @param local - The local database adapter.
|
|
53
|
+
* @param remote - The remote database adapter.
|
|
54
|
+
* @param tables - Tables to sync on start/stop.
|
|
55
|
+
*/
|
|
56
|
+
export declare function enableAutoSync(serviceName: string, mcpServer: any, local: DbAdapter, remote: DbAdapter, tables: string[]): void;
|
|
57
|
+
//# sourceMappingURL=auto-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-sync.d.ts","sourceRoot":"","sources":["../src/auto-sync.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAQ9C,MAAM,WAAW,cAAc;IAC7B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAaD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAmBlD;AAwFD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,GAAG,EACX,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EAAE,GACf;IACD,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,CAAC;IACzC,UAAU,EAAE,MAAM,cAAc,GAAG,IAAI,CAAC;IACxC,MAAM,EAAE,cAAc,CAAC;CACxB,CAiDA;AAMD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,GAAG,EACd,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EAAE,GACf,IAAI,CAEN"}
|
package/dist/cli/index.js
CHANGED
|
@@ -2191,7 +2191,7 @@ var require_arrayParser = __commonJS((exports, module) => {
|
|
|
2191
2191
|
};
|
|
2192
2192
|
});
|
|
2193
2193
|
|
|
2194
|
-
// node_modules/postgres-date/index.js
|
|
2194
|
+
// node_modules/pg-types/node_modules/postgres-date/index.js
|
|
2195
2195
|
var require_postgres_date = __commonJS((exports, module) => {
|
|
2196
2196
|
var DATE_TIME = /(\d{1,})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})(\.\d{1,})?.*?( BC)?$/;
|
|
2197
2197
|
var DATE = /^(\d{1,})-(\d{2})-(\d{2})( BC)?$/;
|
|
@@ -2293,7 +2293,7 @@ var require_mutable = __commonJS((exports, module) => {
|
|
|
2293
2293
|
}
|
|
2294
2294
|
});
|
|
2295
2295
|
|
|
2296
|
-
// node_modules/postgres-interval/index.js
|
|
2296
|
+
// node_modules/pg-types/node_modules/postgres-interval/index.js
|
|
2297
2297
|
var require_postgres_interval = __commonJS((exports, module) => {
|
|
2298
2298
|
var extend = require_mutable();
|
|
2299
2299
|
module.exports = PostgresInterval;
|
|
@@ -2385,7 +2385,7 @@ var require_postgres_interval = __commonJS((exports, module) => {
|
|
|
2385
2385
|
}
|
|
2386
2386
|
});
|
|
2387
2387
|
|
|
2388
|
-
// node_modules/postgres-bytea/index.js
|
|
2388
|
+
// node_modules/pg-types/node_modules/postgres-bytea/index.js
|
|
2389
2389
|
var require_postgres_bytea = __commonJS((exports, module) => {
|
|
2390
2390
|
var bufferFrom = Buffer.from || Buffer;
|
|
2391
2391
|
module.exports = function parseBytea(input) {
|
|
@@ -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 {
|
|
@@ -11257,17 +11260,88 @@ function createDatabase(options) {
|
|
|
11257
11260
|
}
|
|
11258
11261
|
|
|
11259
11262
|
// src/sync.ts
|
|
11260
|
-
function syncPush(local,
|
|
11261
|
-
|
|
11263
|
+
async function syncPush(local, remote, options) {
|
|
11264
|
+
const orderedTables = await getTableOrder(remote, options.tables);
|
|
11265
|
+
return syncTransfer(local, remote, { ...options, tables: orderedTables }, "push");
|
|
11266
|
+
}
|
|
11267
|
+
async function syncPull(remote, local, options) {
|
|
11268
|
+
const orderedTables = await getTableOrder(remote, options.tables);
|
|
11269
|
+
return syncTransfer(remote, local, { ...options, tables: orderedTables }, "pull");
|
|
11270
|
+
}
|
|
11271
|
+
async function getTableOrder(remote, tables) {
|
|
11272
|
+
if (tables.length <= 1)
|
|
11273
|
+
return tables;
|
|
11274
|
+
try {
|
|
11275
|
+
const fks = await remote.all(`
|
|
11276
|
+
SELECT DISTINCT
|
|
11277
|
+
tc.table_name AS source_table,
|
|
11278
|
+
ccu.table_name AS referenced_table
|
|
11279
|
+
FROM information_schema.table_constraints tc
|
|
11280
|
+
JOIN information_schema.constraint_column_usage ccu
|
|
11281
|
+
ON tc.constraint_name = ccu.constraint_name
|
|
11282
|
+
AND tc.table_schema = ccu.table_schema
|
|
11283
|
+
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
11284
|
+
AND tc.table_schema = 'public'
|
|
11285
|
+
`);
|
|
11286
|
+
if (fks.length > 0) {
|
|
11287
|
+
return topoSort(tables, fks);
|
|
11288
|
+
}
|
|
11289
|
+
} catch {}
|
|
11290
|
+
return heuristicOrder(tables);
|
|
11291
|
+
}
|
|
11292
|
+
function topoSort(tables, fks) {
|
|
11293
|
+
const tableSet = new Set(tables);
|
|
11294
|
+
const deps = new Map;
|
|
11295
|
+
for (const t of tables) {
|
|
11296
|
+
deps.set(t, new Set);
|
|
11297
|
+
}
|
|
11298
|
+
for (const fk of fks) {
|
|
11299
|
+
if (tableSet.has(fk.source_table) && tableSet.has(fk.referenced_table)) {
|
|
11300
|
+
deps.get(fk.source_table).add(fk.referenced_table);
|
|
11301
|
+
}
|
|
11302
|
+
}
|
|
11303
|
+
const sorted = [];
|
|
11304
|
+
const visited = new Set;
|
|
11305
|
+
const visiting = new Set;
|
|
11306
|
+
function visit(table) {
|
|
11307
|
+
if (visited.has(table))
|
|
11308
|
+
return;
|
|
11309
|
+
if (visiting.has(table)) {
|
|
11310
|
+
sorted.push(table);
|
|
11311
|
+
visited.add(table);
|
|
11312
|
+
return;
|
|
11313
|
+
}
|
|
11314
|
+
visiting.add(table);
|
|
11315
|
+
const tableDeps = deps.get(table) ?? new Set;
|
|
11316
|
+
for (const dep of tableDeps) {
|
|
11317
|
+
visit(dep);
|
|
11318
|
+
}
|
|
11319
|
+
visiting.delete(table);
|
|
11320
|
+
visited.add(table);
|
|
11321
|
+
sorted.push(table);
|
|
11322
|
+
}
|
|
11323
|
+
for (const t of tables) {
|
|
11324
|
+
visit(t);
|
|
11325
|
+
}
|
|
11326
|
+
return sorted;
|
|
11262
11327
|
}
|
|
11263
|
-
function
|
|
11264
|
-
|
|
11328
|
+
function heuristicOrder(tables) {
|
|
11329
|
+
const sorted = [...tables].sort((a, b) => {
|
|
11330
|
+
const aIsChild = a.includes("_") && tables.some((t) => a.startsWith(t + "_") || a.endsWith("_" + t));
|
|
11331
|
+
const bIsChild = b.includes("_") && tables.some((t) => b.startsWith(t + "_") || b.endsWith("_" + t));
|
|
11332
|
+
if (aIsChild && !bIsChild)
|
|
11333
|
+
return 1;
|
|
11334
|
+
if (!aIsChild && bIsChild)
|
|
11335
|
+
return -1;
|
|
11336
|
+
return a.localeCompare(b);
|
|
11337
|
+
});
|
|
11338
|
+
return sorted;
|
|
11265
11339
|
}
|
|
11266
|
-
function syncTransfer(source, target, options, _direction) {
|
|
11340
|
+
async function syncTransfer(source, target, options, _direction) {
|
|
11267
11341
|
const {
|
|
11268
11342
|
tables,
|
|
11269
11343
|
onProgress,
|
|
11270
|
-
batchSize =
|
|
11344
|
+
batchSize = 100,
|
|
11271
11345
|
conflictColumn = "updated_at",
|
|
11272
11346
|
primaryKey = "id"
|
|
11273
11347
|
} = options;
|
|
@@ -11290,7 +11364,7 @@ function syncTransfer(source, target, options, _direction) {
|
|
|
11290
11364
|
totalTables: tables.length,
|
|
11291
11365
|
currentTableIndex: i
|
|
11292
11366
|
});
|
|
11293
|
-
const rows = source
|
|
11367
|
+
const rows = await readAll(source, `SELECT * FROM "${table}"`);
|
|
11294
11368
|
result.rowsRead = rows.length;
|
|
11295
11369
|
if (rows.length === 0) {
|
|
11296
11370
|
onProgress?.({
|
|
@@ -11305,7 +11379,6 @@ function syncTransfer(source, target, options, _direction) {
|
|
|
11305
11379
|
continue;
|
|
11306
11380
|
}
|
|
11307
11381
|
const columns = Object.keys(rows[0]);
|
|
11308
|
-
const hasConflictCol = columns.includes(conflictColumn);
|
|
11309
11382
|
const hasPrimaryKey = columns.includes(primaryKey);
|
|
11310
11383
|
if (!hasPrimaryKey) {
|
|
11311
11384
|
result.errors.push(`Table "${table}" has no "${primaryKey}" column — skipping`);
|
|
@@ -11320,34 +11393,18 @@ function syncTransfer(source, target, options, _direction) {
|
|
|
11320
11393
|
totalTables: tables.length,
|
|
11321
11394
|
currentTableIndex: i
|
|
11322
11395
|
});
|
|
11396
|
+
const updateCols = columns.filter((c) => c !== primaryKey);
|
|
11323
11397
|
for (let offset = 0;offset < rows.length; offset += batchSize) {
|
|
11324
11398
|
const batch = rows.slice(offset, offset + batchSize);
|
|
11325
|
-
|
|
11326
|
-
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11330
|
-
const existingTime = new Date(existing[conflictColumn]).getTime();
|
|
11331
|
-
const incomingTime = new Date(row[conflictColumn]).getTime();
|
|
11332
|
-
if (existingTime >= incomingTime) {
|
|
11333
|
-
result.rowsSkipped++;
|
|
11334
|
-
continue;
|
|
11335
|
-
}
|
|
11336
|
-
}
|
|
11337
|
-
const setClauses = columns.filter((c) => c !== primaryKey).map((c) => `"${c}" = ?`).join(", ");
|
|
11338
|
-
const values = columns.filter((c) => c !== primaryKey).map((c) => row[c]);
|
|
11339
|
-
values.push(row[primaryKey]);
|
|
11340
|
-
target.run(`UPDATE "${table}" SET ${setClauses} WHERE "${primaryKey}" = ?`, ...values);
|
|
11341
|
-
} else {
|
|
11342
|
-
const placeholders = columns.map(() => "?").join(", ");
|
|
11343
|
-
const colList = columns.map((c) => `"${c}"`).join(", ");
|
|
11344
|
-
const values = columns.map((c) => row[c]);
|
|
11345
|
-
target.run(`INSERT INTO "${table}" (${colList}) VALUES (${placeholders})`, ...values);
|
|
11346
|
-
}
|
|
11347
|
-
result.rowsWritten++;
|
|
11348
|
-
} catch (err) {
|
|
11349
|
-
result.errors.push(`Row ${row[primaryKey]}: ${err?.message ?? String(err)}`);
|
|
11399
|
+
try {
|
|
11400
|
+
if (isAsyncAdapter(target)) {
|
|
11401
|
+
await batchUpsertPg(target, table, columns, updateCols, primaryKey, batch);
|
|
11402
|
+
} else {
|
|
11403
|
+
batchUpsertSqlite(target, table, columns, updateCols, primaryKey, batch);
|
|
11350
11404
|
}
|
|
11405
|
+
result.rowsWritten += batch.length;
|
|
11406
|
+
} catch (err) {
|
|
11407
|
+
result.errors.push(`Batch at offset ${offset}: ${err?.message ?? String(err)}`);
|
|
11351
11408
|
}
|
|
11352
11409
|
onProgress?.({
|
|
11353
11410
|
table,
|
|
@@ -11373,10 +11430,46 @@ function syncTransfer(source, target, options, _direction) {
|
|
|
11373
11430
|
}
|
|
11374
11431
|
return results;
|
|
11375
11432
|
}
|
|
11433
|
+
async function batchUpsertPg(target, table, columns, updateCols, primaryKey, batch) {
|
|
11434
|
+
if (batch.length === 0)
|
|
11435
|
+
return;
|
|
11436
|
+
const colList = columns.map((c) => `"${c}"`).join(", ");
|
|
11437
|
+
const valuePlaceholders = batch.map((_, rowIdx) => {
|
|
11438
|
+
const offset = rowIdx * columns.length;
|
|
11439
|
+
return `(${columns.map((_2, colIdx) => `$${offset + colIdx + 1}`).join(", ")})`;
|
|
11440
|
+
}).join(", ");
|
|
11441
|
+
const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKey}" = EXCLUDED."${primaryKey}"`;
|
|
11442
|
+
const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
|
|
11443
|
+
ON CONFLICT ("${primaryKey}") DO UPDATE SET ${setClause}`;
|
|
11444
|
+
const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
|
|
11445
|
+
await target.run(sql, ...params);
|
|
11446
|
+
}
|
|
11447
|
+
function batchUpsertSqlite(target, table, columns, updateCols, primaryKey, batch) {
|
|
11448
|
+
if (batch.length === 0)
|
|
11449
|
+
return;
|
|
11450
|
+
const colList = columns.map((c) => `"${c}"`).join(", ");
|
|
11451
|
+
const valuePlaceholders = batch.map(() => `(${columns.map(() => "?").join(", ")})`).join(", ");
|
|
11452
|
+
const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKey}" = EXCLUDED."${primaryKey}"`;
|
|
11453
|
+
const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
|
|
11454
|
+
ON CONFLICT ("${primaryKey}") DO UPDATE SET ${setClause}`;
|
|
11455
|
+
const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
|
|
11456
|
+
target.run(sql, ...params);
|
|
11457
|
+
}
|
|
11458
|
+
function isAsyncAdapter(adapter) {
|
|
11459
|
+
return adapter.constructor.name === "PgAdapterAsync" || typeof adapter.raw?.connect === "function";
|
|
11460
|
+
}
|
|
11461
|
+
async function readAll(adapter, sql) {
|
|
11462
|
+
const result = adapter.all(sql);
|
|
11463
|
+
return result instanceof Promise ? await result : result;
|
|
11464
|
+
}
|
|
11376
11465
|
function listSqliteTables(db) {
|
|
11377
11466
|
const rows = db.all(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`);
|
|
11378
11467
|
return rows.map((r) => r.name);
|
|
11379
11468
|
}
|
|
11469
|
+
async function listPgTables(db) {
|
|
11470
|
+
const rows = await db.all(`SELECT tablename FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename`);
|
|
11471
|
+
return rows.map((r) => r.tablename);
|
|
11472
|
+
}
|
|
11380
11473
|
|
|
11381
11474
|
// src/feedback.ts
|
|
11382
11475
|
import { hostname } from "os";
|
|
@@ -11549,6 +11642,9 @@ class SqliteAdapter2 {
|
|
|
11549
11642
|
exec(sql) {
|
|
11550
11643
|
this.db.exec(sql);
|
|
11551
11644
|
}
|
|
11645
|
+
query(sql) {
|
|
11646
|
+
return this.db.query(sql);
|
|
11647
|
+
}
|
|
11552
11648
|
prepare(sql) {
|
|
11553
11649
|
const stmt = this.db.prepare(sql);
|
|
11554
11650
|
return {
|
|
@@ -11578,10 +11674,8 @@ class SqliteAdapter2 {
|
|
|
11578
11674
|
return this.db;
|
|
11579
11675
|
}
|
|
11580
11676
|
}
|
|
11581
|
-
|
|
11582
|
-
class PgAdapter2 {
|
|
11677
|
+
class PgAdapterAsync {
|
|
11583
11678
|
pool;
|
|
11584
|
-
_client = null;
|
|
11585
11679
|
constructor(arg) {
|
|
11586
11680
|
if (typeof arg === "string") {
|
|
11587
11681
|
this.pool = new esm_default.Pool({ connectionString: arg });
|
|
@@ -11589,118 +11683,47 @@ class PgAdapter2 {
|
|
|
11589
11683
|
this.pool = arg;
|
|
11590
11684
|
}
|
|
11591
11685
|
}
|
|
11592
|
-
|
|
11593
|
-
let result;
|
|
11594
|
-
let error;
|
|
11595
|
-
let done = false;
|
|
11596
|
-
fn().then((r) => {
|
|
11597
|
-
result = r;
|
|
11598
|
-
done = true;
|
|
11599
|
-
}).catch((e) => {
|
|
11600
|
-
error = e;
|
|
11601
|
-
done = true;
|
|
11602
|
-
});
|
|
11603
|
-
const deadline = Date.now() + 30000;
|
|
11604
|
-
while (!done && Date.now() < deadline) {
|
|
11605
|
-
Bun.sleepSync(1);
|
|
11606
|
-
}
|
|
11607
|
-
if (error)
|
|
11608
|
-
throw error;
|
|
11609
|
-
if (!done)
|
|
11610
|
-
throw new Error("PgAdapter: query timed out (30s)");
|
|
11611
|
-
return result;
|
|
11612
|
-
}
|
|
11613
|
-
run(sql, ...params) {
|
|
11686
|
+
async run(sql, ...params) {
|
|
11614
11687
|
const pgSql = translateSql(sql, "pg");
|
|
11615
11688
|
const pgParams = translateParams(params);
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
};
|
|
11622
|
-
});
|
|
11689
|
+
const res = await this.pool.query(pgSql, pgParams);
|
|
11690
|
+
return {
|
|
11691
|
+
changes: res.rowCount ?? 0,
|
|
11692
|
+
lastInsertRowid: res.rows?.[0]?.id ?? 0
|
|
11693
|
+
};
|
|
11623
11694
|
}
|
|
11624
|
-
get(sql, ...params) {
|
|
11695
|
+
async get(sql, ...params) {
|
|
11625
11696
|
const pgSql = translateSql(sql, "pg");
|
|
11626
11697
|
const pgParams = translateParams(params);
|
|
11627
|
-
|
|
11628
|
-
|
|
11629
|
-
return res.rows[0] ?? null;
|
|
11630
|
-
});
|
|
11698
|
+
const res = await this.pool.query(pgSql, pgParams);
|
|
11699
|
+
return res.rows[0] ?? null;
|
|
11631
11700
|
}
|
|
11632
|
-
all(sql, ...params) {
|
|
11701
|
+
async all(sql, ...params) {
|
|
11633
11702
|
const pgSql = translateSql(sql, "pg");
|
|
11634
11703
|
const pgParams = translateParams(params);
|
|
11635
|
-
|
|
11636
|
-
|
|
11637
|
-
return res.rows;
|
|
11638
|
-
});
|
|
11704
|
+
const res = await this.pool.query(pgSql, pgParams);
|
|
11705
|
+
return res.rows;
|
|
11639
11706
|
}
|
|
11640
|
-
exec(sql) {
|
|
11707
|
+
async exec(sql) {
|
|
11641
11708
|
const pgSql = translateSql(sql, "pg");
|
|
11642
|
-
this.
|
|
11643
|
-
await this.pool.query(pgSql);
|
|
11644
|
-
});
|
|
11709
|
+
await this.pool.query(pgSql);
|
|
11645
11710
|
}
|
|
11646
|
-
|
|
11647
|
-
|
|
11648
|
-
const adapter = this;
|
|
11649
|
-
return {
|
|
11650
|
-
run(...params) {
|
|
11651
|
-
const pgParams = translateParams(params);
|
|
11652
|
-
return adapter.runSync(async () => {
|
|
11653
|
-
const res = await adapter.pool.query(pgSql, pgParams);
|
|
11654
|
-
return {
|
|
11655
|
-
changes: res.rowCount ?? 0,
|
|
11656
|
-
lastInsertRowid: res.rows?.[0]?.id ?? 0
|
|
11657
|
-
};
|
|
11658
|
-
});
|
|
11659
|
-
},
|
|
11660
|
-
get(...params) {
|
|
11661
|
-
const pgParams = translateParams(params);
|
|
11662
|
-
return adapter.runSync(async () => {
|
|
11663
|
-
const res = await adapter.pool.query(pgSql, pgParams);
|
|
11664
|
-
return res.rows[0] ?? null;
|
|
11665
|
-
});
|
|
11666
|
-
},
|
|
11667
|
-
all(...params) {
|
|
11668
|
-
const pgParams = translateParams(params);
|
|
11669
|
-
return adapter.runSync(async () => {
|
|
11670
|
-
const res = await adapter.pool.query(pgSql, pgParams);
|
|
11671
|
-
return res.rows;
|
|
11672
|
-
});
|
|
11673
|
-
},
|
|
11674
|
-
finalize() {}
|
|
11675
|
-
};
|
|
11711
|
+
async close() {
|
|
11712
|
+
await this.pool.end();
|
|
11676
11713
|
}
|
|
11677
|
-
|
|
11678
|
-
this.
|
|
11679
|
-
|
|
11680
|
-
|
|
11681
|
-
|
|
11682
|
-
|
|
11683
|
-
|
|
11684
|
-
|
|
11685
|
-
|
|
11686
|
-
|
|
11687
|
-
|
|
11688
|
-
|
|
11689
|
-
|
|
11690
|
-
try {
|
|
11691
|
-
result = fn();
|
|
11692
|
-
} finally {
|
|
11693
|
-
this.pool.query = origQuery;
|
|
11694
|
-
}
|
|
11695
|
-
await client.query("COMMIT");
|
|
11696
|
-
return result;
|
|
11697
|
-
} catch (err) {
|
|
11698
|
-
await client.query("ROLLBACK");
|
|
11699
|
-
throw err;
|
|
11700
|
-
} finally {
|
|
11701
|
-
client.release();
|
|
11702
|
-
}
|
|
11703
|
-
});
|
|
11714
|
+
async transaction(fn) {
|
|
11715
|
+
const client = await this.pool.connect();
|
|
11716
|
+
try {
|
|
11717
|
+
await client.query("BEGIN");
|
|
11718
|
+
const result = await fn(client);
|
|
11719
|
+
await client.query("COMMIT");
|
|
11720
|
+
return result;
|
|
11721
|
+
} catch (err) {
|
|
11722
|
+
await client.query("ROLLBACK");
|
|
11723
|
+
throw err;
|
|
11724
|
+
} finally {
|
|
11725
|
+
client.release();
|
|
11726
|
+
}
|
|
11704
11727
|
}
|
|
11705
11728
|
get raw() {
|
|
11706
11729
|
return this.pool;
|
|
@@ -11742,19 +11765,19 @@ program2.command("status").description("Show current cloud configuration and con
|
|
|
11742
11765
|
Checking PostgreSQL connection...`);
|
|
11743
11766
|
try {
|
|
11744
11767
|
const connStr = getConnectionString("postgres");
|
|
11745
|
-
const pg2 = new
|
|
11746
|
-
const row = pg2.get("SELECT 1 as ok");
|
|
11768
|
+
const pg2 = new PgAdapterAsync(connStr);
|
|
11769
|
+
const row = await pg2.get("SELECT 1 as ok");
|
|
11747
11770
|
if (row?.ok === 1) {
|
|
11748
11771
|
console.log("PostgreSQL: connected");
|
|
11749
11772
|
}
|
|
11750
|
-
pg2.close();
|
|
11773
|
+
await pg2.close();
|
|
11751
11774
|
} catch (err) {
|
|
11752
11775
|
console.log("PostgreSQL: connection failed \u2014", err?.message);
|
|
11753
11776
|
}
|
|
11754
11777
|
}
|
|
11755
11778
|
});
|
|
11756
11779
|
var syncCmd = program2.command("sync").description("Sync data between local and cloud");
|
|
11757
|
-
syncCmd.command("push").description("Push local data to cloud").requiredOption("--service <name>", "Service name").option("--tables <tables>", "Comma-separated table names (default: all)").action((opts) => {
|
|
11780
|
+
syncCmd.command("push").description("Push local data to cloud").requiredOption("--service <name>", "Service name").option("--tables <tables>", "Comma-separated table names (default: all)").action(async (opts) => {
|
|
11758
11781
|
const config = getCloudConfig();
|
|
11759
11782
|
if (config.mode === "local") {
|
|
11760
11783
|
console.error("Error: mode is 'local'. Run `cloud setup --mode hybrid` or `--mode cloud` first.");
|
|
@@ -11775,8 +11798,8 @@ syncCmd.command("push").description("Push local data to cloud").requiredOption("
|
|
|
11775
11798
|
}
|
|
11776
11799
|
console.log(`Pushing ${tables.length} table(s) to cloud...`);
|
|
11777
11800
|
const connStr = getConnectionString(opts.service);
|
|
11778
|
-
const cloud = new
|
|
11779
|
-
const results = syncPush(local, cloud, {
|
|
11801
|
+
const cloud = new PgAdapterAsync(connStr);
|
|
11802
|
+
const results = await syncPush(local, cloud, {
|
|
11780
11803
|
tables,
|
|
11781
11804
|
onProgress: (p) => {
|
|
11782
11805
|
if (p.phase === "done") {
|
|
@@ -11785,7 +11808,7 @@ syncCmd.command("push").description("Push local data to cloud").requiredOption("
|
|
|
11785
11808
|
}
|
|
11786
11809
|
});
|
|
11787
11810
|
local.close();
|
|
11788
|
-
cloud.close();
|
|
11811
|
+
await cloud.close();
|
|
11789
11812
|
const totalWritten = results.reduce((s, r) => s + r.rowsWritten, 0);
|
|
11790
11813
|
const totalErrors = results.reduce((s, r) => s + r.errors.length, 0);
|
|
11791
11814
|
console.log(`
|
|
@@ -11798,7 +11821,7 @@ Done. ${totalWritten} rows pushed, ${totalErrors} errors.`);
|
|
|
11798
11821
|
}
|
|
11799
11822
|
}
|
|
11800
11823
|
});
|
|
11801
|
-
syncCmd.command("pull").description("Pull cloud data to local").requiredOption("--service <name>", "Service name").option("--tables <tables>", "Comma-separated table names (default: all)").action((opts) => {
|
|
11824
|
+
syncCmd.command("pull").description("Pull cloud data to local").requiredOption("--service <name>", "Service name").option("--tables <tables>", "Comma-separated table names (default: all)").action(async (opts) => {
|
|
11802
11825
|
const config = getCloudConfig();
|
|
11803
11826
|
if (config.mode === "local") {
|
|
11804
11827
|
console.error("Error: mode is 'local'. Run `cloud setup --mode hybrid` or `--mode cloud` first.");
|
|
@@ -11807,18 +11830,17 @@ syncCmd.command("pull").description("Pull cloud data to local").requiredOption("
|
|
|
11807
11830
|
const dbPath = getDbPath2(opts.service);
|
|
11808
11831
|
const local = new SqliteAdapter2(dbPath);
|
|
11809
11832
|
const connStr = getConnectionString(opts.service);
|
|
11810
|
-
const cloud = new
|
|
11833
|
+
const cloud = new PgAdapterAsync(connStr);
|
|
11811
11834
|
let tables;
|
|
11812
11835
|
if (opts.tables) {
|
|
11813
11836
|
tables = opts.tables.split(",").map((t) => t.trim());
|
|
11814
11837
|
} else {
|
|
11815
11838
|
try {
|
|
11816
|
-
|
|
11817
|
-
tables = rows.map((r) => r.tablename);
|
|
11839
|
+
tables = await listPgTables(cloud);
|
|
11818
11840
|
} catch {
|
|
11819
11841
|
console.error("Failed to list tables from cloud.");
|
|
11820
11842
|
local.close();
|
|
11821
|
-
cloud.close();
|
|
11843
|
+
await cloud.close();
|
|
11822
11844
|
process.exit(1);
|
|
11823
11845
|
return;
|
|
11824
11846
|
}
|
|
@@ -11826,11 +11848,11 @@ syncCmd.command("pull").description("Pull cloud data to local").requiredOption("
|
|
|
11826
11848
|
if (tables.length === 0) {
|
|
11827
11849
|
console.log("No tables found to sync.");
|
|
11828
11850
|
local.close();
|
|
11829
|
-
cloud.close();
|
|
11851
|
+
await cloud.close();
|
|
11830
11852
|
return;
|
|
11831
11853
|
}
|
|
11832
11854
|
console.log(`Pulling ${tables.length} table(s) from cloud...`);
|
|
11833
|
-
const results = syncPull(
|
|
11855
|
+
const results = await syncPull(cloud, local, {
|
|
11834
11856
|
tables,
|
|
11835
11857
|
onProgress: (p) => {
|
|
11836
11858
|
if (p.phase === "done") {
|
|
@@ -11839,7 +11861,7 @@ syncCmd.command("pull").description("Pull cloud data to local").requiredOption("
|
|
|
11839
11861
|
}
|
|
11840
11862
|
});
|
|
11841
11863
|
local.close();
|
|
11842
|
-
cloud.close();
|
|
11864
|
+
await cloud.close();
|
|
11843
11865
|
const totalWritten = results.reduce((s, r) => s + r.rowsWritten, 0);
|
|
11844
11866
|
const totalErrors = results.reduce((s, r) => s + r.errors.length, 0);
|
|
11845
11867
|
console.log(`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-helpers.d.ts","sourceRoot":"","sources":["../src/cli-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWzC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,MAAM,GAClB,IAAI,
|
|
1
|
+
{"version":3,"file":"cli-helpers.d.ts","sourceRoot":"","sources":["../src/cli-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWzC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,MAAM,GAClB,IAAI,CAqHN"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ export { getCloudConfig, saveCloudConfig, getConnectionString, createDatabase, g
|
|
|
4
4
|
export { syncPush, syncPull, listSqliteTables, listPgTables, type SyncOptions, type SyncResult, type SyncProgress, type SyncProgressCallback, } from "./sync.js";
|
|
5
5
|
export { saveFeedback, sendFeedback, listFeedback, ensureFeedbackTable, type Feedback, } from "./feedback.js";
|
|
6
6
|
export { migrateDotfile, getDataDir, getDbPath, hasLegacyDotfile, getHasnaDir, } from "./dotfile.js";
|
|
7
|
+
export { SyncProgressTracker, type SyncProgressInfo, type ProgressCallback, type ResumePoint, } from "./sync-progress.js";
|
|
8
|
+
export { detectConflicts, resolveConflicts, getWinningData, ensureConflictsTable, storeConflicts, listConflicts, resolveConflict, getConflict, purgeResolvedConflicts, type SyncConflict, type ConflictStrategy, type StoredConflict, } from "./sync-conflicts.js";
|
|
9
|
+
export { incrementalSyncPush, incrementalSyncPull, ensureSyncMetaTable, getSyncMetaAll, getSyncMetaForTable, resetSyncMeta, resetAllSyncMeta, type IncrementalSyncStats, type IncrementalSyncOptions, type SyncMeta, } from "./sync-incremental.js";
|
|
10
|
+
export { setupAutoSync, enableAutoSync, getAutoSyncConfig, type AutoSyncConfig, type AutoSyncContext, type AutoSyncResult, } from "./auto-sync.js";
|
|
7
11
|
export { registerCloudTools } from "./mcp-helpers.js";
|
|
8
12
|
export { registerCloudCommands } from "./cli-helpers.js";
|
|
9
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,aAAa,EACb,SAAS,EACT,cAAc,EACd,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,SAAS,GACf,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,KAAK,OAAO,GACb,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,oBAAoB,GAC1B,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,KAAK,QAAQ,GACd,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,cAAc,EACd,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,WAAW,GACZ,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,aAAa,EACb,SAAS,EACT,cAAc,EACd,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,SAAS,GACf,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,KAAK,OAAO,GACb,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,oBAAoB,GAC1B,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,KAAK,QAAQ,GACd,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,cAAc,EACd,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,WAAW,GACZ,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,aAAa,EACb,eAAe,EACf,WAAW,EACX,sBAAsB,EACtB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,QAAQ,GACd,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC"}
|