@lacrous/omnicloud 0.2.5 → 0.2.6

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 CHANGED
@@ -13,30 +13,36 @@ var pkg = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
13
13
  var USAGE = `omnicloud ${pkg.version}
14
14
 
15
15
  Usage:
16
- omnicloud start [--migrate] [--env <file>] Run the OmniCloud server
16
+ omnicloud Start OmniCloud and open it in your browser
17
+ omnicloud start [--no-open] [--env <file>] Start the server (opens the browser unless --no-open)
17
18
  omnicloud migrate [--env <file>] Apply database migrations
18
19
  omnicloud version Print the version
19
20
  omnicloud help Show this message
20
21
 
21
- Configuration is read from environment variables, then from a .env file in the
22
- current directory (or the file given with --env). Variables already set in the
23
- environment are never overwritten. See https://github.com/Lacrous/OmniCloud#configuration.
22
+ Migrations run automatically before the server starts. Configuration is read from
23
+ environment variables, then from a .env file in the current directory (or the file
24
+ given with --env). Variables already set in the environment are never overwritten.
25
+ See https://github.com/Lacrous/OmniCloud#configuration.
24
26
  `;
25
27
  function parseArgs(argv) {
26
- const [command = "help", ...rest] = argv;
28
+ const [first, ...rest] = argv;
29
+ const command = first === void 0 || first.startsWith("-") ? "start" : first;
30
+ const options = first === void 0 || first.startsWith("-") ? argv : rest;
27
31
  let migrate2 = false;
28
32
  let envFile = null;
29
- for (let i = 0; i < rest.length; i++) {
30
- const arg = rest[i];
33
+ let open = true;
34
+ for (let i = 0; i < options.length; i++) {
35
+ const arg = options[i];
31
36
  if (arg === "--migrate") migrate2 = true;
37
+ else if (arg === "--no-open") open = false;
32
38
  else if (arg === "--env") {
33
- const value = rest[++i];
39
+ const value = options[++i];
34
40
  if (!value) throw new Error("--env requires a file path");
35
41
  envFile = value;
36
42
  } else if (arg?.startsWith("--env=")) envFile = arg.slice("--env=".length);
37
43
  else throw new Error(`Unknown option: ${arg}`);
38
44
  }
39
- return { command, migrate: migrate2, envFile };
45
+ return { command, migrate: migrate2, envFile, open };
40
46
  }
41
47
  function parseEnvFile(content) {
42
48
  const values = {};
@@ -90,16 +96,72 @@ async function generate(env) {
90
96
  const code = await run(process.execPath, [prismaCli(), "generate", "--schema", schemaPath], env);
91
97
  if (code !== 0) throw new Error(`Prisma client generation failed (exit ${code}).`);
92
98
  }
99
+ function openUrl(url) {
100
+ const opener = process.platform === "darwin" ? { command: "open", args: [url] } : process.platform === "win32" ? { command: "cmd", args: ["/c", "start", "", url] } : { command: "xdg-open", args: [url] };
101
+ const child = spawn(opener.command, opener.args, { stdio: "ignore", detached: true });
102
+ child.on("error", () => {
103
+ process.stdout.write(`Open ${url} in your browser.
104
+ `);
105
+ });
106
+ child.unref();
107
+ }
108
+ async function waitForServer(url, timeoutMs) {
109
+ const deadline = Date.now() + timeoutMs;
110
+ while (Date.now() < deadline) {
111
+ try {
112
+ const response = await fetch(url);
113
+ if (response.ok) return true;
114
+ } catch {
115
+ }
116
+ await new Promise((done) => setTimeout(done, 250));
117
+ }
118
+ return false;
119
+ }
120
+ function localUrl(env) {
121
+ const port = env.PORT && env.PORT.trim() !== "" ? env.PORT.trim() : "4000";
122
+ const host = env.HOST && env.HOST.trim() !== "" && env.HOST.trim() !== "0.0.0.0" ? env.HOST.trim() : "127.0.0.1";
123
+ return `http://${host}:${port}`;
124
+ }
93
125
  async function start(args, env) {
94
126
  if (!existsSync(join(serverDir, "index.js"))) {
95
127
  throw new Error("The server bundle is missing. Reinstall @lacrous/omnicloud.");
96
128
  }
97
129
  await generate(env);
98
- if (args.migrate) await migrate(env);
130
+ await migrate(env);
99
131
  env.WEB_DIST_DIR ??= join(serverDir, "web");
100
132
  env.NODE_ENV ??= "production";
101
- const code = await run(process.execPath, [join(serverDir, "index.js")], env);
102
- if (code !== 0) throw new Error(`Server exited with code ${code}.`);
133
+ const url = localUrl(env);
134
+ const server = spawn(process.execPath, [join(serverDir, "index.js")], { stdio: "inherit", env });
135
+ let exited = false;
136
+ server.on("exit", () => {
137
+ exited = true;
138
+ });
139
+ const forward = (signal) => () => {
140
+ if (!exited) server.kill(signal);
141
+ };
142
+ process.on("SIGINT", forward("SIGINT"));
143
+ process.on("SIGTERM", forward("SIGTERM"));
144
+ if (args.open) {
145
+ const ready = await waitForServer(`${url}/api/health`, 6e4);
146
+ if (ready) {
147
+ process.stdout.write(`
148
+ OmniCloud is running at ${url}
149
+ `);
150
+ openUrl(url);
151
+ } else if (!exited) {
152
+ process.stdout.write(`
153
+ OmniCloud did not answer at ${url} yet. Check the log above.
154
+ `);
155
+ }
156
+ }
157
+ await new Promise((resolveExit, rejectExit) => {
158
+ server.on("exit", (code, signal) => {
159
+ if (signal) return resolveExit();
160
+ if (code === 0 || code === null) return resolveExit();
161
+ rejectExit(new Error(`Server exited with code ${code}.`));
162
+ });
163
+ server.on("error", rejectExit);
164
+ });
103
165
  }
104
166
  async function main(argv, env = process.env) {
105
167
  let args;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lacrous/omnicloud",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "SDK and core building blocks for OmniCloud — self-hosted cloud storage powered by your Telegram account.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -48,9 +48,9 @@
48
48
  "prisma": "^6.2.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@omnicloud/core": "0.2.5",
52
- "@omnicloud/shared": "0.2.5",
53
- "@omnicloud/telegram": "0.2.5",
51
+ "@omnicloud/core": "0.2.6",
52
+ "@omnicloud/shared": "0.2.6",
53
+ "@omnicloud/telegram": "0.2.6",
54
54
  "@types/node": "^22.10.0",
55
55
  "esbuild": "0.25.12",
56
56
  "tsup": "^8.3.0",
package/server/index.js CHANGED
@@ -4685,7 +4685,7 @@ function encryptionCheck(configured) {
4685
4685
  }
4686
4686
 
4687
4687
  // ../../apps/api/src/routes/storage.ts
4688
- var VERSION = "0.2.5";
4688
+ var VERSION = "0.2.6";
4689
4689
  function registerStorageRoutes(app2, container2) {
4690
4690
  app2.get("/api/health", async () => {
4691
4691
  const database = await probeDatabase(container2);