@supacloud/lite 0.5.0 → 0.5.2
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/CHANGELOG.md +15 -0
- package/dist/cli.js +119 -64
- package/dist/index.js +66 -39
- package/dist/launcher.cjs +15 -2
- package/dist/snapshot.d.ts.map +1 -1
- package/dist/vendor/tinbase/db/data-dir-lock.d.ts +18 -0
- package/dist/vendor/tinbase/db/data-dir-lock.d.ts.map +1 -0
- package/dist/vendor/tinbase/db/pglite-engine.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.2](https://github.com/zuohuadong/supacloud/compare/supacloud-lite-v0.5.1...supacloud-lite-v0.5.2) (2026-07-30)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **lite:** release shadow backend after lock conflicts ([c44e7a3](https://github.com/zuohuadong/supacloud/commit/c44e7a3c17f3a2d1ae9f285f7f9ad5187ebd178b))
|
|
9
|
+
|
|
10
|
+
## [0.5.1](https://github.com/zuohuadong/supacloud/compare/supacloud-lite-v0.5.0...supacloud-lite-v0.5.1) (2026-07-30)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* make Lite Windows shutdown verification reliable ([#650](https://github.com/zuohuadong/supacloud/issues/650)) ([c208006](https://github.com/zuohuadong/supacloud/commit/c208006aa49839562dda5b0fe1419f183ceb5b12))
|
|
16
|
+
* stabilize Lite shutdown and Studio interactions ([a4d6f19](https://github.com/zuohuadong/supacloud/commit/a4d6f19db6c4aa71702fccec83bfbdd2a0c8b2b1))
|
|
17
|
+
|
|
3
18
|
## [0.5.0](https://github.com/zuohuadong/supacloud/compare/supacloud-lite-v0.4.0...supacloud-lite-v0.5.0) (2026-07-29)
|
|
4
19
|
|
|
5
20
|
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { dirname as dirname5, join as join9, resolve as resolve4 } from "path";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "@supacloud/lite",
|
|
11
|
-
version: "0.5.
|
|
11
|
+
version: "0.5.2",
|
|
12
12
|
description: "Bun-native, single-project Supabase-compatible backend powered by PGlite",
|
|
13
13
|
type: "module",
|
|
14
14
|
license: "Apache-2.0",
|
|
@@ -3290,9 +3290,57 @@ function pickTag(text, base) {
|
|
|
3290
3290
|
}
|
|
3291
3291
|
|
|
3292
3292
|
// src/vendor/tinbase/db/pglite-engine.ts
|
|
3293
|
-
import { mkdir, open,
|
|
3293
|
+
import { mkdir, open, unlink as unlink2 } from "fs/promises";
|
|
3294
3294
|
import { dirname, resolve } from "path";
|
|
3295
3295
|
|
|
3296
|
+
// src/vendor/tinbase/db/data-dir-lock.ts
|
|
3297
|
+
import { readFile, unlink } from "fs/promises";
|
|
3298
|
+
async function recoverStaleDataDirLock(lockPath) {
|
|
3299
|
+
const lockState = await inspectDataDirLock(lockPath);
|
|
3300
|
+
if (lockState.kind !== "stale")
|
|
3301
|
+
return lockState;
|
|
3302
|
+
try {
|
|
3303
|
+
await unlink(lockPath);
|
|
3304
|
+
return { kind: "missing" };
|
|
3305
|
+
} catch (error) {
|
|
3306
|
+
if (error.code === "ENOENT")
|
|
3307
|
+
return { kind: "missing" };
|
|
3308
|
+
throw error;
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
async function readDataDirLockOwner(lockPath) {
|
|
3312
|
+
const lockState = await inspectDataDirLock(lockPath);
|
|
3313
|
+
return lockState.kind === "active" || lockState.kind === "stale" ? lockState.owner : null;
|
|
3314
|
+
}
|
|
3315
|
+
async function inspectDataDirLock(lockPath) {
|
|
3316
|
+
let contents;
|
|
3317
|
+
try {
|
|
3318
|
+
contents = await readFile(lockPath, "utf8");
|
|
3319
|
+
} catch (error) {
|
|
3320
|
+
return error.code === "ENOENT" ? { kind: "missing" } : { kind: "unreadable" };
|
|
3321
|
+
}
|
|
3322
|
+
const owner = parseDataDirLockOwner(contents);
|
|
3323
|
+
if (!owner)
|
|
3324
|
+
return { kind: "unreadable" };
|
|
3325
|
+
return isProcessAlive(owner.pid) ? { kind: "active", owner } : { kind: "stale", owner };
|
|
3326
|
+
}
|
|
3327
|
+
function parseDataDirLockOwner(contents) {
|
|
3328
|
+
try {
|
|
3329
|
+
const value = JSON.parse(contents);
|
|
3330
|
+
return typeof value.pid === "number" && Number.isInteger(value.pid) && value.pid > 0 && typeof value.nonce === "string" ? { pid: value.pid, nonce: value.nonce } : null;
|
|
3331
|
+
} catch {
|
|
3332
|
+
return null;
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
function isProcessAlive(pid) {
|
|
3336
|
+
try {
|
|
3337
|
+
process.kill(pid, 0);
|
|
3338
|
+
return true;
|
|
3339
|
+
} catch (error) {
|
|
3340
|
+
return error.code === "EPERM";
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3296
3344
|
// src/standalone-assets-protocol.ts
|
|
3297
3345
|
var STANDALONE_PGLITE_ASSETS = Symbol.for("supacloud-lite.pglite-standalone-assets");
|
|
3298
3346
|
|
|
@@ -3427,31 +3475,27 @@ async function acquireDataDirLock(dataDir) {
|
|
|
3427
3475
|
return;
|
|
3428
3476
|
released = true;
|
|
3429
3477
|
await handle?.close();
|
|
3430
|
-
const owner = await
|
|
3478
|
+
const owner = await readDataDirLockOwner(lockPath);
|
|
3431
3479
|
if (owner?.nonce !== nonce)
|
|
3432
3480
|
return;
|
|
3433
|
-
await
|
|
3481
|
+
await unlink2(lockPath).catch((error) => {
|
|
3434
3482
|
if (error.code !== "ENOENT")
|
|
3435
3483
|
throw error;
|
|
3436
3484
|
});
|
|
3437
3485
|
};
|
|
3438
3486
|
}
|
|
3439
3487
|
async function createDataDirLock(absoluteDataDir, lockPath, nonce) {
|
|
3440
|
-
for (let attempt = 0;attempt <
|
|
3488
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
3441
3489
|
try {
|
|
3442
3490
|
return await writeDataDirLock(lockPath, nonce);
|
|
3443
3491
|
} catch (error) {
|
|
3444
3492
|
if (error.code !== "EEXIST")
|
|
3445
3493
|
throw error;
|
|
3446
|
-
const
|
|
3447
|
-
if (
|
|
3448
|
-
throw lockInUseError(absoluteDataDir, owner.pid);
|
|
3449
|
-
if (
|
|
3494
|
+
const lockState = await recoverStaleDataDirLock(lockPath);
|
|
3495
|
+
if (lockState.kind === "active")
|
|
3496
|
+
throw lockInUseError(absoluteDataDir, lockState.owner.pid);
|
|
3497
|
+
if (lockState.kind === "unreadable")
|
|
3450
3498
|
throw unreadableLockError(lockPath);
|
|
3451
|
-
await unlink(lockPath).catch((unlinkError) => {
|
|
3452
|
-
if (unlinkError.code !== "ENOENT")
|
|
3453
|
-
throw unlinkError;
|
|
3454
|
-
});
|
|
3455
3499
|
}
|
|
3456
3500
|
}
|
|
3457
3501
|
throw unreadableLockError(lockPath);
|
|
@@ -3464,7 +3508,7 @@ async function writeDataDirLock(lockPath, nonce) {
|
|
|
3464
3508
|
return handle;
|
|
3465
3509
|
} catch (error) {
|
|
3466
3510
|
await handle.close().catch(() => {});
|
|
3467
|
-
await
|
|
3511
|
+
await unlink2(lockPath).catch(() => {});
|
|
3468
3512
|
throw error;
|
|
3469
3513
|
}
|
|
3470
3514
|
}
|
|
@@ -3474,22 +3518,6 @@ function lockInUseError(dataDir, pid) {
|
|
|
3474
3518
|
function unreadableLockError(lockPath) {
|
|
3475
3519
|
return new Error(`PGlite data directory has an unreadable lock: ${lockPath}. Confirm no SupaCloud Lite process is using it, then remove the lock manually.`);
|
|
3476
3520
|
}
|
|
3477
|
-
async function readLockOwner(lockPath) {
|
|
3478
|
-
try {
|
|
3479
|
-
const value = JSON.parse(await readFile(lockPath, "utf8"));
|
|
3480
|
-
return typeof value.pid === "number" && Number.isInteger(value.pid) && value.pid > 0 && typeof value.nonce === "string" ? { pid: value.pid, nonce: value.nonce } : null;
|
|
3481
|
-
} catch {
|
|
3482
|
-
return null;
|
|
3483
|
-
}
|
|
3484
|
-
}
|
|
3485
|
-
function isProcessAlive(pid) {
|
|
3486
|
-
try {
|
|
3487
|
-
process.kill(pid, 0);
|
|
3488
|
-
return true;
|
|
3489
|
-
} catch (error) {
|
|
3490
|
-
return error.code === "EPERM";
|
|
3491
|
-
}
|
|
3492
|
-
}
|
|
3493
3521
|
|
|
3494
3522
|
// src/vendor/tinbase/db/database.ts
|
|
3495
3523
|
var DEFAULT_SEARCH_PATH_SQL = `set search_path to "$user", public, extensions`;
|
|
@@ -8035,18 +8063,27 @@ async function computeDbDiff(opts) {
|
|
|
8035
8063
|
engine: opts.makeShadowEngine ? await opts.makeShadowEngine() : undefined,
|
|
8036
8064
|
migrations: opts.migrations
|
|
8037
8065
|
});
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
dataDir: opts.liveEngine ? undefined : opts.liveDataDir,
|
|
8041
|
-
migrations: opts.migrations
|
|
8042
|
-
});
|
|
8066
|
+
let live;
|
|
8067
|
+
let operationFailed = false;
|
|
8043
8068
|
try {
|
|
8069
|
+
live = await createBackend({
|
|
8070
|
+
engine: opts.liveEngine,
|
|
8071
|
+
dataDir: opts.liveEngine ? undefined : opts.liveDataDir,
|
|
8072
|
+
migrations: opts.migrations
|
|
8073
|
+
});
|
|
8044
8074
|
const shadowSnap = await snapshotSchema(shadow.db, schema);
|
|
8045
8075
|
const liveSnap = await snapshotSchema(live.db, schema);
|
|
8046
8076
|
return diffSchemas(shadowSnap, liveSnap, schema);
|
|
8077
|
+
} catch (error) {
|
|
8078
|
+
operationFailed = true;
|
|
8079
|
+
throw error;
|
|
8047
8080
|
} finally {
|
|
8048
|
-
|
|
8049
|
-
|
|
8081
|
+
try {
|
|
8082
|
+
await closeBackends(live, shadow);
|
|
8083
|
+
} catch (error) {
|
|
8084
|
+
if (!operationFailed)
|
|
8085
|
+
throw error;
|
|
8086
|
+
}
|
|
8050
8087
|
}
|
|
8051
8088
|
}
|
|
8052
8089
|
async function pullSchema(opts) {
|
|
@@ -8055,12 +8092,14 @@ async function pullSchema(opts) {
|
|
|
8055
8092
|
engine: opts.makeShadowEngine ? await opts.makeShadowEngine() : undefined,
|
|
8056
8093
|
migrations: opts.migrations
|
|
8057
8094
|
});
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
dataDir: opts.liveEngine ? undefined : opts.liveDataDir,
|
|
8061
|
-
migrations: opts.migrations
|
|
8062
|
-
});
|
|
8095
|
+
let live;
|
|
8096
|
+
let operationFailed = false;
|
|
8063
8097
|
try {
|
|
8098
|
+
live = await createBackend({
|
|
8099
|
+
engine: opts.liveEngine,
|
|
8100
|
+
dataDir: opts.liveEngine ? undefined : opts.liveDataDir,
|
|
8101
|
+
migrations: opts.migrations
|
|
8102
|
+
});
|
|
8064
8103
|
const ddl = diffSchemas(await snapshotSchema(shadow.db, schema), await snapshotSchema(live.db, schema), schema);
|
|
8065
8104
|
if (ddl.length === 0)
|
|
8066
8105
|
return { ddl, version: null, path: null };
|
|
@@ -8079,11 +8118,24 @@ async function pullSchema(opts) {
|
|
|
8079
8118
|
await live.db.query(`insert into supabase_migrations.schema_migrations (version, name, statements)
|
|
8080
8119
|
values ($1, $2, $3) on conflict (version) do nothing`, [stamp, `${stamp}_${name}`, [body]]);
|
|
8081
8120
|
return { ddl, version: stamp, path };
|
|
8121
|
+
} catch (error) {
|
|
8122
|
+
operationFailed = true;
|
|
8123
|
+
throw error;
|
|
8082
8124
|
} finally {
|
|
8083
|
-
|
|
8084
|
-
|
|
8125
|
+
try {
|
|
8126
|
+
await closeBackends(live, shadow);
|
|
8127
|
+
} catch (error) {
|
|
8128
|
+
if (!operationFailed)
|
|
8129
|
+
throw error;
|
|
8130
|
+
}
|
|
8085
8131
|
}
|
|
8086
8132
|
}
|
|
8133
|
+
async function closeBackends(...backends) {
|
|
8134
|
+
const results = await Promise.allSettled(backends.filter((backend) => backend !== undefined).map(async (backend) => await backend.close()));
|
|
8135
|
+
const failed = results.find((result) => result.status === "rejected");
|
|
8136
|
+
if (failed?.status === "rejected")
|
|
8137
|
+
throw failed.reason;
|
|
8138
|
+
}
|
|
8087
8139
|
|
|
8088
8140
|
// src/vendor/tinbase/node/project.ts
|
|
8089
8141
|
import { readdir, readFile as readFile2 } from "fs/promises";
|
|
@@ -8131,7 +8183,7 @@ function isNotFound(error) {
|
|
|
8131
8183
|
}
|
|
8132
8184
|
|
|
8133
8185
|
// src/project-runtime.ts
|
|
8134
|
-
import { chmod, link, lstat, mkdir as mkdir5, readFile as readFile6, realpath as realpath2, unlink as
|
|
8186
|
+
import { chmod, link, lstat, mkdir as mkdir5, readFile as readFile6, realpath as realpath2, unlink as unlink3, writeFile as writeFile4 } from "fs/promises";
|
|
8135
8187
|
import { dirname as dirname3, isAbsolute, join as join7, parse, relative, resolve as resolve2 } from "path";
|
|
8136
8188
|
|
|
8137
8189
|
// src/vendor/tinbase/node/bun-server.ts
|
|
@@ -8947,7 +8999,7 @@ async function ensureProjectSecrets(paths) {
|
|
|
8947
8999
|
throw error2;
|
|
8948
9000
|
stored = validateSecrets(JSON.parse(await readFile6(paths.secretsFile, "utf8")));
|
|
8949
9001
|
} finally {
|
|
8950
|
-
await
|
|
9002
|
+
await unlink3(temporaryFile).catch((error2) => {
|
|
8951
9003
|
if (error2.code !== "ENOENT")
|
|
8952
9004
|
throw error2;
|
|
8953
9005
|
});
|
|
@@ -9322,13 +9374,12 @@ async function assertNoDataDirectoryLock(paths) {
|
|
|
9322
9374
|
if (!paths.dataDir)
|
|
9323
9375
|
return;
|
|
9324
9376
|
const lockPath = `${paths.dataDir}.supacloud-lite.lock`;
|
|
9325
|
-
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
}
|
|
9377
|
+
const lockState = await recoverStaleDataDirLock(lockPath);
|
|
9378
|
+
if (lockState.kind === "missing")
|
|
9379
|
+
return;
|
|
9380
|
+
if (lockState.kind === "active")
|
|
9381
|
+
throw new Error(`data directory is already in use: ${paths.dataDir} (pid ${lockState.owner.pid})`);
|
|
9382
|
+
throw new Error(`data directory has an unreadable lock: ${lockPath}; confirm Lite is stopped, then remove the lock manually`);
|
|
9332
9383
|
}
|
|
9333
9384
|
async function stageDirectory(root, destination) {
|
|
9334
9385
|
try {
|
|
@@ -9522,6 +9573,20 @@ function pathsOverlap(left, right) {
|
|
|
9522
9573
|
return normalizedLeft === normalizedRight || isWithin(normalizedLeft, normalizedRight) || isWithin(normalizedRight, normalizedLeft);
|
|
9523
9574
|
}
|
|
9524
9575
|
|
|
9576
|
+
// src/shutdown.ts
|
|
9577
|
+
async function waitForShutdown(closeProject, signalSource = process) {
|
|
9578
|
+
await new Promise((resolveShutdown) => {
|
|
9579
|
+
const resolveOnSignal = () => {
|
|
9580
|
+
signalSource.off("SIGINT", resolveOnSignal);
|
|
9581
|
+
signalSource.off("SIGTERM", resolveOnSignal);
|
|
9582
|
+
resolveShutdown();
|
|
9583
|
+
};
|
|
9584
|
+
signalSource.once("SIGINT", resolveOnSignal);
|
|
9585
|
+
signalSource.once("SIGTERM", resolveOnSignal);
|
|
9586
|
+
});
|
|
9587
|
+
await closeProject();
|
|
9588
|
+
}
|
|
9589
|
+
|
|
9525
9590
|
// src/cli.ts
|
|
9526
9591
|
function parseArgs(argv) {
|
|
9527
9592
|
const args = [...argv];
|
|
@@ -9687,6 +9752,7 @@ Use --service-role to print the privileged key.`);
|
|
|
9687
9752
|
Run "supacloud-lite keys --service-role" only when privileged access is required.
|
|
9688
9753
|
`);
|
|
9689
9754
|
await waitForShutdown(() => project.close());
|
|
9755
|
+
process.exitCode = 0;
|
|
9690
9756
|
}
|
|
9691
9757
|
async function runDbCommand(options) {
|
|
9692
9758
|
const subcommand = options.positionals[0];
|
|
@@ -9815,17 +9881,6 @@ function timestamp() {
|
|
|
9815
9881
|
return new Date().toISOString().replace(/[-:T]/g, "").slice(0, 14);
|
|
9816
9882
|
}
|
|
9817
9883
|
function quietLog() {}
|
|
9818
|
-
function waitForShutdown(closeProject) {
|
|
9819
|
-
return new Promise((resolveShutdown, rejectShutdown) => {
|
|
9820
|
-
const closeOnSignal = () => {
|
|
9821
|
-
process.off("SIGINT", closeOnSignal);
|
|
9822
|
-
process.off("SIGTERM", closeOnSignal);
|
|
9823
|
-
closeProject().then(resolveShutdown, rejectShutdown);
|
|
9824
|
-
};
|
|
9825
|
-
process.once("SIGINT", closeOnSignal);
|
|
9826
|
-
process.once("SIGTERM", closeOnSignal);
|
|
9827
|
-
});
|
|
9828
|
-
}
|
|
9829
9884
|
function printHelp() {
|
|
9830
9885
|
console.log(`supacloud-lite - Bun-native Supabase-compatible backend on PGlite
|
|
9831
9886
|
|
package/dist/index.js
CHANGED
|
@@ -71,7 +71,7 @@ function randomToken(bytes = 32) {
|
|
|
71
71
|
// package.json
|
|
72
72
|
var package_default = {
|
|
73
73
|
name: "@supacloud/lite",
|
|
74
|
-
version: "0.5.
|
|
74
|
+
version: "0.5.2",
|
|
75
75
|
description: "Bun-native, single-project Supabase-compatible backend powered by PGlite",
|
|
76
76
|
type: "module",
|
|
77
77
|
license: "Apache-2.0",
|
|
@@ -3295,9 +3295,57 @@ function pickTag(text, base) {
|
|
|
3295
3295
|
}
|
|
3296
3296
|
|
|
3297
3297
|
// src/vendor/tinbase/db/pglite-engine.ts
|
|
3298
|
-
import { mkdir, open,
|
|
3298
|
+
import { mkdir, open, unlink as unlink2 } from "fs/promises";
|
|
3299
3299
|
import { dirname, resolve } from "path";
|
|
3300
3300
|
|
|
3301
|
+
// src/vendor/tinbase/db/data-dir-lock.ts
|
|
3302
|
+
import { readFile, unlink } from "fs/promises";
|
|
3303
|
+
async function recoverStaleDataDirLock(lockPath) {
|
|
3304
|
+
const lockState = await inspectDataDirLock(lockPath);
|
|
3305
|
+
if (lockState.kind !== "stale")
|
|
3306
|
+
return lockState;
|
|
3307
|
+
try {
|
|
3308
|
+
await unlink(lockPath);
|
|
3309
|
+
return { kind: "missing" };
|
|
3310
|
+
} catch (error) {
|
|
3311
|
+
if (error.code === "ENOENT")
|
|
3312
|
+
return { kind: "missing" };
|
|
3313
|
+
throw error;
|
|
3314
|
+
}
|
|
3315
|
+
}
|
|
3316
|
+
async function readDataDirLockOwner(lockPath) {
|
|
3317
|
+
const lockState = await inspectDataDirLock(lockPath);
|
|
3318
|
+
return lockState.kind === "active" || lockState.kind === "stale" ? lockState.owner : null;
|
|
3319
|
+
}
|
|
3320
|
+
async function inspectDataDirLock(lockPath) {
|
|
3321
|
+
let contents;
|
|
3322
|
+
try {
|
|
3323
|
+
contents = await readFile(lockPath, "utf8");
|
|
3324
|
+
} catch (error) {
|
|
3325
|
+
return error.code === "ENOENT" ? { kind: "missing" } : { kind: "unreadable" };
|
|
3326
|
+
}
|
|
3327
|
+
const owner = parseDataDirLockOwner(contents);
|
|
3328
|
+
if (!owner)
|
|
3329
|
+
return { kind: "unreadable" };
|
|
3330
|
+
return isProcessAlive(owner.pid) ? { kind: "active", owner } : { kind: "stale", owner };
|
|
3331
|
+
}
|
|
3332
|
+
function parseDataDirLockOwner(contents) {
|
|
3333
|
+
try {
|
|
3334
|
+
const value = JSON.parse(contents);
|
|
3335
|
+
return typeof value.pid === "number" && Number.isInteger(value.pid) && value.pid > 0 && typeof value.nonce === "string" ? { pid: value.pid, nonce: value.nonce } : null;
|
|
3336
|
+
} catch {
|
|
3337
|
+
return null;
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
function isProcessAlive(pid) {
|
|
3341
|
+
try {
|
|
3342
|
+
process.kill(pid, 0);
|
|
3343
|
+
return true;
|
|
3344
|
+
} catch (error) {
|
|
3345
|
+
return error.code === "EPERM";
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
|
|
3301
3349
|
// src/standalone-assets-protocol.ts
|
|
3302
3350
|
var STANDALONE_PGLITE_ASSETS = Symbol.for("supacloud-lite.pglite-standalone-assets");
|
|
3303
3351
|
|
|
@@ -3432,31 +3480,27 @@ async function acquireDataDirLock(dataDir) {
|
|
|
3432
3480
|
return;
|
|
3433
3481
|
released = true;
|
|
3434
3482
|
await handle?.close();
|
|
3435
|
-
const owner = await
|
|
3483
|
+
const owner = await readDataDirLockOwner(lockPath);
|
|
3436
3484
|
if (owner?.nonce !== nonce)
|
|
3437
3485
|
return;
|
|
3438
|
-
await
|
|
3486
|
+
await unlink2(lockPath).catch((error) => {
|
|
3439
3487
|
if (error.code !== "ENOENT")
|
|
3440
3488
|
throw error;
|
|
3441
3489
|
});
|
|
3442
3490
|
};
|
|
3443
3491
|
}
|
|
3444
3492
|
async function createDataDirLock(absoluteDataDir, lockPath, nonce) {
|
|
3445
|
-
for (let attempt = 0;attempt <
|
|
3493
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
3446
3494
|
try {
|
|
3447
3495
|
return await writeDataDirLock(lockPath, nonce);
|
|
3448
3496
|
} catch (error) {
|
|
3449
3497
|
if (error.code !== "EEXIST")
|
|
3450
3498
|
throw error;
|
|
3451
|
-
const
|
|
3452
|
-
if (
|
|
3453
|
-
throw lockInUseError(absoluteDataDir, owner.pid);
|
|
3454
|
-
if (
|
|
3499
|
+
const lockState = await recoverStaleDataDirLock(lockPath);
|
|
3500
|
+
if (lockState.kind === "active")
|
|
3501
|
+
throw lockInUseError(absoluteDataDir, lockState.owner.pid);
|
|
3502
|
+
if (lockState.kind === "unreadable")
|
|
3455
3503
|
throw unreadableLockError(lockPath);
|
|
3456
|
-
await unlink(lockPath).catch((unlinkError) => {
|
|
3457
|
-
if (unlinkError.code !== "ENOENT")
|
|
3458
|
-
throw unlinkError;
|
|
3459
|
-
});
|
|
3460
3504
|
}
|
|
3461
3505
|
}
|
|
3462
3506
|
throw unreadableLockError(lockPath);
|
|
@@ -3469,7 +3513,7 @@ async function writeDataDirLock(lockPath, nonce) {
|
|
|
3469
3513
|
return handle;
|
|
3470
3514
|
} catch (error) {
|
|
3471
3515
|
await handle.close().catch(() => {});
|
|
3472
|
-
await
|
|
3516
|
+
await unlink2(lockPath).catch(() => {});
|
|
3473
3517
|
throw error;
|
|
3474
3518
|
}
|
|
3475
3519
|
}
|
|
@@ -3479,22 +3523,6 @@ function lockInUseError(dataDir, pid) {
|
|
|
3479
3523
|
function unreadableLockError(lockPath) {
|
|
3480
3524
|
return new Error(`PGlite data directory has an unreadable lock: ${lockPath}. Confirm no SupaCloud Lite process is using it, then remove the lock manually.`);
|
|
3481
3525
|
}
|
|
3482
|
-
async function readLockOwner(lockPath) {
|
|
3483
|
-
try {
|
|
3484
|
-
const value = JSON.parse(await readFile(lockPath, "utf8"));
|
|
3485
|
-
return typeof value.pid === "number" && Number.isInteger(value.pid) && value.pid > 0 && typeof value.nonce === "string" ? { pid: value.pid, nonce: value.nonce } : null;
|
|
3486
|
-
} catch {
|
|
3487
|
-
return null;
|
|
3488
|
-
}
|
|
3489
|
-
}
|
|
3490
|
-
function isProcessAlive(pid) {
|
|
3491
|
-
try {
|
|
3492
|
-
process.kill(pid, 0);
|
|
3493
|
-
return true;
|
|
3494
|
-
} catch (error) {
|
|
3495
|
-
return error.code === "EPERM";
|
|
3496
|
-
}
|
|
3497
|
-
}
|
|
3498
3526
|
|
|
3499
3527
|
// src/vendor/tinbase/db/database.ts
|
|
3500
3528
|
var DEFAULT_SEARCH_PATH_SQL = `set search_path to "$user", public, extensions`;
|
|
@@ -8039,7 +8067,7 @@ async function serveBun(backend, opts = {}) {
|
|
|
8039
8067
|
};
|
|
8040
8068
|
}
|
|
8041
8069
|
// src/project-runtime.ts
|
|
8042
|
-
import { chmod, link, lstat, mkdir as mkdir4, readFile as readFile6, realpath as realpath2, unlink as
|
|
8070
|
+
import { chmod, link, lstat, mkdir as mkdir4, readFile as readFile6, realpath as realpath2, unlink as unlink3, writeFile as writeFile3 } from "fs/promises";
|
|
8043
8071
|
import { dirname as dirname3, isAbsolute, join as join6, parse, relative, resolve as resolve2 } from "path";
|
|
8044
8072
|
|
|
8045
8073
|
// src/vendor/tinbase/node/config-toml.ts
|
|
@@ -8659,7 +8687,7 @@ async function ensureProjectSecrets(paths) {
|
|
|
8659
8687
|
throw error2;
|
|
8660
8688
|
stored = validateSecrets(JSON.parse(await readFile6(paths.secretsFile, "utf8")));
|
|
8661
8689
|
} finally {
|
|
8662
|
-
await
|
|
8690
|
+
await unlink3(temporaryFile).catch((error2) => {
|
|
8663
8691
|
if (error2.code !== "ENOENT")
|
|
8664
8692
|
throw error2;
|
|
8665
8693
|
});
|
|
@@ -9033,13 +9061,12 @@ async function assertNoDataDirectoryLock(paths) {
|
|
|
9033
9061
|
if (!paths.dataDir)
|
|
9034
9062
|
return;
|
|
9035
9063
|
const lockPath = `${paths.dataDir}.supacloud-lite.lock`;
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
}
|
|
9064
|
+
const lockState = await recoverStaleDataDirLock(lockPath);
|
|
9065
|
+
if (lockState.kind === "missing")
|
|
9066
|
+
return;
|
|
9067
|
+
if (lockState.kind === "active")
|
|
9068
|
+
throw new Error(`data directory is already in use: ${paths.dataDir} (pid ${lockState.owner.pid})`);
|
|
9069
|
+
throw new Error(`data directory has an unreadable lock: ${lockPath}; confirm Lite is stopped, then remove the lock manually`);
|
|
9043
9070
|
}
|
|
9044
9071
|
async function stageDirectory(root, destination) {
|
|
9045
9072
|
try {
|
package/dist/launcher.cjs
CHANGED
|
@@ -6,6 +6,18 @@ const { join } = require('node:path')
|
|
|
6
6
|
|
|
7
7
|
const cliPath = join(__dirname, 'cli.js')
|
|
8
8
|
const bunProcess = spawn('bun', [cliPath, ...process.argv.slice(2)], { shell: false, stdio: 'inherit' })
|
|
9
|
+
let requestedShutdownSignal = null
|
|
10
|
+
|
|
11
|
+
function forwardShutdownSignal(signal) {
|
|
12
|
+
if (requestedShutdownSignal || bunProcess.exitCode !== null || bunProcess.signalCode !== null) return
|
|
13
|
+
requestedShutdownSignal = signal
|
|
14
|
+
bunProcess.kill(signal)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const forwardSigint = () => forwardShutdownSignal('SIGINT')
|
|
18
|
+
const forwardSigterm = () => forwardShutdownSignal('SIGTERM')
|
|
19
|
+
process.once('SIGINT', forwardSigint)
|
|
20
|
+
process.once('SIGTERM', forwardSigterm)
|
|
9
21
|
|
|
10
22
|
bunProcess.once('error', (error) => {
|
|
11
23
|
if (error.code === 'ENOENT') {
|
|
@@ -17,6 +29,7 @@ bunProcess.once('error', (error) => {
|
|
|
17
29
|
})
|
|
18
30
|
|
|
19
31
|
bunProcess.once('exit', (exitCode, signal) => {
|
|
20
|
-
|
|
21
|
-
|
|
32
|
+
process.off('SIGINT', forwardSigint)
|
|
33
|
+
process.off('SIGTERM', forwardSigterm)
|
|
34
|
+
process.exitCode = exitCode ?? (requestedShutdownSignal === signal ? 0 : 1)
|
|
22
35
|
})
|
package/dist/snapshot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAGlF,QAAA,MAAM,eAAe,4BAA4B,CAAA;AACjD,QAAA,MAAM,gBAAgB,IAAI,CAAA;AAE1B,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,eAAe,CAAA;IAC9B,OAAO,EAAE,OAAO,gBAAgB,CAAA;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,wBAAwB,CAAA;IACxC,gBAAgB,EAAE,OAAO,CAAA;IACzB,oBAAoB,EAAE,OAAO,CAAA;IAC7B,eAAe,EAAE,IAAI,CAAA;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,YAAY,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,wBAAwB,CAAA;IACxC,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,YAAY,CAAA;IACnB,cAAc,EAAE,wBAAwB,CAAA;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAA;CACxB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqC9F;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA0FrG"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface DataDirLockOwner {
|
|
2
|
+
pid: number;
|
|
3
|
+
nonce: string;
|
|
4
|
+
}
|
|
5
|
+
export type DataDirLockState = {
|
|
6
|
+
kind: 'missing';
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'unreadable';
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'active';
|
|
11
|
+
owner: DataDirLockOwner;
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'stale';
|
|
14
|
+
owner: DataDirLockOwner;
|
|
15
|
+
};
|
|
16
|
+
export declare function recoverStaleDataDirLock(lockPath: string): Promise<DataDirLockState>;
|
|
17
|
+
export declare function readDataDirLockOwner(lockPath: string): Promise<DataDirLockOwner | null>;
|
|
18
|
+
//# sourceMappingURL=data-dir-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-dir-lock.d.ts","sourceRoot":"","sources":["../../../../src/vendor/tinbase/db/data-dir-lock.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,CAAA;AAE9C,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAWzF;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAG7F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pglite-engine.d.ts","sourceRoot":"","sources":["../../../../src/vendor/tinbase/db/pglite-engine.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAA2B,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"pglite-engine.d.ts","sourceRoot":"","sources":["../../../../src/vendor/tinbase/db/pglite-engine.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAA2B,MAAM,aAAa,CAAA;AAOpE;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmG5E"}
|