@humbdb/humb 0.0.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/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +18 -0
- package/dist/bin.js.map +1 -0
- package/dist/chunk-2ERJS5IY.js +83 -0
- package/dist/chunk-2ERJS5IY.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/web/assets/index-CENj019G.js +229 -0
- package/dist/web/assets/index-CENj019G.js.map +1 -0
- package/dist/web/assets/index-DxztNmnp.css +1 -0
- package/dist/web/index.html +58 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Humb contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# humb
|
|
2
|
+
|
|
3
|
+
The `humb` CLI launches a local-first database management UI from your terminal.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx humb postgres://user:pass@localhost:5432/mydb
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
It parses the target, starts the local server, opens your browser, and shuts down cleanly on
|
|
10
|
+
`Ctrl+C`. Supports PostgreSQL first, with more engines planned. See
|
|
11
|
+
[`docs/product-specs/connect-and-inspect-postgres.md`](../../docs/product-specs/connect-and-inspect-postgres.md).
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
main
|
|
4
|
+
} from "./chunk-2ERJS5IY.js";
|
|
5
|
+
|
|
6
|
+
// src/bin.ts
|
|
7
|
+
import { InvalidConnectionTargetError } from "@humbdb/core";
|
|
8
|
+
main().catch((error) => {
|
|
9
|
+
if (error instanceof InvalidConnectionTargetError) {
|
|
10
|
+
process.stderr.write(`${error.message}
|
|
11
|
+
`);
|
|
12
|
+
} else {
|
|
13
|
+
process.stderr.write(`Humb failed to start: ${error.message}
|
|
14
|
+
`);
|
|
15
|
+
}
|
|
16
|
+
process.exit(1);
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { InvalidConnectionTargetError } from \"@humbdb/core\";\nimport { main } from \"./index.js\";\n\nmain().catch((error: unknown) => {\n if (error instanceof InvalidConnectionTargetError) {\n process.stderr.write(`${error.message}\\n`);\n } else {\n process.stderr.write(`Humb failed to start: ${(error as Error).message}\\n`);\n }\n process.exit(1);\n});\n"],"mappings":";;;;;;AACA,SAAS,oCAAoC;AAG7C,KAAK,EAAE,MAAM,CAAC,UAAmB;AAC/B,MAAI,iBAAiB,8BAA8B;AACjD,YAAQ,OAAO,MAAM,GAAG,MAAM,OAAO;AAAA,CAAI;AAAA,EAC3C,OAAO;AACL,YAAQ,OAAO,MAAM,yBAA0B,MAAgB,OAAO;AAAA,CAAI;AAAA,EAC5E;AACA,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { existsSync, statSync } from "fs";
|
|
3
|
+
import { dirname, join, resolve } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { parseConnectionTarget } from "@humbdb/core";
|
|
6
|
+
import { resolveAdapter } from "@humbdb/driver-contract";
|
|
7
|
+
import { postgresAdapterFactory } from "@humbdb/postgres";
|
|
8
|
+
import { startServer } from "@humbdb/server";
|
|
9
|
+
import { sqliteAdapterFactory } from "@humbdb/sqlite";
|
|
10
|
+
import { Command } from "commander";
|
|
11
|
+
import open from "open";
|
|
12
|
+
function defaultWebRoot(here) {
|
|
13
|
+
const bundled = resolve(here, "web");
|
|
14
|
+
if (existsSync(join(bundled, "index.html"))) {
|
|
15
|
+
return bundled;
|
|
16
|
+
}
|
|
17
|
+
return resolve(here, "../../../apps/web/dist");
|
|
18
|
+
}
|
|
19
|
+
function parseArgs(argv) {
|
|
20
|
+
const program = new Command();
|
|
21
|
+
program.name("humb").description("Launch a local-first database management UI from your terminal.").argument(
|
|
22
|
+
"[target]",
|
|
23
|
+
"database connection string (postgres://user:pass@host:5432/db) or a path to a SQLite file (./app.db)"
|
|
24
|
+
).option("-p, --port <port>", "port for the local server", (value) => parseInt(value, 10)).option(
|
|
25
|
+
"--files-dir <dir>",
|
|
26
|
+
"directory the Files tab may read *.sql files from (opt-in; disabled by default)"
|
|
27
|
+
).allowExcessArguments(false).exitOverride();
|
|
28
|
+
program.parse(argv, { from: "user" });
|
|
29
|
+
const opts = program.opts();
|
|
30
|
+
return { target: program.args[0], port: opts.port, filesDir: opts.filesDir };
|
|
31
|
+
}
|
|
32
|
+
function resolvePort(flagPort, env) {
|
|
33
|
+
if (flagPort !== void 0) {
|
|
34
|
+
return flagPort;
|
|
35
|
+
}
|
|
36
|
+
const envPort = env.HUMB_PORT?.trim();
|
|
37
|
+
if (!envPort) {
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
const parsed = Number.parseInt(envPort, 10);
|
|
41
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
42
|
+
}
|
|
43
|
+
function resolveFilesRoot(filesDir, cwd) {
|
|
44
|
+
return filesDir ? resolve(cwd, filesDir) : void 0;
|
|
45
|
+
}
|
|
46
|
+
async function main(argv = process.argv.slice(2)) {
|
|
47
|
+
const args = parseArgs(argv);
|
|
48
|
+
const target = parseConnectionTarget(args.target);
|
|
49
|
+
const adapter = resolveAdapter([postgresAdapterFactory, sqliteAdapterFactory], target);
|
|
50
|
+
await adapter.connect();
|
|
51
|
+
const filesRoot = resolveFilesRoot(args.filesDir, process.cwd());
|
|
52
|
+
if (filesRoot && (!existsSync(filesRoot) || !statSync(filesRoot).isDirectory())) {
|
|
53
|
+
throw new Error(`--files-dir "${filesRoot}" does not exist or is not a directory.`);
|
|
54
|
+
}
|
|
55
|
+
const port = resolvePort(args.port, process.env);
|
|
56
|
+
const server = await startServer({
|
|
57
|
+
adapter,
|
|
58
|
+
target,
|
|
59
|
+
port,
|
|
60
|
+
logger: true,
|
|
61
|
+
webRoot: defaultWebRoot(dirname(fileURLToPath(import.meta.url))),
|
|
62
|
+
filesRoot
|
|
63
|
+
});
|
|
64
|
+
process.stdout.write(`Humb is running at ${server.url}
|
|
65
|
+
`);
|
|
66
|
+
await open(server.url);
|
|
67
|
+
const shutdown = async () => {
|
|
68
|
+
await server.close();
|
|
69
|
+
await adapter.disconnect();
|
|
70
|
+
process.exit(0);
|
|
71
|
+
};
|
|
72
|
+
process.on("SIGINT", shutdown);
|
|
73
|
+
process.on("SIGTERM", shutdown);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export {
|
|
77
|
+
defaultWebRoot,
|
|
78
|
+
parseArgs,
|
|
79
|
+
resolvePort,
|
|
80
|
+
resolveFilesRoot,
|
|
81
|
+
main
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=chunk-2ERJS5IY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * The `humb` CLI: parse a database target, start the local server, and open the browser.\n */\nimport { existsSync, statSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseConnectionTarget } from \"@humbdb/core\";\nimport { resolveAdapter } from \"@humbdb/driver-contract\";\nimport { postgresAdapterFactory } from \"@humbdb/postgres\";\nimport { startServer } from \"@humbdb/server\";\nimport { sqliteAdapterFactory } from \"@humbdb/sqlite\";\nimport { Command } from \"commander\";\nimport open from \"open\";\n\n/**\n * Where the built `apps/web` static assets live, relative to this file's own directory (`here` -\n * `dist` when built, `src` in dev/test). Two candidates, tried in order:\n *\n * 1. `<here>/web`, bundled alongside this file by `tsup.config.ts`'s `onSuccess` hook and shipped\n * inside the published `humb` npm package (see `files` in `package.json`) - this is what\n * resolves once installed standalone outside this monorepo (F010).\n * 2. `<here>/../../../apps/web/dist`, monorepo-relative - what resolves in local dev/test, where\n * the bundled copy was never created.\n *\n * `startServer` no-ops static serving if neither path contains a build, so this is safe even\n * before `apps/web` is built at all.\n */\nexport function defaultWebRoot(here: string): string {\n const bundled = resolve(here, \"web\");\n if (existsSync(join(bundled, \"index.html\"))) {\n return bundled;\n }\n return resolve(here, \"../../../apps/web/dist\");\n}\n\nexport interface CliArgs {\n target: string | undefined;\n port: number | undefined;\n filesDir: string | undefined;\n}\n\n/** Parse CLI arguments. Throws (via commander) on malformed flags. */\nexport function parseArgs(argv: string[]): CliArgs {\n const program = new Command();\n program\n .name(\"humb\")\n .description(\"Launch a local-first database management UI from your terminal.\")\n .argument(\n \"[target]\",\n \"database connection string (postgres://user:pass@host:5432/db) or a path to a SQLite file (./app.db)\"\n )\n .option(\"-p, --port <port>\", \"port for the local server\", (value) => parseInt(value, 10))\n .option(\n \"--files-dir <dir>\",\n \"directory the Files tab may read *.sql files from (opt-in; disabled by default)\"\n )\n .allowExcessArguments(false)\n .exitOverride();\n\n program.parse(argv, { from: \"user\" });\n const opts = program.opts<{ port?: number; filesDir?: string }>();\n return { target: program.args[0], port: opts.port, filesDir: opts.filesDir };\n}\n\n/** Resolve the port to listen on: `--port` flag, then `HUMB_PORT` env var, then the server default. */\nexport function resolvePort(\n flagPort: number | undefined,\n env: NodeJS.ProcessEnv\n): number | undefined {\n if (flagPort !== undefined) {\n return flagPort;\n }\n const envPort = env.HUMB_PORT?.trim();\n if (!envPort) {\n return undefined;\n }\n const parsed = Number.parseInt(envPort, 10);\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n\n/** Resolves the `--files-dir` flag to an absolute path. Undefined means file browsing is disabled. */\nexport function resolveFilesRoot(filesDir: string | undefined, cwd: string): string | undefined {\n return filesDir ? resolve(cwd, filesDir) : undefined;\n}\n\n/** Run the CLI. Returns the running server's URL. */\nexport async function main(argv: string[] = process.argv.slice(2)): Promise<void> {\n const args = parseArgs(argv);\n\n const target = parseConnectionTarget(args.target);\n const adapter = resolveAdapter([postgresAdapterFactory, sqliteAdapterFactory], target);\n await adapter.connect();\n\n const filesRoot = resolveFilesRoot(args.filesDir, process.cwd());\n if (filesRoot && (!existsSync(filesRoot) || !statSync(filesRoot).isDirectory())) {\n throw new Error(`--files-dir \"${filesRoot}\" does not exist or is not a directory.`);\n }\n\n const port = resolvePort(args.port, process.env);\n const server = await startServer({\n adapter,\n target,\n port,\n logger: true,\n webRoot: defaultWebRoot(dirname(fileURLToPath(import.meta.url))),\n filesRoot\n });\n process.stdout.write(`Humb is running at ${server.url}\\n`);\n await open(server.url);\n\n const shutdown = async (): Promise<void> => {\n await server.close();\n await adapter.disconnect();\n process.exit(0);\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n}\n"],"mappings":";AAGA,SAAS,YAAY,gBAAgB;AACrC,SAAS,SAAS,MAAM,eAAe;AACvC,SAAS,qBAAqB;AAC9B,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAC/B,SAAS,8BAA8B;AACvC,SAAS,mBAAmB;AAC5B,SAAS,4BAA4B;AACrC,SAAS,eAAe;AACxB,OAAO,UAAU;AAeV,SAAS,eAAe,MAAsB;AACnD,QAAM,UAAU,QAAQ,MAAM,KAAK;AACnC,MAAI,WAAW,KAAK,SAAS,YAAY,CAAC,GAAG;AAC3C,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,MAAM,wBAAwB;AAC/C;AASO,SAAS,UAAU,MAAyB;AACjD,QAAM,UAAU,IAAI,QAAQ;AAC5B,UACG,KAAK,MAAM,EACX,YAAY,iEAAiE,EAC7E;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,qBAAqB,6BAA6B,CAAC,UAAU,SAAS,OAAO,EAAE,CAAC,EACvF;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,qBAAqB,KAAK,EAC1B,aAAa;AAEhB,UAAQ,MAAM,MAAM,EAAE,MAAM,OAAO,CAAC;AACpC,QAAM,OAAO,QAAQ,KAA2C;AAChE,SAAO,EAAE,QAAQ,QAAQ,KAAK,CAAC,GAAG,MAAM,KAAK,MAAM,UAAU,KAAK,SAAS;AAC7E;AAGO,SAAS,YACd,UACA,KACoB;AACpB,MAAI,aAAa,QAAW;AAC1B,WAAO;AAAA,EACT;AACA,QAAM,UAAU,IAAI,WAAW,KAAK;AACpC,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,QAAM,SAAS,OAAO,SAAS,SAAS,EAAE;AAC1C,SAAO,OAAO,MAAM,MAAM,IAAI,SAAY;AAC5C;AAGO,SAAS,iBAAiB,UAA8B,KAAiC;AAC9F,SAAO,WAAW,QAAQ,KAAK,QAAQ,IAAI;AAC7C;AAGA,eAAsB,KAAK,OAAiB,QAAQ,KAAK,MAAM,CAAC,GAAkB;AAChF,QAAM,OAAO,UAAU,IAAI;AAE3B,QAAM,SAAS,sBAAsB,KAAK,MAAM;AAChD,QAAM,UAAU,eAAe,CAAC,wBAAwB,oBAAoB,GAAG,MAAM;AACrF,QAAM,QAAQ,QAAQ;AAEtB,QAAM,YAAY,iBAAiB,KAAK,UAAU,QAAQ,IAAI,CAAC;AAC/D,MAAI,cAAc,CAAC,WAAW,SAAS,KAAK,CAAC,SAAS,SAAS,EAAE,YAAY,IAAI;AAC/E,UAAM,IAAI,MAAM,gBAAgB,SAAS,yCAAyC;AAAA,EACpF;AAEA,QAAM,OAAO,YAAY,KAAK,MAAM,QAAQ,GAAG;AAC/C,QAAM,SAAS,MAAM,YAAY;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,SAAS,eAAe,QAAQ,cAAc,YAAY,GAAG,CAAC,CAAC;AAAA,IAC/D;AAAA,EACF,CAAC;AACD,UAAQ,OAAO,MAAM,sBAAsB,OAAO,GAAG;AAAA,CAAI;AACzD,QAAM,KAAK,OAAO,GAAG;AAErB,QAAM,WAAW,YAA2B;AAC1C,UAAM,OAAO,MAAM;AACnB,UAAM,QAAQ,WAAW;AACzB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,GAAG,UAAU,QAAQ;AAC7B,UAAQ,GAAG,WAAW,QAAQ;AAChC;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the built `apps/web` static assets live, relative to this file's own directory (`here` -
|
|
3
|
+
* `dist` when built, `src` in dev/test). Two candidates, tried in order:
|
|
4
|
+
*
|
|
5
|
+
* 1. `<here>/web`, bundled alongside this file by `tsup.config.ts`'s `onSuccess` hook and shipped
|
|
6
|
+
* inside the published `humb` npm package (see `files` in `package.json`) - this is what
|
|
7
|
+
* resolves once installed standalone outside this monorepo (F010).
|
|
8
|
+
* 2. `<here>/../../../apps/web/dist`, monorepo-relative - what resolves in local dev/test, where
|
|
9
|
+
* the bundled copy was never created.
|
|
10
|
+
*
|
|
11
|
+
* `startServer` no-ops static serving if neither path contains a build, so this is safe even
|
|
12
|
+
* before `apps/web` is built at all.
|
|
13
|
+
*/
|
|
14
|
+
declare function defaultWebRoot(here: string): string;
|
|
15
|
+
interface CliArgs {
|
|
16
|
+
target: string | undefined;
|
|
17
|
+
port: number | undefined;
|
|
18
|
+
filesDir: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
/** Parse CLI arguments. Throws (via commander) on malformed flags. */
|
|
21
|
+
declare function parseArgs(argv: string[]): CliArgs;
|
|
22
|
+
/** Resolve the port to listen on: `--port` flag, then `HUMB_PORT` env var, then the server default. */
|
|
23
|
+
declare function resolvePort(flagPort: number | undefined, env: NodeJS.ProcessEnv): number | undefined;
|
|
24
|
+
/** Resolves the `--files-dir` flag to an absolute path. Undefined means file browsing is disabled. */
|
|
25
|
+
declare function resolveFilesRoot(filesDir: string | undefined, cwd: string): string | undefined;
|
|
26
|
+
/** Run the CLI. Returns the running server's URL. */
|
|
27
|
+
declare function main(argv?: string[]): Promise<void>;
|
|
28
|
+
|
|
29
|
+
export { type CliArgs, defaultWebRoot, main, parseArgs, resolveFilesRoot, resolvePort };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|