@hasna/cloud 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +228 -31
- package/dist/index.js +221 -24
- package/dist/mcp/index.js +54 -0
- package/dist/sync-schedule.d.ts +7 -13
- package/dist/sync-schedule.d.ts.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -11343,15 +11343,15 @@ __export(exports_discover, {
|
|
|
11343
11343
|
SYNC_EXCLUDED_TABLE_PATTERNS: () => SYNC_EXCLUDED_TABLE_PATTERNS2,
|
|
11344
11344
|
KNOWN_PG_SERVICES: () => KNOWN_PG_SERVICES
|
|
11345
11345
|
});
|
|
11346
|
-
import { readdirSync as readdirSync5, existsSync as
|
|
11346
|
+
import { readdirSync as readdirSync5, existsSync as existsSync8 } from "fs";
|
|
11347
11347
|
import { join as join8 } from "path";
|
|
11348
|
-
import { homedir as
|
|
11348
|
+
import { homedir as homedir7 } from "os";
|
|
11349
11349
|
function isSyncExcludedTable2(table) {
|
|
11350
11350
|
return SYNC_EXCLUDED_TABLE_PATTERNS2.some((p) => p.test(table));
|
|
11351
11351
|
}
|
|
11352
11352
|
function discoverServices2() {
|
|
11353
|
-
const dataDir = join8(
|
|
11354
|
-
if (!
|
|
11353
|
+
const dataDir = join8(homedir7(), ".hasna");
|
|
11354
|
+
if (!existsSync8(dataDir))
|
|
11355
11355
|
return [];
|
|
11356
11356
|
try {
|
|
11357
11357
|
const entries = readdirSync5(dataDir, { withFileTypes: true });
|
|
@@ -11372,8 +11372,8 @@ function discoverSyncableServices2() {
|
|
|
11372
11372
|
return local.filter((s) => pgSet.has(s));
|
|
11373
11373
|
}
|
|
11374
11374
|
function getServiceDbPath(service) {
|
|
11375
|
-
const dataDir = join8(
|
|
11376
|
-
if (!
|
|
11375
|
+
const dataDir = join8(homedir7(), ".hasna", service);
|
|
11376
|
+
if (!existsSync8(dataDir))
|
|
11377
11377
|
return null;
|
|
11378
11378
|
const candidates = [
|
|
11379
11379
|
join8(dataDir, `${service}.db`),
|
|
@@ -11389,7 +11389,7 @@ function getServiceDbPath(service) {
|
|
|
11389
11389
|
}
|
|
11390
11390
|
} catch {}
|
|
11391
11391
|
for (const p of candidates) {
|
|
11392
|
-
if (
|
|
11392
|
+
if (existsSync8(p))
|
|
11393
11393
|
return p;
|
|
11394
11394
|
}
|
|
11395
11395
|
return null;
|
|
@@ -11643,6 +11643,59 @@ async function resolvePrimaryKeys(source, target, table, pkOption) {
|
|
|
11643
11643
|
}
|
|
11644
11644
|
return pks;
|
|
11645
11645
|
}
|
|
11646
|
+
function pgTypeToSqlite(pgType) {
|
|
11647
|
+
const t = pgType.toLowerCase();
|
|
11648
|
+
if (t.includes("int") || t === "bigint" || t === "smallint" || t === "serial" || t === "bigserial")
|
|
11649
|
+
return "INTEGER";
|
|
11650
|
+
if (t.includes("bool"))
|
|
11651
|
+
return "INTEGER";
|
|
11652
|
+
if (t.includes("float") || t.includes("double") || t === "real" || t === "numeric" || t === "decimal")
|
|
11653
|
+
return "REAL";
|
|
11654
|
+
if (t === "bytea")
|
|
11655
|
+
return "BLOB";
|
|
11656
|
+
return "TEXT";
|
|
11657
|
+
}
|
|
11658
|
+
async function ensureTableInSqliteFromPg(target, source, table) {
|
|
11659
|
+
const existing = target.all(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`, table);
|
|
11660
|
+
if (existing.length > 0)
|
|
11661
|
+
return false;
|
|
11662
|
+
const cols = await source.all(`SELECT column_name, data_type, is_nullable, column_default
|
|
11663
|
+
FROM information_schema.columns
|
|
11664
|
+
WHERE table_schema = 'public' AND table_name = '${table}'
|
|
11665
|
+
ORDER BY ordinal_position`);
|
|
11666
|
+
if (cols.length === 0)
|
|
11667
|
+
return false;
|
|
11668
|
+
const pkCols = await source.all(`SELECT kcu.column_name
|
|
11669
|
+
FROM information_schema.table_constraints tc
|
|
11670
|
+
JOIN information_schema.key_column_usage kcu
|
|
11671
|
+
ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema
|
|
11672
|
+
WHERE tc.constraint_type = 'PRIMARY KEY' AND tc.table_schema = 'public' AND tc.table_name = '${table}'
|
|
11673
|
+
ORDER BY kcu.ordinal_position`);
|
|
11674
|
+
const pkSet = new Set(pkCols.map((c) => c.column_name));
|
|
11675
|
+
const skipTypes = new Set(["tsvector", "tsquery", "user-defined"]);
|
|
11676
|
+
const filteredCols = cols.filter((c) => !skipTypes.has(c.data_type));
|
|
11677
|
+
const colDefs = filteredCols.map((c) => {
|
|
11678
|
+
const sqliteType = pgTypeToSqlite(c.data_type);
|
|
11679
|
+
const notNull = c.is_nullable === "NO" && !pkSet.has(c.column_name) ? " NOT NULL" : "";
|
|
11680
|
+
return `"${c.column_name}" ${sqliteType}${notNull}`;
|
|
11681
|
+
});
|
|
11682
|
+
if (pkSet.size > 0) {
|
|
11683
|
+
const pkList = [...pkSet].map((c) => `"${c}"`).join(", ");
|
|
11684
|
+
colDefs.push(`PRIMARY KEY (${pkList})`);
|
|
11685
|
+
}
|
|
11686
|
+
const sql = `CREATE TABLE IF NOT EXISTS "${table}" (${colDefs.join(", ")})`;
|
|
11687
|
+
target.exec(sql);
|
|
11688
|
+
process.stderr.write(` [sync] ${table}: auto-created in SQLite from PG schema
|
|
11689
|
+
`);
|
|
11690
|
+
return true;
|
|
11691
|
+
}
|
|
11692
|
+
async function ensureTablesExist(source, target, tables) {
|
|
11693
|
+
for (const table of tables) {
|
|
11694
|
+
if (!isAsyncAdapter(target) && isAsyncAdapter(source)) {
|
|
11695
|
+
await ensureTableInSqliteFromPg(target, source, table);
|
|
11696
|
+
}
|
|
11697
|
+
}
|
|
11698
|
+
}
|
|
11646
11699
|
async function filterColumnsForTarget(target, table, sourceColumns) {
|
|
11647
11700
|
try {
|
|
11648
11701
|
if (!isAsyncAdapter(target)) {
|
|
@@ -11677,6 +11730,7 @@ async function syncTransfer(source, target, options, _direction) {
|
|
|
11677
11730
|
} = options;
|
|
11678
11731
|
const results = [];
|
|
11679
11732
|
const sqliteTarget = !isAsyncAdapter(target) ? target : null;
|
|
11733
|
+
await ensureTablesExist(source, target, tables);
|
|
11680
11734
|
if (sqliteTarget) {
|
|
11681
11735
|
try {
|
|
11682
11736
|
sqliteTarget.exec("PRAGMA foreign_keys = OFF");
|
|
@@ -12131,18 +12185,10 @@ class PgAdapterAsync2 {
|
|
|
12131
12185
|
// src/sync-schedule.ts
|
|
12132
12186
|
init_config();
|
|
12133
12187
|
import { join as join5, dirname } from "path";
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
const jsPath = join5(dir, "scheduled-sync.js");
|
|
12139
|
-
try {
|
|
12140
|
-
const { existsSync: existsSync5 } = __require("fs");
|
|
12141
|
-
if (existsSync5(tsPath))
|
|
12142
|
-
return tsPath;
|
|
12143
|
-
} catch {}
|
|
12144
|
-
return jsPath;
|
|
12145
|
-
}
|
|
12188
|
+
import { existsSync as existsSync5, writeFileSync as writeFileSync3, unlinkSync, mkdirSync as mkdirSync5 } from "fs";
|
|
12189
|
+
import { homedir as homedir5, platform } from "os";
|
|
12190
|
+
var SERVICE_NAME = "hasna-cloud-sync";
|
|
12191
|
+
var CONFIG_DIR3 = join5(homedir5(), ".hasna", "cloud");
|
|
12146
12192
|
function parseInterval(input) {
|
|
12147
12193
|
const trimmed = input.trim().toLowerCase();
|
|
12148
12194
|
const hourMatch = trimmed.match(/^(\d+)\s*h$/);
|
|
@@ -12181,19 +12227,161 @@ function minutesToCron(minutes) {
|
|
|
12181
12227
|
}
|
|
12182
12228
|
return `*/${minutes} * * * *`;
|
|
12183
12229
|
}
|
|
12230
|
+
function getWorkerPath() {
|
|
12231
|
+
const dir = typeof import.meta.dir === "string" ? import.meta.dir : dirname(import.meta.url.replace("file://", ""));
|
|
12232
|
+
const tsPath = join5(dir, "scheduled-sync.ts");
|
|
12233
|
+
const jsPath = join5(dir, "scheduled-sync.js");
|
|
12234
|
+
try {
|
|
12235
|
+
if (existsSync5(tsPath))
|
|
12236
|
+
return tsPath;
|
|
12237
|
+
} catch {}
|
|
12238
|
+
return jsPath;
|
|
12239
|
+
}
|
|
12240
|
+
function getBunPath() {
|
|
12241
|
+
const candidates = [
|
|
12242
|
+
join5(homedir5(), ".bun", "bin", "bun"),
|
|
12243
|
+
"/usr/local/bin/bun",
|
|
12244
|
+
"/usr/bin/bun"
|
|
12245
|
+
];
|
|
12246
|
+
for (const p of candidates) {
|
|
12247
|
+
if (existsSync5(p))
|
|
12248
|
+
return p;
|
|
12249
|
+
}
|
|
12250
|
+
return "bun";
|
|
12251
|
+
}
|
|
12252
|
+
function getLaunchdPlistPath() {
|
|
12253
|
+
return join5(homedir5(), "Library", "LaunchAgents", `com.hasna.cloud-sync.plist`);
|
|
12254
|
+
}
|
|
12255
|
+
function createLaunchdPlist(intervalMinutes) {
|
|
12256
|
+
const workerPath = getWorkerPath();
|
|
12257
|
+
const bunPath = getBunPath();
|
|
12258
|
+
const logPath = join5(CONFIG_DIR3, "sync.log");
|
|
12259
|
+
const errorLogPath = join5(CONFIG_DIR3, "sync-error.log");
|
|
12260
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
12261
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
12262
|
+
<plist version="1.0">
|
|
12263
|
+
<dict>
|
|
12264
|
+
<key>Label</key>
|
|
12265
|
+
<string>com.hasna.cloud-sync</string>
|
|
12266
|
+
<key>ProgramArguments</key>
|
|
12267
|
+
<array>
|
|
12268
|
+
<string>${bunPath}</string>
|
|
12269
|
+
<string>run</string>
|
|
12270
|
+
<string>${workerPath}</string>
|
|
12271
|
+
</array>
|
|
12272
|
+
<key>StartInterval</key>
|
|
12273
|
+
<integer>${intervalMinutes * 60}</integer>
|
|
12274
|
+
<key>RunAtLoad</key>
|
|
12275
|
+
<true/>
|
|
12276
|
+
<key>StandardOutPath</key>
|
|
12277
|
+
<string>${logPath}</string>
|
|
12278
|
+
<key>StandardErrorPath</key>
|
|
12279
|
+
<string>${errorLogPath}</string>
|
|
12280
|
+
<key>EnvironmentVariables</key>
|
|
12281
|
+
<dict>
|
|
12282
|
+
<key>PATH</key>
|
|
12283
|
+
<string>${process.env.PATH || "/usr/local/bin:/usr/bin:/bin"}</string>
|
|
12284
|
+
<key>HOME</key>
|
|
12285
|
+
<string>${homedir5()}</string>
|
|
12286
|
+
</dict>
|
|
12287
|
+
</dict>
|
|
12288
|
+
</plist>`;
|
|
12289
|
+
}
|
|
12290
|
+
async function registerLaunchd(intervalMinutes) {
|
|
12291
|
+
const plistPath = getLaunchdPlistPath();
|
|
12292
|
+
const plistDir = dirname(plistPath);
|
|
12293
|
+
mkdirSync5(plistDir, { recursive: true });
|
|
12294
|
+
try {
|
|
12295
|
+
await Bun.spawn(["launchctl", "unload", plistPath]).exited;
|
|
12296
|
+
} catch {}
|
|
12297
|
+
writeFileSync3(plistPath, createLaunchdPlist(intervalMinutes));
|
|
12298
|
+
await Bun.spawn(["launchctl", "load", plistPath]).exited;
|
|
12299
|
+
}
|
|
12300
|
+
async function removeLaunchd() {
|
|
12301
|
+
const plistPath = getLaunchdPlistPath();
|
|
12302
|
+
try {
|
|
12303
|
+
await Bun.spawn(["launchctl", "unload", plistPath]).exited;
|
|
12304
|
+
} catch {}
|
|
12305
|
+
try {
|
|
12306
|
+
unlinkSync(plistPath);
|
|
12307
|
+
} catch {}
|
|
12308
|
+
}
|
|
12309
|
+
function getSystemdDir() {
|
|
12310
|
+
return join5(homedir5(), ".config", "systemd", "user");
|
|
12311
|
+
}
|
|
12312
|
+
function createSystemdService() {
|
|
12313
|
+
const workerPath = getWorkerPath();
|
|
12314
|
+
const bunPath = getBunPath();
|
|
12315
|
+
return `[Unit]
|
|
12316
|
+
Description=Hasna Cloud Sync
|
|
12317
|
+
After=network.target
|
|
12318
|
+
|
|
12319
|
+
[Service]
|
|
12320
|
+
Type=oneshot
|
|
12321
|
+
ExecStart=${bunPath} run ${workerPath}
|
|
12322
|
+
Environment=HOME=${homedir5()}
|
|
12323
|
+
Environment=PATH=${process.env.PATH || "/usr/local/bin:/usr/bin:/bin"}
|
|
12324
|
+
|
|
12325
|
+
[Install]
|
|
12326
|
+
WantedBy=default.target
|
|
12327
|
+
`;
|
|
12328
|
+
}
|
|
12329
|
+
function createSystemdTimer(intervalMinutes) {
|
|
12330
|
+
return `[Unit]
|
|
12331
|
+
Description=Hasna Cloud Sync Timer
|
|
12332
|
+
|
|
12333
|
+
[Timer]
|
|
12334
|
+
OnBootSec=${intervalMinutes}min
|
|
12335
|
+
OnUnitActiveSec=${intervalMinutes}min
|
|
12336
|
+
Persistent=true
|
|
12337
|
+
|
|
12338
|
+
[Install]
|
|
12339
|
+
WantedBy=timers.target
|
|
12340
|
+
`;
|
|
12341
|
+
}
|
|
12342
|
+
async function registerSystemd(intervalMinutes) {
|
|
12343
|
+
const dir = getSystemdDir();
|
|
12344
|
+
mkdirSync5(dir, { recursive: true });
|
|
12345
|
+
writeFileSync3(join5(dir, `${SERVICE_NAME}.service`), createSystemdService());
|
|
12346
|
+
writeFileSync3(join5(dir, `${SERVICE_NAME}.timer`), createSystemdTimer(intervalMinutes));
|
|
12347
|
+
await Bun.spawn(["systemctl", "--user", "daemon-reload"]).exited;
|
|
12348
|
+
await Bun.spawn(["systemctl", "--user", "enable", "--now", `${SERVICE_NAME}.timer`]).exited;
|
|
12349
|
+
}
|
|
12350
|
+
async function removeSystemd() {
|
|
12351
|
+
try {
|
|
12352
|
+
await Bun.spawn(["systemctl", "--user", "disable", "--now", `${SERVICE_NAME}.timer`]).exited;
|
|
12353
|
+
} catch {}
|
|
12354
|
+
const dir = getSystemdDir();
|
|
12355
|
+
try {
|
|
12356
|
+
unlinkSync(join5(dir, `${SERVICE_NAME}.service`));
|
|
12357
|
+
} catch {}
|
|
12358
|
+
try {
|
|
12359
|
+
unlinkSync(join5(dir, `${SERVICE_NAME}.timer`));
|
|
12360
|
+
} catch {}
|
|
12361
|
+
try {
|
|
12362
|
+
await Bun.spawn(["systemctl", "--user", "daemon-reload"]).exited;
|
|
12363
|
+
} catch {}
|
|
12364
|
+
}
|
|
12184
12365
|
async function registerSyncSchedule(intervalMinutes) {
|
|
12185
12366
|
if (intervalMinutes <= 0) {
|
|
12186
12367
|
throw new Error("Interval must be a positive number of minutes.");
|
|
12187
12368
|
}
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12369
|
+
mkdirSync5(CONFIG_DIR3, { recursive: true });
|
|
12370
|
+
if (platform() === "darwin") {
|
|
12371
|
+
await registerLaunchd(intervalMinutes);
|
|
12372
|
+
} else {
|
|
12373
|
+
await registerSystemd(intervalMinutes);
|
|
12374
|
+
}
|
|
12191
12375
|
const config = getCloudConfig2();
|
|
12192
12376
|
config.sync.schedule_minutes = intervalMinutes;
|
|
12193
12377
|
saveCloudConfig2(config);
|
|
12194
12378
|
}
|
|
12195
12379
|
async function removeSyncSchedule() {
|
|
12196
|
-
|
|
12380
|
+
if (platform() === "darwin") {
|
|
12381
|
+
await removeLaunchd();
|
|
12382
|
+
} else {
|
|
12383
|
+
await removeSystemd();
|
|
12384
|
+
}
|
|
12197
12385
|
const config = getCloudConfig2();
|
|
12198
12386
|
config.sync.schedule_minutes = 0;
|
|
12199
12387
|
saveCloudConfig2(config);
|
|
@@ -12202,17 +12390,26 @@ function getSyncScheduleStatus() {
|
|
|
12202
12390
|
const config = getCloudConfig2();
|
|
12203
12391
|
const minutes = config.sync.schedule_minutes;
|
|
12204
12392
|
const registered = minutes > 0;
|
|
12393
|
+
let mechanism = "none";
|
|
12394
|
+
if (registered) {
|
|
12395
|
+
if (platform() === "darwin") {
|
|
12396
|
+
mechanism = existsSync5(getLaunchdPlistPath()) ? "launchd" : "none";
|
|
12397
|
+
} else {
|
|
12398
|
+
mechanism = existsSync5(join5(getSystemdDir(), `${SERVICE_NAME}.timer`)) ? "systemd" : "none";
|
|
12399
|
+
}
|
|
12400
|
+
}
|
|
12205
12401
|
return {
|
|
12206
12402
|
registered,
|
|
12207
12403
|
schedule_minutes: minutes,
|
|
12208
|
-
cron_expression: registered ? minutesToCron(minutes) : null
|
|
12404
|
+
cron_expression: registered ? minutesToCron(minutes) : null,
|
|
12405
|
+
mechanism
|
|
12209
12406
|
};
|
|
12210
12407
|
}
|
|
12211
12408
|
|
|
12212
12409
|
// src/scheduled-sync.ts
|
|
12213
12410
|
init_config();
|
|
12214
12411
|
init_adapter();
|
|
12215
|
-
import { existsSync as
|
|
12412
|
+
import { existsSync as existsSync6, readdirSync as readdirSync3 } from "fs";
|
|
12216
12413
|
import { join as join6 } from "path";
|
|
12217
12414
|
|
|
12218
12415
|
// src/sync-incremental.ts
|
|
@@ -12355,7 +12552,7 @@ function discoverSyncableServices() {
|
|
|
12355
12552
|
if (!entry.isDirectory())
|
|
12356
12553
|
continue;
|
|
12357
12554
|
const dbPath = join6(hasnaDir, entry.name, `${entry.name}.db`);
|
|
12358
|
-
if (
|
|
12555
|
+
if (existsSync6(dbPath)) {
|
|
12359
12556
|
services.push(entry.name);
|
|
12360
12557
|
}
|
|
12361
12558
|
}
|
|
@@ -12378,7 +12575,7 @@ async function runScheduledSync() {
|
|
|
12378
12575
|
};
|
|
12379
12576
|
try {
|
|
12380
12577
|
const dbPath = join6(getDataDir(service), `${service}.db`);
|
|
12381
|
-
if (!
|
|
12578
|
+
if (!existsSync6(dbPath)) {
|
|
12382
12579
|
continue;
|
|
12383
12580
|
}
|
|
12384
12581
|
const local = new SqliteAdapter(dbPath);
|
|
@@ -12421,9 +12618,9 @@ async function runScheduledSync() {
|
|
|
12421
12618
|
}
|
|
12422
12619
|
|
|
12423
12620
|
// src/discover.ts
|
|
12424
|
-
import { readdirSync as readdirSync4, existsSync as
|
|
12621
|
+
import { readdirSync as readdirSync4, existsSync as existsSync7 } from "fs";
|
|
12425
12622
|
import { join as join7 } from "path";
|
|
12426
|
-
import { homedir as
|
|
12623
|
+
import { homedir as homedir6 } from "os";
|
|
12427
12624
|
var SYNC_EXCLUDED_TABLE_PATTERNS = [
|
|
12428
12625
|
/^sqlite_/,
|
|
12429
12626
|
/_fts$/,
|
|
@@ -12435,8 +12632,8 @@ function isSyncExcludedTable(table) {
|
|
|
12435
12632
|
return SYNC_EXCLUDED_TABLE_PATTERNS.some((p) => p.test(table));
|
|
12436
12633
|
}
|
|
12437
12634
|
function discoverServices() {
|
|
12438
|
-
const dataDir = join7(
|
|
12439
|
-
if (!
|
|
12635
|
+
const dataDir = join7(homedir6(), ".hasna");
|
|
12636
|
+
if (!existsSync7(dataDir))
|
|
12440
12637
|
return [];
|
|
12441
12638
|
try {
|
|
12442
12639
|
const entries = readdirSync4(dataDir, { withFileTypes: true });
|
package/dist/index.js
CHANGED
|
@@ -9347,15 +9347,15 @@ __export(exports_discover, {
|
|
|
9347
9347
|
SYNC_EXCLUDED_TABLE_PATTERNS: () => SYNC_EXCLUDED_TABLE_PATTERNS,
|
|
9348
9348
|
KNOWN_PG_SERVICES: () => KNOWN_PG_SERVICES
|
|
9349
9349
|
});
|
|
9350
|
-
import { readdirSync as readdirSync3, existsSync as
|
|
9350
|
+
import { readdirSync as readdirSync3, existsSync as existsSync6 } from "fs";
|
|
9351
9351
|
import { join as join6 } from "path";
|
|
9352
|
-
import { homedir as
|
|
9352
|
+
import { homedir as homedir5 } from "os";
|
|
9353
9353
|
function isSyncExcludedTable(table) {
|
|
9354
9354
|
return SYNC_EXCLUDED_TABLE_PATTERNS.some((p) => p.test(table));
|
|
9355
9355
|
}
|
|
9356
9356
|
function discoverServices() {
|
|
9357
|
-
const dataDir = join6(
|
|
9358
|
-
if (!
|
|
9357
|
+
const dataDir = join6(homedir5(), ".hasna");
|
|
9358
|
+
if (!existsSync6(dataDir))
|
|
9359
9359
|
return [];
|
|
9360
9360
|
try {
|
|
9361
9361
|
const entries = readdirSync3(dataDir, { withFileTypes: true });
|
|
@@ -9376,8 +9376,8 @@ function discoverSyncableServices2() {
|
|
|
9376
9376
|
return local.filter((s) => pgSet.has(s));
|
|
9377
9377
|
}
|
|
9378
9378
|
function getServiceDbPath(service) {
|
|
9379
|
-
const dataDir = join6(
|
|
9380
|
-
if (!
|
|
9379
|
+
const dataDir = join6(homedir5(), ".hasna", service);
|
|
9380
|
+
if (!existsSync6(dataDir))
|
|
9381
9381
|
return null;
|
|
9382
9382
|
const candidates = [
|
|
9383
9383
|
join6(dataDir, `${service}.db`),
|
|
@@ -9393,7 +9393,7 @@ function getServiceDbPath(service) {
|
|
|
9393
9393
|
}
|
|
9394
9394
|
} catch {}
|
|
9395
9395
|
for (const p of candidates) {
|
|
9396
|
-
if (
|
|
9396
|
+
if (existsSync6(p))
|
|
9397
9397
|
return p;
|
|
9398
9398
|
}
|
|
9399
9399
|
return null;
|
|
@@ -9571,6 +9571,59 @@ async function resolvePrimaryKeys(source, target, table, pkOption) {
|
|
|
9571
9571
|
}
|
|
9572
9572
|
return pks;
|
|
9573
9573
|
}
|
|
9574
|
+
function pgTypeToSqlite(pgType) {
|
|
9575
|
+
const t = pgType.toLowerCase();
|
|
9576
|
+
if (t.includes("int") || t === "bigint" || t === "smallint" || t === "serial" || t === "bigserial")
|
|
9577
|
+
return "INTEGER";
|
|
9578
|
+
if (t.includes("bool"))
|
|
9579
|
+
return "INTEGER";
|
|
9580
|
+
if (t.includes("float") || t.includes("double") || t === "real" || t === "numeric" || t === "decimal")
|
|
9581
|
+
return "REAL";
|
|
9582
|
+
if (t === "bytea")
|
|
9583
|
+
return "BLOB";
|
|
9584
|
+
return "TEXT";
|
|
9585
|
+
}
|
|
9586
|
+
async function ensureTableInSqliteFromPg(target, source, table) {
|
|
9587
|
+
const existing = target.all(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`, table);
|
|
9588
|
+
if (existing.length > 0)
|
|
9589
|
+
return false;
|
|
9590
|
+
const cols = await source.all(`SELECT column_name, data_type, is_nullable, column_default
|
|
9591
|
+
FROM information_schema.columns
|
|
9592
|
+
WHERE table_schema = 'public' AND table_name = '${table}'
|
|
9593
|
+
ORDER BY ordinal_position`);
|
|
9594
|
+
if (cols.length === 0)
|
|
9595
|
+
return false;
|
|
9596
|
+
const pkCols = await source.all(`SELECT kcu.column_name
|
|
9597
|
+
FROM information_schema.table_constraints tc
|
|
9598
|
+
JOIN information_schema.key_column_usage kcu
|
|
9599
|
+
ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema
|
|
9600
|
+
WHERE tc.constraint_type = 'PRIMARY KEY' AND tc.table_schema = 'public' AND tc.table_name = '${table}'
|
|
9601
|
+
ORDER BY kcu.ordinal_position`);
|
|
9602
|
+
const pkSet = new Set(pkCols.map((c) => c.column_name));
|
|
9603
|
+
const skipTypes = new Set(["tsvector", "tsquery", "user-defined"]);
|
|
9604
|
+
const filteredCols = cols.filter((c) => !skipTypes.has(c.data_type));
|
|
9605
|
+
const colDefs = filteredCols.map((c) => {
|
|
9606
|
+
const sqliteType = pgTypeToSqlite(c.data_type);
|
|
9607
|
+
const notNull = c.is_nullable === "NO" && !pkSet.has(c.column_name) ? " NOT NULL" : "";
|
|
9608
|
+
return `"${c.column_name}" ${sqliteType}${notNull}`;
|
|
9609
|
+
});
|
|
9610
|
+
if (pkSet.size > 0) {
|
|
9611
|
+
const pkList = [...pkSet].map((c) => `"${c}"`).join(", ");
|
|
9612
|
+
colDefs.push(`PRIMARY KEY (${pkList})`);
|
|
9613
|
+
}
|
|
9614
|
+
const sql = `CREATE TABLE IF NOT EXISTS "${table}" (${colDefs.join(", ")})`;
|
|
9615
|
+
target.exec(sql);
|
|
9616
|
+
process.stderr.write(` [sync] ${table}: auto-created in SQLite from PG schema
|
|
9617
|
+
`);
|
|
9618
|
+
return true;
|
|
9619
|
+
}
|
|
9620
|
+
async function ensureTablesExist(source, target, tables) {
|
|
9621
|
+
for (const table of tables) {
|
|
9622
|
+
if (!isAsyncAdapter(target) && isAsyncAdapter(source)) {
|
|
9623
|
+
await ensureTableInSqliteFromPg(target, source, table);
|
|
9624
|
+
}
|
|
9625
|
+
}
|
|
9626
|
+
}
|
|
9574
9627
|
async function filterColumnsForTarget(target, table, sourceColumns) {
|
|
9575
9628
|
try {
|
|
9576
9629
|
if (!isAsyncAdapter(target)) {
|
|
@@ -9605,6 +9658,7 @@ async function syncTransfer(source, target, options, _direction) {
|
|
|
9605
9658
|
} = options;
|
|
9606
9659
|
const results = [];
|
|
9607
9660
|
const sqliteTarget = !isAsyncAdapter(target) ? target : null;
|
|
9661
|
+
await ensureTablesExist(source, target, tables);
|
|
9608
9662
|
if (sqliteTarget) {
|
|
9609
9663
|
try {
|
|
9610
9664
|
sqliteTarget.exec("PRAGMA foreign_keys = OFF");
|
|
@@ -10536,18 +10590,10 @@ async function runScheduledSync() {
|
|
|
10536
10590
|
// src/sync-schedule.ts
|
|
10537
10591
|
init_config();
|
|
10538
10592
|
import { join as join5, dirname } from "path";
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
const jsPath = join5(dir, "scheduled-sync.js");
|
|
10544
|
-
try {
|
|
10545
|
-
const { existsSync: existsSync5 } = __require("fs");
|
|
10546
|
-
if (existsSync5(tsPath))
|
|
10547
|
-
return tsPath;
|
|
10548
|
-
} catch {}
|
|
10549
|
-
return jsPath;
|
|
10550
|
-
}
|
|
10593
|
+
import { existsSync as existsSync5, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
|
|
10594
|
+
import { homedir as homedir4, platform } from "os";
|
|
10595
|
+
var SERVICE_NAME = "hasna-cloud-sync";
|
|
10596
|
+
var CONFIG_DIR2 = join5(homedir4(), ".hasna", "cloud");
|
|
10551
10597
|
function parseInterval(input) {
|
|
10552
10598
|
const trimmed = input.trim().toLowerCase();
|
|
10553
10599
|
const hourMatch = trimmed.match(/^(\d+)\s*h$/);
|
|
@@ -10586,19 +10632,161 @@ function minutesToCron(minutes) {
|
|
|
10586
10632
|
}
|
|
10587
10633
|
return `*/${minutes} * * * *`;
|
|
10588
10634
|
}
|
|
10635
|
+
function getWorkerPath() {
|
|
10636
|
+
const dir = typeof import.meta.dir === "string" ? import.meta.dir : dirname(import.meta.url.replace("file://", ""));
|
|
10637
|
+
const tsPath = join5(dir, "scheduled-sync.ts");
|
|
10638
|
+
const jsPath = join5(dir, "scheduled-sync.js");
|
|
10639
|
+
try {
|
|
10640
|
+
if (existsSync5(tsPath))
|
|
10641
|
+
return tsPath;
|
|
10642
|
+
} catch {}
|
|
10643
|
+
return jsPath;
|
|
10644
|
+
}
|
|
10645
|
+
function getBunPath() {
|
|
10646
|
+
const candidates = [
|
|
10647
|
+
join5(homedir4(), ".bun", "bin", "bun"),
|
|
10648
|
+
"/usr/local/bin/bun",
|
|
10649
|
+
"/usr/bin/bun"
|
|
10650
|
+
];
|
|
10651
|
+
for (const p of candidates) {
|
|
10652
|
+
if (existsSync5(p))
|
|
10653
|
+
return p;
|
|
10654
|
+
}
|
|
10655
|
+
return "bun";
|
|
10656
|
+
}
|
|
10657
|
+
function getLaunchdPlistPath() {
|
|
10658
|
+
return join5(homedir4(), "Library", "LaunchAgents", `com.hasna.cloud-sync.plist`);
|
|
10659
|
+
}
|
|
10660
|
+
function createLaunchdPlist(intervalMinutes) {
|
|
10661
|
+
const workerPath = getWorkerPath();
|
|
10662
|
+
const bunPath = getBunPath();
|
|
10663
|
+
const logPath = join5(CONFIG_DIR2, "sync.log");
|
|
10664
|
+
const errorLogPath = join5(CONFIG_DIR2, "sync-error.log");
|
|
10665
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
10666
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
10667
|
+
<plist version="1.0">
|
|
10668
|
+
<dict>
|
|
10669
|
+
<key>Label</key>
|
|
10670
|
+
<string>com.hasna.cloud-sync</string>
|
|
10671
|
+
<key>ProgramArguments</key>
|
|
10672
|
+
<array>
|
|
10673
|
+
<string>${bunPath}</string>
|
|
10674
|
+
<string>run</string>
|
|
10675
|
+
<string>${workerPath}</string>
|
|
10676
|
+
</array>
|
|
10677
|
+
<key>StartInterval</key>
|
|
10678
|
+
<integer>${intervalMinutes * 60}</integer>
|
|
10679
|
+
<key>RunAtLoad</key>
|
|
10680
|
+
<true/>
|
|
10681
|
+
<key>StandardOutPath</key>
|
|
10682
|
+
<string>${logPath}</string>
|
|
10683
|
+
<key>StandardErrorPath</key>
|
|
10684
|
+
<string>${errorLogPath}</string>
|
|
10685
|
+
<key>EnvironmentVariables</key>
|
|
10686
|
+
<dict>
|
|
10687
|
+
<key>PATH</key>
|
|
10688
|
+
<string>${process.env.PATH || "/usr/local/bin:/usr/bin:/bin"}</string>
|
|
10689
|
+
<key>HOME</key>
|
|
10690
|
+
<string>${homedir4()}</string>
|
|
10691
|
+
</dict>
|
|
10692
|
+
</dict>
|
|
10693
|
+
</plist>`;
|
|
10694
|
+
}
|
|
10695
|
+
async function registerLaunchd(intervalMinutes) {
|
|
10696
|
+
const plistPath = getLaunchdPlistPath();
|
|
10697
|
+
const plistDir = dirname(plistPath);
|
|
10698
|
+
mkdirSync3(plistDir, { recursive: true });
|
|
10699
|
+
try {
|
|
10700
|
+
await Bun.spawn(["launchctl", "unload", plistPath]).exited;
|
|
10701
|
+
} catch {}
|
|
10702
|
+
writeFileSync2(plistPath, createLaunchdPlist(intervalMinutes));
|
|
10703
|
+
await Bun.spawn(["launchctl", "load", plistPath]).exited;
|
|
10704
|
+
}
|
|
10705
|
+
async function removeLaunchd() {
|
|
10706
|
+
const plistPath = getLaunchdPlistPath();
|
|
10707
|
+
try {
|
|
10708
|
+
await Bun.spawn(["launchctl", "unload", plistPath]).exited;
|
|
10709
|
+
} catch {}
|
|
10710
|
+
try {
|
|
10711
|
+
unlinkSync(plistPath);
|
|
10712
|
+
} catch {}
|
|
10713
|
+
}
|
|
10714
|
+
function getSystemdDir() {
|
|
10715
|
+
return join5(homedir4(), ".config", "systemd", "user");
|
|
10716
|
+
}
|
|
10717
|
+
function createSystemdService() {
|
|
10718
|
+
const workerPath = getWorkerPath();
|
|
10719
|
+
const bunPath = getBunPath();
|
|
10720
|
+
return `[Unit]
|
|
10721
|
+
Description=Hasna Cloud Sync
|
|
10722
|
+
After=network.target
|
|
10723
|
+
|
|
10724
|
+
[Service]
|
|
10725
|
+
Type=oneshot
|
|
10726
|
+
ExecStart=${bunPath} run ${workerPath}
|
|
10727
|
+
Environment=HOME=${homedir4()}
|
|
10728
|
+
Environment=PATH=${process.env.PATH || "/usr/local/bin:/usr/bin:/bin"}
|
|
10729
|
+
|
|
10730
|
+
[Install]
|
|
10731
|
+
WantedBy=default.target
|
|
10732
|
+
`;
|
|
10733
|
+
}
|
|
10734
|
+
function createSystemdTimer(intervalMinutes) {
|
|
10735
|
+
return `[Unit]
|
|
10736
|
+
Description=Hasna Cloud Sync Timer
|
|
10737
|
+
|
|
10738
|
+
[Timer]
|
|
10739
|
+
OnBootSec=${intervalMinutes}min
|
|
10740
|
+
OnUnitActiveSec=${intervalMinutes}min
|
|
10741
|
+
Persistent=true
|
|
10742
|
+
|
|
10743
|
+
[Install]
|
|
10744
|
+
WantedBy=timers.target
|
|
10745
|
+
`;
|
|
10746
|
+
}
|
|
10747
|
+
async function registerSystemd(intervalMinutes) {
|
|
10748
|
+
const dir = getSystemdDir();
|
|
10749
|
+
mkdirSync3(dir, { recursive: true });
|
|
10750
|
+
writeFileSync2(join5(dir, `${SERVICE_NAME}.service`), createSystemdService());
|
|
10751
|
+
writeFileSync2(join5(dir, `${SERVICE_NAME}.timer`), createSystemdTimer(intervalMinutes));
|
|
10752
|
+
await Bun.spawn(["systemctl", "--user", "daemon-reload"]).exited;
|
|
10753
|
+
await Bun.spawn(["systemctl", "--user", "enable", "--now", `${SERVICE_NAME}.timer`]).exited;
|
|
10754
|
+
}
|
|
10755
|
+
async function removeSystemd() {
|
|
10756
|
+
try {
|
|
10757
|
+
await Bun.spawn(["systemctl", "--user", "disable", "--now", `${SERVICE_NAME}.timer`]).exited;
|
|
10758
|
+
} catch {}
|
|
10759
|
+
const dir = getSystemdDir();
|
|
10760
|
+
try {
|
|
10761
|
+
unlinkSync(join5(dir, `${SERVICE_NAME}.service`));
|
|
10762
|
+
} catch {}
|
|
10763
|
+
try {
|
|
10764
|
+
unlinkSync(join5(dir, `${SERVICE_NAME}.timer`));
|
|
10765
|
+
} catch {}
|
|
10766
|
+
try {
|
|
10767
|
+
await Bun.spawn(["systemctl", "--user", "daemon-reload"]).exited;
|
|
10768
|
+
} catch {}
|
|
10769
|
+
}
|
|
10589
10770
|
async function registerSyncSchedule(intervalMinutes) {
|
|
10590
10771
|
if (intervalMinutes <= 0) {
|
|
10591
10772
|
throw new Error("Interval must be a positive number of minutes.");
|
|
10592
10773
|
}
|
|
10593
|
-
|
|
10594
|
-
|
|
10595
|
-
|
|
10774
|
+
mkdirSync3(CONFIG_DIR2, { recursive: true });
|
|
10775
|
+
if (platform() === "darwin") {
|
|
10776
|
+
await registerLaunchd(intervalMinutes);
|
|
10777
|
+
} else {
|
|
10778
|
+
await registerSystemd(intervalMinutes);
|
|
10779
|
+
}
|
|
10596
10780
|
const config = getCloudConfig();
|
|
10597
10781
|
config.sync.schedule_minutes = intervalMinutes;
|
|
10598
10782
|
saveCloudConfig(config);
|
|
10599
10783
|
}
|
|
10600
10784
|
async function removeSyncSchedule() {
|
|
10601
|
-
|
|
10785
|
+
if (platform() === "darwin") {
|
|
10786
|
+
await removeLaunchd();
|
|
10787
|
+
} else {
|
|
10788
|
+
await removeSystemd();
|
|
10789
|
+
}
|
|
10602
10790
|
const config = getCloudConfig();
|
|
10603
10791
|
config.sync.schedule_minutes = 0;
|
|
10604
10792
|
saveCloudConfig(config);
|
|
@@ -10607,10 +10795,19 @@ function getSyncScheduleStatus() {
|
|
|
10607
10795
|
const config = getCloudConfig();
|
|
10608
10796
|
const minutes = config.sync.schedule_minutes;
|
|
10609
10797
|
const registered = minutes > 0;
|
|
10798
|
+
let mechanism = "none";
|
|
10799
|
+
if (registered) {
|
|
10800
|
+
if (platform() === "darwin") {
|
|
10801
|
+
mechanism = existsSync5(getLaunchdPlistPath()) ? "launchd" : "none";
|
|
10802
|
+
} else {
|
|
10803
|
+
mechanism = existsSync5(join5(getSystemdDir(), `${SERVICE_NAME}.timer`)) ? "systemd" : "none";
|
|
10804
|
+
}
|
|
10805
|
+
}
|
|
10610
10806
|
return {
|
|
10611
10807
|
registered,
|
|
10612
10808
|
schedule_minutes: minutes,
|
|
10613
|
-
cron_expression: registered ? minutesToCron(minutes) : null
|
|
10809
|
+
cron_expression: registered ? minutesToCron(minutes) : null,
|
|
10810
|
+
mechanism
|
|
10614
10811
|
};
|
|
10615
10812
|
}
|
|
10616
10813
|
// src/pg-migrate.ts
|
package/dist/mcp/index.js
CHANGED
|
@@ -24786,6 +24786,59 @@ async function resolvePrimaryKeys(source, target, table, pkOption) {
|
|
|
24786
24786
|
}
|
|
24787
24787
|
return pks;
|
|
24788
24788
|
}
|
|
24789
|
+
function pgTypeToSqlite(pgType) {
|
|
24790
|
+
const t = pgType.toLowerCase();
|
|
24791
|
+
if (t.includes("int") || t === "bigint" || t === "smallint" || t === "serial" || t === "bigserial")
|
|
24792
|
+
return "INTEGER";
|
|
24793
|
+
if (t.includes("bool"))
|
|
24794
|
+
return "INTEGER";
|
|
24795
|
+
if (t.includes("float") || t.includes("double") || t === "real" || t === "numeric" || t === "decimal")
|
|
24796
|
+
return "REAL";
|
|
24797
|
+
if (t === "bytea")
|
|
24798
|
+
return "BLOB";
|
|
24799
|
+
return "TEXT";
|
|
24800
|
+
}
|
|
24801
|
+
async function ensureTableInSqliteFromPg(target, source, table) {
|
|
24802
|
+
const existing = target.all(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`, table);
|
|
24803
|
+
if (existing.length > 0)
|
|
24804
|
+
return false;
|
|
24805
|
+
const cols = await source.all(`SELECT column_name, data_type, is_nullable, column_default
|
|
24806
|
+
FROM information_schema.columns
|
|
24807
|
+
WHERE table_schema = 'public' AND table_name = '${table}'
|
|
24808
|
+
ORDER BY ordinal_position`);
|
|
24809
|
+
if (cols.length === 0)
|
|
24810
|
+
return false;
|
|
24811
|
+
const pkCols = await source.all(`SELECT kcu.column_name
|
|
24812
|
+
FROM information_schema.table_constraints tc
|
|
24813
|
+
JOIN information_schema.key_column_usage kcu
|
|
24814
|
+
ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema
|
|
24815
|
+
WHERE tc.constraint_type = 'PRIMARY KEY' AND tc.table_schema = 'public' AND tc.table_name = '${table}'
|
|
24816
|
+
ORDER BY kcu.ordinal_position`);
|
|
24817
|
+
const pkSet = new Set(pkCols.map((c) => c.column_name));
|
|
24818
|
+
const skipTypes = new Set(["tsvector", "tsquery", "user-defined"]);
|
|
24819
|
+
const filteredCols = cols.filter((c) => !skipTypes.has(c.data_type));
|
|
24820
|
+
const colDefs = filteredCols.map((c) => {
|
|
24821
|
+
const sqliteType = pgTypeToSqlite(c.data_type);
|
|
24822
|
+
const notNull = c.is_nullable === "NO" && !pkSet.has(c.column_name) ? " NOT NULL" : "";
|
|
24823
|
+
return `"${c.column_name}" ${sqliteType}${notNull}`;
|
|
24824
|
+
});
|
|
24825
|
+
if (pkSet.size > 0) {
|
|
24826
|
+
const pkList = [...pkSet].map((c) => `"${c}"`).join(", ");
|
|
24827
|
+
colDefs.push(`PRIMARY KEY (${pkList})`);
|
|
24828
|
+
}
|
|
24829
|
+
const sql = `CREATE TABLE IF NOT EXISTS "${table}" (${colDefs.join(", ")})`;
|
|
24830
|
+
target.exec(sql);
|
|
24831
|
+
process.stderr.write(` [sync] ${table}: auto-created in SQLite from PG schema
|
|
24832
|
+
`);
|
|
24833
|
+
return true;
|
|
24834
|
+
}
|
|
24835
|
+
async function ensureTablesExist(source, target, tables) {
|
|
24836
|
+
for (const table of tables) {
|
|
24837
|
+
if (!isAsyncAdapter(target) && isAsyncAdapter(source)) {
|
|
24838
|
+
await ensureTableInSqliteFromPg(target, source, table);
|
|
24839
|
+
}
|
|
24840
|
+
}
|
|
24841
|
+
}
|
|
24789
24842
|
async function filterColumnsForTarget(target, table, sourceColumns) {
|
|
24790
24843
|
try {
|
|
24791
24844
|
if (!isAsyncAdapter(target)) {
|
|
@@ -24820,6 +24873,7 @@ async function syncTransfer(source, target, options, _direction) {
|
|
|
24820
24873
|
} = options;
|
|
24821
24874
|
const results = [];
|
|
24822
24875
|
const sqliteTarget = !isAsyncAdapter(target) ? target : null;
|
|
24876
|
+
await ensureTablesExist(source, target, tables);
|
|
24823
24877
|
if (sqliteTarget) {
|
|
24824
24878
|
try {
|
|
24825
24879
|
sqliteTarget.exec("PRAGMA foreign_keys = OFF");
|
package/dist/sync-schedule.d.ts
CHANGED
|
@@ -9,34 +9,28 @@
|
|
|
9
9
|
export declare function parseInterval(input: string): number;
|
|
10
10
|
/**
|
|
11
11
|
* Convert minutes to a cron expression.
|
|
12
|
-
*
|
|
13
|
-
* - For intervals that divide evenly into 60: `*\/<n> * * * *`
|
|
14
|
-
* - For hourly multiples: `0 *\/<h> * * *`
|
|
15
|
-
* - Otherwise: `*\/<n> * * * *` (best-effort)
|
|
16
12
|
*/
|
|
17
13
|
export declare function minutesToCron(minutes: number): string;
|
|
18
14
|
export interface SyncScheduleStatus {
|
|
19
15
|
registered: boolean;
|
|
20
16
|
schedule_minutes: number;
|
|
21
17
|
cron_expression: string | null;
|
|
18
|
+
mechanism: "launchd" | "systemd" | "none";
|
|
22
19
|
}
|
|
23
20
|
/**
|
|
24
|
-
* Register a
|
|
25
|
-
* interval.
|
|
21
|
+
* Register a system-level scheduled sync.
|
|
26
22
|
*
|
|
27
|
-
* -
|
|
28
|
-
* -
|
|
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
|
|
29
26
|
*/
|
|
30
27
|
export declare function registerSyncSchedule(intervalMinutes: number): Promise<void>;
|
|
31
28
|
/**
|
|
32
|
-
* Remove the registered sync
|
|
33
|
-
*
|
|
34
|
-
* - Calls `Bun.cron.remove()` to unregister the OS-level job.
|
|
35
|
-
* - Sets `schedule_minutes` to 0 in config.
|
|
29
|
+
* Remove the registered sync schedule.
|
|
36
30
|
*/
|
|
37
31
|
export declare function removeSyncSchedule(): Promise<void>;
|
|
38
32
|
/**
|
|
39
|
-
* Get the current sync schedule status
|
|
33
|
+
* Get the current sync schedule status.
|
|
40
34
|
*/
|
|
41
35
|
export declare function getSyncScheduleStatus(): SyncScheduleStatus;
|
|
42
36
|
//# sourceMappingURL=sync-schedule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-schedule.d.ts","sourceRoot":"","sources":["../src/sync-schedule.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/sync.d.ts.map
CHANGED
|
@@ -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;;;;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;
|
|
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;AAwuBD;;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