lianrouter 2.1.1 → 2.2.1
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.js +198 -20
- package/package.json +43 -43
package/dist/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ var package_default;
|
|
|
17
17
|
var init_package = __esm(() => {
|
|
18
18
|
package_default = {
|
|
19
19
|
name: "lianrouter",
|
|
20
|
-
version: "2.
|
|
20
|
+
version: "2.2.1",
|
|
21
21
|
description: "LianRouter launcher: install, run and control the gateway from one command",
|
|
22
22
|
type: "module",
|
|
23
23
|
bin: {
|
|
@@ -482,7 +482,7 @@ class GitHubReleaseSource {
|
|
|
482
482
|
};
|
|
483
483
|
});
|
|
484
484
|
return {
|
|
485
|
-
version: newest.tag_name,
|
|
485
|
+
version: normalizeVersion(newest.tag_name),
|
|
486
486
|
notesUrl: newest.html_url,
|
|
487
487
|
...newest.published_at.length > 0 ? { publishedAt: newest.published_at } : {},
|
|
488
488
|
assets
|
|
@@ -507,7 +507,7 @@ var init_github_source = __esm(() => {
|
|
|
507
507
|
});
|
|
508
508
|
|
|
509
509
|
// cli/update/install.ts
|
|
510
|
-
import { cp, mkdir as mkdir2, rename, rm as rm3, stat } from "fs/promises";
|
|
510
|
+
import { cp, mkdir as mkdir2, readdir as readdir2, rename, rm as rm3, stat } from "fs/promises";
|
|
511
511
|
import { dirname, join as join2, relative, resolve as resolve2, sep as sep2 } from "path";
|
|
512
512
|
async function pathExists(target) {
|
|
513
513
|
try {
|
|
@@ -534,6 +534,26 @@ async function assertNotDevCheckout(installRoot) {
|
|
|
534
534
|
throw new Error(`refusing to self-update ${root}: it is a source checkout (.git and src/main.ts present). ` + "Build locally with `bun run build` instead of installing a release over the working tree.");
|
|
535
535
|
}
|
|
536
536
|
}
|
|
537
|
+
async function sweepBackups(root, remove = rm3) {
|
|
538
|
+
const backupDir = join2(resolve2(root), BACKUP_DIR_NAME);
|
|
539
|
+
let entries;
|
|
540
|
+
try {
|
|
541
|
+
entries = await readdir2(backupDir);
|
|
542
|
+
} catch {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
let failed = false;
|
|
546
|
+
for (const entry of entries) {
|
|
547
|
+
await remove(join2(backupDir, entry), { recursive: true, force: true }).catch(() => {
|
|
548
|
+
failed = true;
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
if (!failed) {
|
|
552
|
+
await remove(backupDir, { recursive: true, force: true }).catch(() => {
|
|
553
|
+
return;
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
537
557
|
async function installAtomically(options) {
|
|
538
558
|
const root = resolve2(options.installRoot);
|
|
539
559
|
const staged = resolve2(options.stagedDir);
|
|
@@ -590,7 +610,7 @@ async function installAtomically(options) {
|
|
|
590
610
|
throw error;
|
|
591
611
|
}
|
|
592
612
|
onProgress?.({ percent: 100, message: "install complete" });
|
|
593
|
-
await
|
|
613
|
+
await sweepBackups(root, options.remove ?? rm3);
|
|
594
614
|
}
|
|
595
615
|
var BACKUP_DIR_NAME = ".backup";
|
|
596
616
|
var init_install = () => {};
|
|
@@ -618,15 +638,19 @@ async function readInstalledVersion(installRoot) {
|
|
|
618
638
|
if (typeof version !== "string" || version.trim().length === 0) {
|
|
619
639
|
return;
|
|
620
640
|
}
|
|
641
|
+
const normalized = normalizeVersion(version);
|
|
642
|
+
if (normalized.length === 0) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
621
645
|
return {
|
|
622
|
-
version:
|
|
646
|
+
version: normalized,
|
|
623
647
|
installedAt: typeof installedAt === "string" ? installedAt : "",
|
|
624
648
|
assetName: typeof assetName === "string" ? assetName : ""
|
|
625
649
|
};
|
|
626
650
|
}
|
|
627
651
|
async function writeInstalledVersion(installRoot, record) {
|
|
628
652
|
const payload = {
|
|
629
|
-
version: record.version,
|
|
653
|
+
version: normalizeVersion(record.version),
|
|
630
654
|
installedAt: record.installedAt,
|
|
631
655
|
assetName: record.assetName
|
|
632
656
|
};
|
|
@@ -646,7 +670,7 @@ var init_version_file = __esm(() => {
|
|
|
646
670
|
});
|
|
647
671
|
|
|
648
672
|
// cli/update/engine.ts
|
|
649
|
-
import { mkdtemp, readdir as
|
|
673
|
+
import { mkdtemp, readdir as readdir3, rm as rm4 } from "fs/promises";
|
|
650
674
|
import { tmpdir } from "os";
|
|
651
675
|
import { join as join4 } from "path";
|
|
652
676
|
function withinSlice(start, end, percent) {
|
|
@@ -700,7 +724,7 @@ async function resolveInstallCandidate(opts) {
|
|
|
700
724
|
};
|
|
701
725
|
}
|
|
702
726
|
async function payloadEntries(stagedDir) {
|
|
703
|
-
const entries = await
|
|
727
|
+
const entries = await readdir3(stagedDir, { withFileTypes: true });
|
|
704
728
|
return entries.map((entry) => entry.name);
|
|
705
729
|
}
|
|
706
730
|
async function runUpdate(opts) {
|
|
@@ -868,6 +892,9 @@ function resolveBinaryPath(installRoot = resolveInstallRoot(), platform = proces
|
|
|
868
892
|
function resolveLogFile(installRoot = resolveInstallRoot()) {
|
|
869
893
|
return join5(installRoot, LOGS_DIR, LOG_FILE_NAME);
|
|
870
894
|
}
|
|
895
|
+
function resolveConfigFile(installRoot = resolveInstallRoot()) {
|
|
896
|
+
return join5(installRoot, CONFIG_FILE_NAME);
|
|
897
|
+
}
|
|
871
898
|
function resolvePidFile(installRoot = resolveInstallRoot()) {
|
|
872
899
|
return join5(resolveStateDir(installRoot), PID_FILE_NAME);
|
|
873
900
|
}
|
|
@@ -930,7 +957,7 @@ function consoleUrl(port, host = "localhost") {
|
|
|
930
957
|
function healthUrl(port) {
|
|
931
958
|
return `http://127.0.0.1:${port}/health`;
|
|
932
959
|
}
|
|
933
|
-
var HOME_ENV = "LIANROUTER_HOME", APP_DIR_NAME = "LianRouter", LOGS_DIR = "logs", CACHE_DIR = "cache", RUN_DIR = "run", UPDATE_CACHE_DIR = "updates", LOG_FILE_NAME = "lianrouter.log", PID_FILE_NAME = "lianrouter.pid", CONTROL_FILE_NAME = "control.json", TRAY_PID_FILE_NAME = "tray.pid", DEFAULT_PORT = 12800;
|
|
960
|
+
var HOME_ENV = "LIANROUTER_HOME", APP_DIR_NAME = "LianRouter", LOGS_DIR = "logs", CACHE_DIR = "cache", RUN_DIR = "run", UPDATE_CACHE_DIR = "updates", CONFIG_FILE_NAME = ".env", LOG_FILE_NAME = "lianrouter.log", PID_FILE_NAME = "lianrouter.pid", CONTROL_FILE_NAME = "control.json", TRAY_PID_FILE_NAME = "tray.pid", DEFAULT_PORT = 12800;
|
|
934
961
|
var init_paths = () => {};
|
|
935
962
|
|
|
936
963
|
// cli/tui/terminal.ts
|
|
@@ -1557,7 +1584,7 @@ var init_app = __esm(async () => {
|
|
|
1557
1584
|
|
|
1558
1585
|
// cli/src/launcher.ts
|
|
1559
1586
|
init_version();
|
|
1560
|
-
import { existsSync as
|
|
1587
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1561
1588
|
import { join as join8 } from "path";
|
|
1562
1589
|
|
|
1563
1590
|
// cli/src/bootstrap.ts
|
|
@@ -1569,7 +1596,7 @@ init_install();
|
|
|
1569
1596
|
init_version_file();
|
|
1570
1597
|
init_paths();
|
|
1571
1598
|
import { statSync } from "fs";
|
|
1572
|
-
import { mkdir as mkdir3, mkdtemp as mkdtemp2, readdir as
|
|
1599
|
+
import { mkdir as mkdir3, mkdtemp as mkdtemp2, readdir as readdir4, rm as rm5 } from "fs/promises";
|
|
1573
1600
|
import { tmpdir as tmpdir2 } from "os";
|
|
1574
1601
|
import { join as join6 } from "path";
|
|
1575
1602
|
var SLICE2 = {
|
|
@@ -1598,7 +1625,7 @@ function withinSlice2(start, end, percent) {
|
|
|
1598
1625
|
return start + (end - start) * clamped / 100;
|
|
1599
1626
|
}
|
|
1600
1627
|
async function payloadEntries2(stagedDir) {
|
|
1601
|
-
const entries = await
|
|
1628
|
+
const entries = await readdir4(stagedDir, { withFileTypes: true });
|
|
1602
1629
|
return entries.map((entry) => entry.name);
|
|
1603
1630
|
}
|
|
1604
1631
|
async function ensureGatewayInstalled(options) {
|
|
@@ -1987,7 +2014,7 @@ function buildMenuItems(input) {
|
|
|
1987
2014
|
if (input.update !== undefined) {
|
|
1988
2015
|
items.push({
|
|
1989
2016
|
action: "update",
|
|
1990
|
-
label: `Update to v${input.update.latest} (current: v${input.
|
|
2017
|
+
label: `Update to v${input.update.latest} (current: v${input.update.current})`
|
|
1991
2018
|
});
|
|
1992
2019
|
}
|
|
1993
2020
|
items.push({ action: "web", label: "Web UI (Open in Browser)" }, { action: "tui", label: "Terminal UI (Interactive CLI)" }, { action: "tray", label: "Hide to Tray (Background)" }, { action: "exit", label: "Exit" });
|
|
@@ -2604,6 +2631,134 @@ class GatewaySupervisor {
|
|
|
2604
2631
|
}
|
|
2605
2632
|
}
|
|
2606
2633
|
|
|
2634
|
+
// cli/src/install-config.ts
|
|
2635
|
+
init_paths();
|
|
2636
|
+
import { randomBytes } from "crypto";
|
|
2637
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
2638
|
+
var ALWAYS_REQUIRED = ["DATABASE_URL", "LIANROUTER_ENCRYPTION_KEY"];
|
|
2639
|
+
function parseEnvFile(text) {
|
|
2640
|
+
const values = {};
|
|
2641
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
2642
|
+
const line = rawLine.trim();
|
|
2643
|
+
if (line === "" || line.startsWith("#")) {
|
|
2644
|
+
continue;
|
|
2645
|
+
}
|
|
2646
|
+
const separator = line.indexOf("=");
|
|
2647
|
+
if (separator <= 0) {
|
|
2648
|
+
continue;
|
|
2649
|
+
}
|
|
2650
|
+
const key = line.slice(0, separator).trim();
|
|
2651
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
2652
|
+
continue;
|
|
2653
|
+
}
|
|
2654
|
+
let value = line.slice(separator + 1).trim();
|
|
2655
|
+
const quote = value[0];
|
|
2656
|
+
if (quote === '"' || quote === "'") {
|
|
2657
|
+
if (value.length >= 2 && value.endsWith(quote)) {
|
|
2658
|
+
value = value.slice(1, -1);
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
values[key] = value;
|
|
2662
|
+
}
|
|
2663
|
+
return values;
|
|
2664
|
+
}
|
|
2665
|
+
function resolveGatewayConfig(installRoot, shellEnv = process.env) {
|
|
2666
|
+
const path = resolveConfigFile(installRoot);
|
|
2667
|
+
const present = existsSync2(path);
|
|
2668
|
+
const fileValues = present ? parseEnvFile(readFileSync2(path, "utf8")) : {};
|
|
2669
|
+
const env = {};
|
|
2670
|
+
for (const [key, value] of Object.entries(fileValues)) {
|
|
2671
|
+
if (shellEnv[key] !== undefined && shellEnv[key].trim() !== "") {
|
|
2672
|
+
continue;
|
|
2673
|
+
}
|
|
2674
|
+
if (value.trim() === "") {
|
|
2675
|
+
continue;
|
|
2676
|
+
}
|
|
2677
|
+
env[key] = value;
|
|
2678
|
+
}
|
|
2679
|
+
const effective = (name) => {
|
|
2680
|
+
const fromShell = shellEnv[name];
|
|
2681
|
+
if (fromShell !== undefined && fromShell.trim() !== "") {
|
|
2682
|
+
return fromShell.trim();
|
|
2683
|
+
}
|
|
2684
|
+
const fromFile = fileValues[name];
|
|
2685
|
+
return fromFile !== undefined && fromFile.trim() !== "" ? fromFile.trim() : undefined;
|
|
2686
|
+
};
|
|
2687
|
+
const required = [...ALWAYS_REQUIRED];
|
|
2688
|
+
if ((effective("REDIS_MODE") ?? "normal") === "normal") {
|
|
2689
|
+
required.push("REDIS_URL");
|
|
2690
|
+
}
|
|
2691
|
+
const missing = required.filter((name) => effective(name) === undefined);
|
|
2692
|
+
return { path, present, env, missing };
|
|
2693
|
+
}
|
|
2694
|
+
function describeMissingConfig(config) {
|
|
2695
|
+
const location = config.present ? ` config file: ${config.path}` : ` config file: ${config.path} (not found)`;
|
|
2696
|
+
const examples = {
|
|
2697
|
+
DATABASE_URL: "postgres://user:password@localhost:5432/lianrouter",
|
|
2698
|
+
LIANROUTER_ENCRYPTION_KEY: "<base64 or 64-character hex that decodes to exactly 32 bytes>",
|
|
2699
|
+
REDIS_URL: "redis://localhost:6379"
|
|
2700
|
+
};
|
|
2701
|
+
const lines = [
|
|
2702
|
+
"the gateway is not configured, so it cannot start",
|
|
2703
|
+
location,
|
|
2704
|
+
` missing: ${config.missing.join(", ")}`,
|
|
2705
|
+
"",
|
|
2706
|
+
"add these lines to that file:",
|
|
2707
|
+
...config.missing.map((name) => ` ${name}=${examples[name] ?? "<value>"}`),
|
|
2708
|
+
"",
|
|
2709
|
+
"or set them in your shell before starting; a shell value wins over the file.",
|
|
2710
|
+
`run \`lianrouter init\` to write a starter file at ${config.path}`
|
|
2711
|
+
];
|
|
2712
|
+
if (config.missing.includes("REDIS_URL")) {
|
|
2713
|
+
lines.push("to run a single gateway process without Redis, set REDIS_MODE=single_instance_local instead of REDIS_URL");
|
|
2714
|
+
}
|
|
2715
|
+
return lines.join(`
|
|
2716
|
+
`);
|
|
2717
|
+
}
|
|
2718
|
+
function assertGatewayConfigured(config) {
|
|
2719
|
+
if (config.missing.length > 0) {
|
|
2720
|
+
throw new Error(describeMissingConfig(config));
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
function starterConfigText(encryptionKey) {
|
|
2724
|
+
return `# LianRouter gateway configuration.
|
|
2725
|
+
# The launcher reads this file and passes its values to the gateway process.
|
|
2726
|
+
# A variable already set in your shell wins over the value written here.
|
|
2727
|
+
# Generated by \`lianrouter init\`.
|
|
2728
|
+
|
|
2729
|
+
# PostgreSQL connection string. Required.
|
|
2730
|
+
# Replace the placeholder below and remove the leading "# ". The gateway never
|
|
2731
|
+
# infers a Docker or Laragon connection.
|
|
2732
|
+
# DATABASE_URL=postgres://user:password@localhost:5432/lianrouter
|
|
2733
|
+
|
|
2734
|
+
# 256-bit key for encrypting provider credentials and hashing API keys.
|
|
2735
|
+
# Required. Base64 (44 characters) or hex (64 characters); it must decode to
|
|
2736
|
+
# exactly 32 bytes. Keep it secret and keep it stable: a new key cannot decrypt
|
|
2737
|
+
# credentials encrypted with the old one.
|
|
2738
|
+
LIANROUTER_ENCRYPTION_KEY=${encryptionKey}
|
|
2739
|
+
|
|
2740
|
+
# Redis coordination. REDIS_URL is required in the default mode; set
|
|
2741
|
+
# REDIS_MODE=single_instance_local to run a single gateway process without
|
|
2742
|
+
# Redis at all.
|
|
2743
|
+
REDIS_MODE=normal
|
|
2744
|
+
# REDIS_URL=redis://localhost:6379
|
|
2745
|
+
`;
|
|
2746
|
+
}
|
|
2747
|
+
function writeStarterConfig(installRoot) {
|
|
2748
|
+
const path = resolveConfigFile(installRoot);
|
|
2749
|
+
mkdirSync2(installRoot, { recursive: true });
|
|
2750
|
+
const encryptionKey = randomBytes(32).toString("base64");
|
|
2751
|
+
try {
|
|
2752
|
+
writeFileSync(path, starterConfigText(encryptionKey), { encoding: "utf8", flag: "wx" });
|
|
2753
|
+
} catch (error) {
|
|
2754
|
+
if (error.code === "EEXIST") {
|
|
2755
|
+
throw new Error(`refusing to overwrite the existing config file at ${path}`);
|
|
2756
|
+
}
|
|
2757
|
+
throw error;
|
|
2758
|
+
}
|
|
2759
|
+
return path;
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2607
2762
|
// cli/src/update-flow.ts
|
|
2608
2763
|
init_version_file();
|
|
2609
2764
|
async function resolveGatewayVersion(installRoot, launcherVersion) {
|
|
@@ -2667,11 +2822,11 @@ async function runUpdateSequence(deps) {
|
|
|
2667
2822
|
|
|
2668
2823
|
// cli/src/tray-launcher.ts
|
|
2669
2824
|
init_paths();
|
|
2670
|
-
import { existsSync as
|
|
2825
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2671
2826
|
import { readFile as readFile2, rm as rm8, writeFile as writeFile3 } from "fs/promises";
|
|
2672
2827
|
import { join as join7 } from "path";
|
|
2673
2828
|
function resolveTrayEntry(options) {
|
|
2674
|
-
return trayEntryCandidates(options).find((candidate) =>
|
|
2829
|
+
return trayEntryCandidates(options).find((candidate) => existsSync3(candidate));
|
|
2675
2830
|
}
|
|
2676
2831
|
function trayEntryCandidates(options) {
|
|
2677
2832
|
const bundleDir = options.bundleDir ?? import.meta.dir;
|
|
@@ -2805,6 +2960,7 @@ Commands:
|
|
|
2805
2960
|
update Check for and install an update
|
|
2806
2961
|
tray Run the gateway in the background with a tray icon
|
|
2807
2962
|
tui Open the terminal UI
|
|
2963
|
+
init Write a starter config file into the install root
|
|
2808
2964
|
|
|
2809
2965
|
Options:
|
|
2810
2966
|
--port <n> Gateway port (default ${DEFAULT_PORT}, or $PORT)
|
|
@@ -2818,7 +2974,15 @@ Options:
|
|
|
2818
2974
|
Environment:
|
|
2819
2975
|
LIANROUTER_HOME Override the install/state root
|
|
2820
2976
|
PORT Default gateway port`;
|
|
2821
|
-
var KNOWN_COMMANDS = [
|
|
2977
|
+
var KNOWN_COMMANDS = [
|
|
2978
|
+
"start",
|
|
2979
|
+
"stop",
|
|
2980
|
+
"status",
|
|
2981
|
+
"update",
|
|
2982
|
+
"tray",
|
|
2983
|
+
"tui",
|
|
2984
|
+
"init"
|
|
2985
|
+
];
|
|
2822
2986
|
function parseArgs(argv) {
|
|
2823
2987
|
let port;
|
|
2824
2988
|
let host = "localhost";
|
|
@@ -2906,7 +3070,7 @@ function readPortEnv() {
|
|
|
2906
3070
|
}
|
|
2907
3071
|
function resolveRuntime() {
|
|
2908
3072
|
const repoRoot = resolveDevRepoRoot();
|
|
2909
|
-
if (repoRoot !== undefined &&
|
|
3073
|
+
if (repoRoot !== undefined && existsSync4(join8(repoRoot, "src", "app.ts"))) {
|
|
2910
3074
|
return {
|
|
2911
3075
|
installRoot: resolveInstallRoot(),
|
|
2912
3076
|
cwd: repoRoot,
|
|
@@ -2918,7 +3082,7 @@ function resolveRuntime() {
|
|
|
2918
3082
|
return { installRoot, cwd: installRoot, command: undefined, devRepoRoot: undefined };
|
|
2919
3083
|
}
|
|
2920
3084
|
async function ensureInstalledGateway(installRoot) {
|
|
2921
|
-
const present =
|
|
3085
|
+
const present = existsSync4(resolveBinaryPath(installRoot));
|
|
2922
3086
|
if (present) {
|
|
2923
3087
|
await ensureGatewayInstalled({ installRoot, currentVersion: CLI_VERSION });
|
|
2924
3088
|
return;
|
|
@@ -2952,6 +3116,17 @@ async function run(argv) {
|
|
|
2952
3116
|
return 0;
|
|
2953
3117
|
}
|
|
2954
3118
|
const runtime = resolveRuntime();
|
|
3119
|
+
if (options.command === "init") {
|
|
3120
|
+
const path = writeStarterConfig(runtime.installRoot);
|
|
3121
|
+
console.log(`Wrote ${path}`);
|
|
3122
|
+
console.log("Set DATABASE_URL in that file (uncomment the line), then run lianrouter.");
|
|
3123
|
+
return 0;
|
|
3124
|
+
}
|
|
3125
|
+
const startsGateway = options.command === undefined || options.command === "start" || options.command === "tray" || options.command === "tui";
|
|
3126
|
+
const gatewayConfig = runtime.command === undefined && startsGateway ? resolveGatewayConfig(runtime.installRoot) : undefined;
|
|
3127
|
+
if (gatewayConfig !== undefined) {
|
|
3128
|
+
assertGatewayConfigured(gatewayConfig);
|
|
3129
|
+
}
|
|
2955
3130
|
if (runtime.command === undefined && options.command !== "status" && options.command !== "stop") {
|
|
2956
3131
|
await ensureInstalledGateway(runtime.installRoot);
|
|
2957
3132
|
}
|
|
@@ -2960,7 +3135,10 @@ async function run(argv) {
|
|
|
2960
3135
|
installRoot: runtime.installRoot,
|
|
2961
3136
|
logFile: resolveLogFile(runtime.installRoot),
|
|
2962
3137
|
cwd: runtime.cwd,
|
|
2963
|
-
env: {
|
|
3138
|
+
env: {
|
|
3139
|
+
LIANROUTER_LAUNCHER_HOME: runtime.installRoot,
|
|
3140
|
+
...gatewayConfig?.env ?? {}
|
|
3141
|
+
},
|
|
2964
3142
|
...runtime.command === undefined ? {} : { command: runtime.command }
|
|
2965
3143
|
});
|
|
2966
3144
|
switch (options.command) {
|
|
@@ -3117,7 +3295,7 @@ async function runInteractive(supervisor, options, runtime) {
|
|
|
3117
3295
|
const action = await promptMenu({
|
|
3118
3296
|
version: CLI_VERSION,
|
|
3119
3297
|
port: supervisor.status.port,
|
|
3120
|
-
update: update !== null && update.available ? { latest: update.latest } : undefined
|
|
3298
|
+
update: update !== null && update.available ? { latest: update.latest, current: update.current } : undefined
|
|
3121
3299
|
});
|
|
3122
3300
|
return await dispatch(action, supervisor, session, options, runtime);
|
|
3123
3301
|
}
|
package/package.json
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "lianrouter",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "LianRouter launcher: install, run and control the gateway from one command",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"lianrouter": "./dist/cli.js"
|
|
8
|
-
},
|
|
9
|
-
"engines": {
|
|
10
|
-
"bun": ">=1.4.2"
|
|
11
|
-
},
|
|
12
|
-
"files": [
|
|
13
|
-
"dist",
|
|
14
|
-
"README.md"
|
|
15
|
-
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"build": "bun run ../scripts/build-cli.ts",
|
|
18
|
-
"typecheck": "tsc --noEmit -p .",
|
|
19
|
-
"postinstall": "echo lianrouter: the gateway binary installs on first run, not during this install",
|
|
20
|
-
"prepublishOnly": "bun run build"
|
|
21
|
-
},
|
|
22
|
-
"repository": {
|
|
23
|
-
"type": "git",
|
|
24
|
-
"url": "git+https://github.com/ReXooGen/Lian-Router.git",
|
|
25
|
-
"directory": "cli"
|
|
26
|
-
},
|
|
27
|
-
"bugs": {
|
|
28
|
-
"url": "https://github.com/ReXooGen/Lian-Router/issues"
|
|
29
|
-
},
|
|
30
|
-
"homepage": "https://github.com/ReXooGen/Lian-Router#readme",
|
|
31
|
-
"publishConfig": {
|
|
32
|
-
"access": "public"
|
|
33
|
-
},
|
|
34
|
-
"keywords": [
|
|
35
|
-
"lianrouter",
|
|
36
|
-
"ai-gateway",
|
|
37
|
-
"openai-compatible",
|
|
38
|
-
"llm-router",
|
|
39
|
-
"self-hosted",
|
|
40
|
-
"cli",
|
|
41
|
-
"launcher"
|
|
42
|
-
]
|
|
43
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "lianrouter",
|
|
3
|
+
"version": "2.2.1",
|
|
4
|
+
"description": "LianRouter launcher: install, run and control the gateway from one command",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"lianrouter": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"bun": ">=1.4.2"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "bun run ../scripts/build-cli.ts",
|
|
18
|
+
"typecheck": "tsc --noEmit -p .",
|
|
19
|
+
"postinstall": "echo lianrouter: the gateway binary installs on first run, not during this install",
|
|
20
|
+
"prepublishOnly": "bun run build"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/ReXooGen/Lian-Router.git",
|
|
25
|
+
"directory": "cli"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/ReXooGen/Lian-Router/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/ReXooGen/Lian-Router#readme",
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"lianrouter",
|
|
36
|
+
"ai-gateway",
|
|
37
|
+
"openai-compatible",
|
|
38
|
+
"llm-router",
|
|
39
|
+
"self-hosted",
|
|
40
|
+
"cli",
|
|
41
|
+
"launcher"
|
|
42
|
+
]
|
|
43
|
+
}
|