@hasna/cloud 0.1.35 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +2 -1
- package/README.md +30 -27
- package/dist/adapter.d.ts +65 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.test.d.ts +2 -0
- package/dist/adapter.test.d.ts.map +1 -0
- package/dist/auto-sync.d.ts +28 -0
- package/dist/auto-sync.d.ts.map +1 -0
- package/dist/cli/cmd-doctor.d.ts +3 -0
- package/dist/cli/cmd-doctor.d.ts.map +1 -0
- package/dist/cli/cmd-feedback.d.ts +3 -0
- package/dist/cli/cmd-feedback.d.ts.map +1 -0
- package/dist/cli/cmd-migrate.d.ts +3 -0
- package/dist/cli/cmd-migrate.d.ts.map +1 -0
- package/dist/cli/cmd-setup.d.ts +3 -0
- package/dist/cli/cmd-setup.d.ts.map +1 -0
- package/dist/cli/cmd-sync.d.ts +4 -0
- package/dist/cli/cmd-sync.d.ts.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +15346 -0
- package/dist/cli-helpers.d.ts +17 -0
- package/dist/cli-helpers.d.ts.map +1 -0
- package/dist/config.d.ts +220 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/daemon-sync.d.ts +108 -0
- package/dist/daemon-sync.d.ts.map +1 -0
- package/dist/dialect.d.ts +17 -0
- package/dist/dialect.d.ts.map +1 -0
- package/dist/dialect.test.d.ts +2 -0
- package/dist/dialect.test.d.ts.map +1 -0
- package/dist/discover.d.ts +35 -0
- package/dist/discover.d.ts.map +1 -0
- package/dist/discover.test.d.ts +2 -0
- package/dist/discover.test.d.ts.map +1 -0
- package/dist/dotfile.d.ts +27 -0
- package/dist/dotfile.d.ts.map +1 -0
- package/dist/feedback.d.ts +32 -0
- package/dist/feedback.d.ts.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12223 -0
- package/dist/machines.d.ts +63 -0
- package/dist/machines.d.ts.map +1 -0
- package/dist/mcp/bin.js +2 -0
- package/dist/mcp/http.d.ts +28 -0
- package/dist/mcp/http.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +27795 -0
- package/dist/mcp-helpers.d.ts +22 -0
- package/dist/mcp-helpers.d.ts.map +1 -0
- package/dist/pg-migrate.d.ts +58 -0
- package/dist/pg-migrate.d.ts.map +1 -0
- package/dist/scheduled-sync.d.ts +24 -0
- package/dist/scheduled-sync.d.ts.map +1 -0
- package/dist/scheduled-sync.js +9517 -0
- package/dist/sync-conflicts.d.ts +76 -0
- package/dist/sync-conflicts.d.ts.map +1 -0
- package/dist/sync-conflicts.test.d.ts +2 -0
- package/dist/sync-conflicts.test.d.ts.map +1 -0
- package/dist/sync-incremental.d.ts +67 -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-schedule.d.ts +36 -0
- package/dist/sync-schedule.d.ts.map +1 -0
- package/dist/sync-schedule.test.d.ts +2 -0
- package/dist/sync-schedule.test.d.ts.map +1 -0
- package/dist/sync.d.ts +53 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.test.d.ts +2 -0
- package/dist/sync.test.d.ts.map +1 -0
- package/package.json +26 -15
- package/archive/cli.js +0 -4
- package/archive/index.d.ts +0 -9
- package/archive/index.js +0 -15
- package/archive/mcp.js +0 -4
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { DbAdapter } from "./adapter.js";
|
|
2
|
+
export interface SyncConflict {
|
|
3
|
+
table: string;
|
|
4
|
+
row_id: string;
|
|
5
|
+
local_updated_at: string;
|
|
6
|
+
remote_updated_at: string;
|
|
7
|
+
local_data: Record<string, any>;
|
|
8
|
+
remote_data: Record<string, any>;
|
|
9
|
+
resolved: boolean;
|
|
10
|
+
resolution?: "local-wins" | "remote-wins" | "newest-wins" | "manual";
|
|
11
|
+
}
|
|
12
|
+
export type ConflictStrategy = "local-wins" | "remote-wins" | "newest-wins";
|
|
13
|
+
export interface StoredConflict {
|
|
14
|
+
id: string;
|
|
15
|
+
table_name: string;
|
|
16
|
+
row_id: string;
|
|
17
|
+
local_data: string;
|
|
18
|
+
remote_data: string;
|
|
19
|
+
local_updated_at: string;
|
|
20
|
+
remote_updated_at: string;
|
|
21
|
+
resolution: string | null;
|
|
22
|
+
resolved_at: string | null;
|
|
23
|
+
created_at: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Find rows that exist in BOTH local and remote datasets with DIFFERENT
|
|
27
|
+
* `updated_at` values. Returns a list of SyncConflict objects.
|
|
28
|
+
*
|
|
29
|
+
* @param local - Array of rows from the local database
|
|
30
|
+
* @param remote - Array of rows from the remote database
|
|
31
|
+
* @param table - The table name these rows belong to
|
|
32
|
+
* @param primaryKey - Column used as primary key (default: "id")
|
|
33
|
+
* @param conflictColumn - Column used for timestamp comparison (default: "updated_at")
|
|
34
|
+
*/
|
|
35
|
+
export declare function detectConflicts(local: Record<string, any>[], remote: Record<string, any>[], table: string, primaryKey?: string, conflictColumn?: string): SyncConflict[];
|
|
36
|
+
/**
|
|
37
|
+
* Resolve a list of conflicts using the given strategy.
|
|
38
|
+
* Returns the winning row data for each conflict.
|
|
39
|
+
*
|
|
40
|
+
* @param conflicts - The conflicts to resolve
|
|
41
|
+
* @param strategy - Resolution strategy (default: "newest-wins")
|
|
42
|
+
* @returns Array of resolved conflicts with `resolved: true` and `resolution` set
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveConflicts(conflicts: SyncConflict[], strategy?: ConflictStrategy): SyncConflict[];
|
|
45
|
+
/**
|
|
46
|
+
* Get the winning data for a resolved conflict.
|
|
47
|
+
*/
|
|
48
|
+
export declare function getWinningData(conflict: SyncConflict): Record<string, any>;
|
|
49
|
+
/**
|
|
50
|
+
* Ensure the _sync_conflicts table exists.
|
|
51
|
+
*/
|
|
52
|
+
export declare function ensureConflictsTable(db: DbAdapter): void;
|
|
53
|
+
/**
|
|
54
|
+
* Store unresolved conflicts in the database for later review.
|
|
55
|
+
*/
|
|
56
|
+
export declare function storeConflicts(db: DbAdapter, conflicts: SyncConflict[]): void;
|
|
57
|
+
/**
|
|
58
|
+
* List all stored conflicts, optionally filtered by resolved status.
|
|
59
|
+
*/
|
|
60
|
+
export declare function listConflicts(db: DbAdapter, opts?: {
|
|
61
|
+
resolved?: boolean;
|
|
62
|
+
table?: string;
|
|
63
|
+
}): StoredConflict[];
|
|
64
|
+
/**
|
|
65
|
+
* Resolve a stored conflict by ID using the given strategy.
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolveConflict(db: DbAdapter, conflictId: string, strategy: ConflictStrategy | "manual"): StoredConflict | null;
|
|
68
|
+
/**
|
|
69
|
+
* Get a single stored conflict by ID.
|
|
70
|
+
*/
|
|
71
|
+
export declare function getConflict(db: DbAdapter, conflictId: string): StoredConflict | null;
|
|
72
|
+
/**
|
|
73
|
+
* Delete all resolved conflicts (cleanup).
|
|
74
|
+
*/
|
|
75
|
+
export declare function purgeResolvedConflicts(db: DbAdapter): number;
|
|
76
|
+
//# sourceMappingURL=sync-conflicts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-conflicts.d.ts","sourceRoot":"","sources":["../src/sync-conflicts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAM9C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,YAAY,GAAG,aAAa,GAAG,aAAa,GAAG,QAAQ,CAAC;CACtE;AAED,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,aAAa,GAAG,aAAa,CAAC;AAE5E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAC7B,KAAK,EAAE,MAAM,EACb,UAAU,SAAO,EACjB,cAAc,SAAe,GAC5B,YAAY,EAAE,CAkChB;AAMD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,YAAY,EAAE,EACzB,QAAQ,GAAE,gBAAgC,GACzC,YAAY,EAAE,CA4BhB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAyB1E;AAMD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAexD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAI,CAmB7E;AAMD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,SAAS,EACb,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C,cAAc,EAAE,CAsBlB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,SAAS,EACb,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,gBAAgB,GAAG,QAAQ,GACpC,cAAc,GAAG,IAAI,CAoBvB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAMpF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAM5D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-conflicts.test.d.ts","sourceRoot":"","sources":["../src/sync-conflicts.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { DbAdapter } from "./adapter.js";
|
|
2
|
+
import type { ConflictStrategy } from "./sync-conflicts.js";
|
|
3
|
+
export interface IncrementalSyncStats {
|
|
4
|
+
table: string;
|
|
5
|
+
total_rows: number;
|
|
6
|
+
synced_rows: number;
|
|
7
|
+
skipped_rows: number;
|
|
8
|
+
errors: string[];
|
|
9
|
+
first_sync: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface SyncMeta {
|
|
12
|
+
table_name: string;
|
|
13
|
+
last_synced_at: string;
|
|
14
|
+
last_synced_row_count: number;
|
|
15
|
+
direction: "push" | "pull";
|
|
16
|
+
}
|
|
17
|
+
export interface IncrementalSyncOptions {
|
|
18
|
+
/** Primary key column name (default: "id"). */
|
|
19
|
+
primaryKey?: string;
|
|
20
|
+
/** Conflict resolution column (default: "updated_at"). */
|
|
21
|
+
conflictColumn?: string;
|
|
22
|
+
/** Batch size for writes (default: 500). */
|
|
23
|
+
batchSize?: number;
|
|
24
|
+
/** Conflict resolution strategy for rows present on both sides. */
|
|
25
|
+
conflictStrategy?: ConflictStrategy;
|
|
26
|
+
/** Which side is being transferred into the target. */
|
|
27
|
+
sourceRole?: "local" | "remote";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Ensure the `_sync_meta` table exists in the given database.
|
|
31
|
+
*/
|
|
32
|
+
export declare function ensureSyncMetaTable(db: DbAdapter): void;
|
|
33
|
+
/**
|
|
34
|
+
* Push only changed rows (since last sync) from local to remote.
|
|
35
|
+
*
|
|
36
|
+
* - Checks `_sync_meta` in the local DB for `last_synced_at`.
|
|
37
|
+
* - If found: only selects rows where `updated_at > last_synced_at`.
|
|
38
|
+
* - If not found: full push (first-time sync).
|
|
39
|
+
* - After push, updates `_sync_meta` with current timestamp and row count.
|
|
40
|
+
*/
|
|
41
|
+
export declare function incrementalSyncPush(local: DbAdapter, remote: DbAdapter, tables: string[], options?: IncrementalSyncOptions): IncrementalSyncStats[];
|
|
42
|
+
/**
|
|
43
|
+
* Pull only changed rows (since last sync) from remote to local.
|
|
44
|
+
*
|
|
45
|
+
* - Checks `_sync_meta` in the local DB for `last_synced_at`.
|
|
46
|
+
* - If found: only selects rows where `updated_at > last_synced_at`.
|
|
47
|
+
* - If not found: full pull (first-time sync).
|
|
48
|
+
* - After pull, updates `_sync_meta` with current timestamp and row count.
|
|
49
|
+
*/
|
|
50
|
+
export declare function incrementalSyncPull(remote: DbAdapter, local: DbAdapter, tables: string[], options?: IncrementalSyncOptions): IncrementalSyncStats[];
|
|
51
|
+
/**
|
|
52
|
+
* Get the sync metadata for all tables or a specific table.
|
|
53
|
+
*/
|
|
54
|
+
export declare function getSyncMetaAll(db: DbAdapter): SyncMeta[];
|
|
55
|
+
/**
|
|
56
|
+
* Get sync metadata for a specific table.
|
|
57
|
+
*/
|
|
58
|
+
export declare function getSyncMetaForTable(db: DbAdapter, table: string): SyncMeta | null;
|
|
59
|
+
/**
|
|
60
|
+
* Reset sync metadata for a table (forces full re-sync on next run).
|
|
61
|
+
*/
|
|
62
|
+
export declare function resetSyncMeta(db: DbAdapter, table: string): void;
|
|
63
|
+
/**
|
|
64
|
+
* Reset all sync metadata (forces full re-sync for all tables).
|
|
65
|
+
*/
|
|
66
|
+
export declare function resetAllSyncMeta(db: DbAdapter): void;
|
|
67
|
+
//# sourceMappingURL=sync-incremental.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-incremental.d.ts","sourceRoot":"","sources":["../src/sync-incremental.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAM5D,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CACjC;AAcD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAEvD;AAmJD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,GAAE,sBAA2B,GACnC,oBAAoB,EAAE,CA4ExB;AAMD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,GAAE,sBAA2B,GACnC,oBAAoB,EAAE,CA4ExB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,SAAS,GAAG,QAAQ,EAAE,CAKxD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,SAAS,EACb,KAAK,EAAE,MAAM,GACZ,QAAQ,GAAG,IAAI,CAEjB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAGhE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAGpD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { DbAdapter } from "./adapter.js";
|
|
2
|
+
export interface SyncProgressInfo {
|
|
3
|
+
table: string;
|
|
4
|
+
total: number;
|
|
5
|
+
done: number;
|
|
6
|
+
percent: number;
|
|
7
|
+
elapsed_ms: number;
|
|
8
|
+
eta_ms: number;
|
|
9
|
+
status: "pending" | "in_progress" | "completed" | "failed" | "resumed";
|
|
10
|
+
}
|
|
11
|
+
export type ProgressCallback = (progress: SyncProgressInfo) => void;
|
|
12
|
+
export interface ResumePoint {
|
|
13
|
+
table_name: string;
|
|
14
|
+
last_row_id: string;
|
|
15
|
+
direction: string;
|
|
16
|
+
started_at: string;
|
|
17
|
+
status: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class SyncProgressTracker {
|
|
20
|
+
private db;
|
|
21
|
+
private progress;
|
|
22
|
+
private startTimes;
|
|
23
|
+
private callback?;
|
|
24
|
+
constructor(db: DbAdapter, callback?: ProgressCallback);
|
|
25
|
+
private ensureResumeTable;
|
|
26
|
+
/**
|
|
27
|
+
* Start tracking a table sync. Sets status to in_progress or resumed.
|
|
28
|
+
*/
|
|
29
|
+
start(table: string, total: number, direction: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Update progress for a table after processing rows.
|
|
32
|
+
*/
|
|
33
|
+
update(table: string, done: number, lastRowId: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Mark a table sync as completed.
|
|
36
|
+
*/
|
|
37
|
+
markComplete(table: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Mark a table sync as failed.
|
|
40
|
+
*/
|
|
41
|
+
markFailed(table: string, _error: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Check if a previous sync was interrupted (status is 'in_progress' or 'resumed').
|
|
44
|
+
*/
|
|
45
|
+
canResume(table: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Returns the last successfully synced row ID for a table, or null.
|
|
48
|
+
*/
|
|
49
|
+
getResumePoint(table: string): ResumePoint | null;
|
|
50
|
+
/**
|
|
51
|
+
* Clear resume state for a table (e.g., after a fresh sync starts).
|
|
52
|
+
*/
|
|
53
|
+
clearResume(table: string): void;
|
|
54
|
+
/**
|
|
55
|
+
* Get current progress info for a table.
|
|
56
|
+
*/
|
|
57
|
+
getProgress(table: string): SyncProgressInfo | null;
|
|
58
|
+
/**
|
|
59
|
+
* Get progress info for all tracked tables.
|
|
60
|
+
*/
|
|
61
|
+
getAllProgress(): SyncProgressInfo[];
|
|
62
|
+
/**
|
|
63
|
+
* List all resume records from the database (including historical).
|
|
64
|
+
*/
|
|
65
|
+
listResumeRecords(): ResumePoint[];
|
|
66
|
+
private notify;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=sync-progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-progress.d.ts","sourceRoot":"","sources":["../src/sync-progress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAM9C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;CACxE;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEpE,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAMD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,EAAE,CAAY;IACtB,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,QAAQ,CAAC,CAAmB;gBAExB,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,gBAAgB;IAUtD,OAAO,CAAC,iBAAiB;IAgBzB;;OAEG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAmC5D;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IA0B5D;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAkBjC;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAmB/C;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IASjC;;OAEG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAUjD;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAahC;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAInD;;OAEG;IACH,cAAc,IAAI,gBAAgB,EAAE;IAIpC;;OAEG;IACH,iBAAiB,IAAI,WAAW,EAAE;IAUlC,OAAO,CAAC,MAAM;CAMf"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a human-friendly interval string into minutes.
|
|
3
|
+
*
|
|
4
|
+
* Supported formats:
|
|
5
|
+
* - `5m`, `10m`, `30m` - minutes
|
|
6
|
+
* - `1h`, `2h` - hours (converted to minutes)
|
|
7
|
+
* - `5` - plain number treated as minutes
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseInterval(input: string): number;
|
|
10
|
+
/**
|
|
11
|
+
* Convert minutes to a cron expression.
|
|
12
|
+
*/
|
|
13
|
+
export declare function minutesToCron(minutes: number): string;
|
|
14
|
+
export interface SyncScheduleStatus {
|
|
15
|
+
registered: boolean;
|
|
16
|
+
schedule_minutes: number;
|
|
17
|
+
cron_expression: string | null;
|
|
18
|
+
mechanism: "launchd" | "systemd" | "none";
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Register a system-level scheduled sync.
|
|
22
|
+
*
|
|
23
|
+
* - macOS: creates a launchd plist in ~/Library/LaunchAgents/
|
|
24
|
+
* - Linux: creates a systemd user timer in ~/.config/systemd/user/
|
|
25
|
+
* - Persists interval in ~/.hasna/cloud/config.json
|
|
26
|
+
*/
|
|
27
|
+
export declare function registerSyncSchedule(intervalMinutes: number): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Remove the registered sync schedule.
|
|
30
|
+
*/
|
|
31
|
+
export declare function removeSyncSchedule(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Get the current sync schedule status.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getSyncScheduleStatus(): SyncScheduleStatus;
|
|
36
|
+
//# sourceMappingURL=sync-schedule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-schedule.d.ts","sourceRoot":"","sources":["../src/sync-schedule.ts"],"names":[],"mappings":"AAgBA;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAiCnD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAiBrD;AAsKD,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;CAC3C;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAUxD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,kBAAkB,CAoB1D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-schedule.test.d.ts","sourceRoot":"","sources":["../src/sync-schedule.test.ts"],"names":[],"mappings":""}
|
package/dist/sync.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { DbAdapter } from "./adapter.js";
|
|
2
|
+
import type { PgAdapterAsync } from "./adapter.js";
|
|
3
|
+
export interface SyncProgress {
|
|
4
|
+
table: string;
|
|
5
|
+
phase: "reading" | "writing" | "done";
|
|
6
|
+
rowsRead: number;
|
|
7
|
+
rowsWritten: number;
|
|
8
|
+
totalTables: number;
|
|
9
|
+
currentTableIndex: number;
|
|
10
|
+
}
|
|
11
|
+
export type SyncProgressCallback = (progress: SyncProgress) => void;
|
|
12
|
+
export interface SyncOptions {
|
|
13
|
+
/** Tables to sync. */
|
|
14
|
+
tables: string[];
|
|
15
|
+
/** Optional progress callback. */
|
|
16
|
+
onProgress?: SyncProgressCallback;
|
|
17
|
+
/** Batch size for UPSERT operations. Default: 100 */
|
|
18
|
+
batchSize?: number;
|
|
19
|
+
/** Conflict resolution column (default: "updated_at"). Newest wins. */
|
|
20
|
+
conflictColumn?: 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[];
|
|
27
|
+
}
|
|
28
|
+
export interface SyncResult {
|
|
29
|
+
table: string;
|
|
30
|
+
rowsRead: number;
|
|
31
|
+
rowsWritten: number;
|
|
32
|
+
rowsSkipped: number;
|
|
33
|
+
errors: string[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Push data from a local SQLite database to the cloud PostgreSQL database.
|
|
37
|
+
* Uses batch UPSERT for performance and FK-aware table ordering.
|
|
38
|
+
*/
|
|
39
|
+
export declare function syncPush(local: DbAdapter, remote: PgAdapterAsync, options: SyncOptions): Promise<SyncResult[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Pull data from the cloud PostgreSQL database into a local SQLite database.
|
|
42
|
+
* Uses FK-aware table ordering.
|
|
43
|
+
*/
|
|
44
|
+
export declare function syncPull(remote: PgAdapterAsync, local: DbAdapter, options: SyncOptions): Promise<SyncResult[]>;
|
|
45
|
+
/**
|
|
46
|
+
* List all user tables in a SQLite database.
|
|
47
|
+
*/
|
|
48
|
+
export declare function listSqliteTables(db: DbAdapter): string[];
|
|
49
|
+
/**
|
|
50
|
+
* List all user tables in a PostgreSQL database (async).
|
|
51
|
+
*/
|
|
52
|
+
export declare function listPgTables(db: PgAdapterAsync): Promise<string[]>;
|
|
53
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +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;;;;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;AAmxBD;;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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.test.d.ts","sourceRoot":"","sources":["../src/sync.test.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,35 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/cloud",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.36",
|
|
4
|
+
"description": "Shared cloud infrastructure — database adapter (SQLite + PostgreSQL), sync engine, feedback system, unified dotfile config",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"main": "
|
|
8
|
-
"types": "
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
9
|
"bin": {
|
|
10
|
-
"cloud": "
|
|
11
|
-
"cloud-mcp": "
|
|
10
|
+
"cloud": "dist/cli/index.js",
|
|
11
|
+
"cloud-mcp": "dist/mcp/bin.js"
|
|
12
12
|
},
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
15
|
-
"import": "./
|
|
16
|
-
"types": "./
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
-
"
|
|
21
|
-
"README.md",
|
|
20
|
+
"dist",
|
|
22
21
|
"LICENSE"
|
|
23
22
|
],
|
|
24
23
|
"scripts": {
|
|
25
|
-
"build": "bun
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
24
|
+
"build": "bun build src/index.ts --outdir dist --target node && bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/mcp/index.ts --outdir dist/mcp --target node && printf '#!/usr/bin/env bun\\nimport \"./index.js\";\\n' > dist/mcp/bin.js && chmod +x dist/mcp/bin.js && bun build src/scheduled-sync.ts --outdir dist --target node && bun run build:types",
|
|
25
|
+
"build:types": "tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
26
|
+
"test": "bun test",
|
|
27
|
+
"prepublishOnly": "bun run build",
|
|
28
|
+
"postinstall": "mkdir -p $HOME/.hasna/cloud 2>/dev/null || true; test -f $HOME/.hasna/cloud/config.json || printf '{\"rds\":{\"host\":\"hasnaxyz-prod-opensource.c4limg0qgqvk.us-east-1.rds.amazonaws.com\",\"port\":5432,\"username\":\"\",\"password_env\":\"HASNA_RDS_PASSWORD\",\"ssl\":true},\"mode\":\"local\",\"feedback_endpoint\":\"https://feedback.hasna.com/api/v1/feedback\",\"auto_sync_interval_minutes\":0,\"sync\":{\"schedule_minutes\":0}}\\n' > $HOME/.hasna/cloud/config.json 2>/dev/null || true"
|
|
30
29
|
},
|
|
31
30
|
"publishConfig": {
|
|
32
31
|
"registry": "https://registry.npmjs.org",
|
|
33
32
|
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
36
|
+
"commander": "^13.1.0",
|
|
37
|
+
"pg": "^8.13.3",
|
|
38
|
+
"zod": "^3.24.2",
|
|
39
|
+
"@hasna/events": "^0.1.6"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/bun": "^1.2.6",
|
|
43
|
+
"@types/pg": "^8.11.11",
|
|
44
|
+
"typescript": "^5.7.3"
|
|
34
45
|
}
|
|
35
46
|
}
|
package/archive/cli.js
DELETED
package/archive/index.d.ts
DELETED
package/archive/index.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
const message = [
|
|
2
|
-
"@hasna/cloud is deprecated.",
|
|
3
|
-
"Do not use it as a runtime dependency for open packages.",
|
|
4
|
-
"Use repo-native local SQLite/file storage and explicit remote adapters instead.",
|
|
5
|
-
].join(" ");
|
|
6
|
-
|
|
7
|
-
export function archivedCloudPackageNotice() {
|
|
8
|
-
return message;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default {
|
|
12
|
-
archived: true,
|
|
13
|
-
deprecated: true,
|
|
14
|
-
message,
|
|
15
|
-
};
|
package/archive/mcp.js
DELETED