@mohxmd/dbstudio 0.1.0
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/README.md +78 -0
- package/bin/dbstudio +0 -0
- package/lib/commands/studio.ts +98 -0
- package/lib/commands/tunnel.ts +60 -0
- package/lib/constants/help.ts +33 -0
- package/lib/utils/args.ts +50 -0
- package/lib/utils/config.ts +70 -0
- package/lib/utils/dialect.ts +20 -0
- package/main.ts +41 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# dbstudio
|
|
2
|
+
|
|
3
|
+
> Spin up Drizzle Studio instantly from any database URL ā no project setup needed.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
### Global
|
|
8
|
+
```bash
|
|
9
|
+
npm i -g dbstudio
|
|
10
|
+
# or
|
|
11
|
+
bun add -g dbstudio
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### Without installing
|
|
15
|
+
```bash
|
|
16
|
+
bunx dbstudio <url>
|
|
17
|
+
# or
|
|
18
|
+
bun x dbstudio <url>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Standalone binaries
|
|
22
|
+
Download prebuilt binaries from GitHub Releases (Linux/macOS/Windows).
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# PostgreSQL
|
|
28
|
+
dbstudio postgresql://user:pass@localhost:5432/mydb
|
|
29
|
+
|
|
30
|
+
# MySQL
|
|
31
|
+
dbstudio mysql://user:pass@localhost:3306/mydb
|
|
32
|
+
|
|
33
|
+
# SQLite
|
|
34
|
+
dbstudio sqlite:./local.db
|
|
35
|
+
|
|
36
|
+
# Custom port
|
|
37
|
+
dbstudio postgresql://... --port 8080
|
|
38
|
+
|
|
39
|
+
# Auto-open browser
|
|
40
|
+
dbstudio postgresql://... --open
|
|
41
|
+
|
|
42
|
+
# Quick share with a temporary public URL
|
|
43
|
+
dbstudio postgresql://... --share
|
|
44
|
+
|
|
45
|
+
# Named tunnel with your hostname
|
|
46
|
+
dbstudio postgresql://... --share --tunnel dbstudio --hostname db.yourteam.com
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## How it works
|
|
50
|
+
|
|
51
|
+
1. Detects dialect from your URL (postgresql / mysql / sqlite)
|
|
52
|
+
2. Writes a temporary `drizzle.config.ts` in your OS temp directory
|
|
53
|
+
3. Spins up `drizzle-kit studio`
|
|
54
|
+
4. Cleans up the temp file when the process exits (including Ctrl+C)
|
|
55
|
+
|
|
56
|
+
No project config directory. No project setup. Just pass a URL.
|
|
57
|
+
|
|
58
|
+
## Options
|
|
59
|
+
|
|
60
|
+
| Flag | Default | Description |
|
|
61
|
+
|------|---------|-------------|
|
|
62
|
+
| `--port` | `4983` | Port to run studio on |
|
|
63
|
+
| `--host` | `127.0.0.1` | Host to bind to (`0.0.0.0` is used automatically with `--share` unless explicitly set) |
|
|
64
|
+
| `--open` | false | Auto-open in browser |
|
|
65
|
+
| `--share` | false | Expose Studio through Cloudflare Tunnel |
|
|
66
|
+
| `--tunnel` | | Named Cloudflare tunnel (requires `--hostname`) |
|
|
67
|
+
| `--hostname` | | Public hostname for named tunnel |
|
|
68
|
+
| `--help` | | Show help |
|
|
69
|
+
| `--version` | | Show version |
|
|
70
|
+
|
|
71
|
+
## Requirements
|
|
72
|
+
|
|
73
|
+
- [Bun](https://bun.sh) >= 1.0
|
|
74
|
+
- `cloudflared` if you use `--share`
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
package/bin/dbstudio
ADDED
|
Binary file
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { StudioOptions } from "../utils/args";
|
|
2
|
+
import { detectDialect } from "../utils/dialect";
|
|
3
|
+
import { createDrizzleConfig, cleanupAll } from "../utils/config";
|
|
4
|
+
import { launchTunnel } from "./tunnel";
|
|
5
|
+
import type { ChildProcess } from "child_process";
|
|
6
|
+
|
|
7
|
+
const procs: ChildProcess[] = [];
|
|
8
|
+
|
|
9
|
+
function killAll() {
|
|
10
|
+
for (const p of procs) {
|
|
11
|
+
if (!p.killed) p.kill("SIGTERM");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function registerCleanup() {
|
|
16
|
+
process.on("exit", cleanupAll);
|
|
17
|
+
process.on("SIGINT", () => {
|
|
18
|
+
console.log("\n\nš Shutting down dbstudio...");
|
|
19
|
+
killAll();
|
|
20
|
+
cleanupAll();
|
|
21
|
+
process.exit(0);
|
|
22
|
+
});
|
|
23
|
+
process.on("SIGTERM", () => {
|
|
24
|
+
killAll();
|
|
25
|
+
cleanupAll();
|
|
26
|
+
process.exit(0);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function runStudioCommand(options: StudioOptions): Promise<number> {
|
|
31
|
+
const { dbUrl, port, host, shouldOpen, shouldShare, tunnelName, publicHostname } = options;
|
|
32
|
+
|
|
33
|
+
const dialect = detectDialect(dbUrl);
|
|
34
|
+
const drizzleConfig = createDrizzleConfig(dbUrl, dialect);
|
|
35
|
+
const safeUrl = dbUrl.replace(/:\/\/.*@/, "://<credentials>@");
|
|
36
|
+
|
|
37
|
+
registerCleanup();
|
|
38
|
+
|
|
39
|
+
// Print startup info
|
|
40
|
+
|
|
41
|
+
console.log(`\nš dbstudio`);
|
|
42
|
+
console.log(` Dialect : ${dialect}`);
|
|
43
|
+
console.log(` URL : ${safeUrl}`);
|
|
44
|
+
console.log(` Studio : https://local.drizzle.studio`);
|
|
45
|
+
|
|
46
|
+
if (shouldShare && !tunnelName) {
|
|
47
|
+
console.log(` Tunnel : starting... public URL coming shortly`);
|
|
48
|
+
}
|
|
49
|
+
if (tunnelName && publicHostname) {
|
|
50
|
+
console.log(` Tunnel : https://${publicHostname}`);
|
|
51
|
+
}
|
|
52
|
+
console.log();
|
|
53
|
+
|
|
54
|
+
// Spawn drizzle-kit studio via bunx
|
|
55
|
+
// bunx is used so the binary works after `bun build --compile`
|
|
56
|
+
// without needing a local node_modules at runtime
|
|
57
|
+
|
|
58
|
+
const studioArgs = [
|
|
59
|
+
"drizzle-kit",
|
|
60
|
+
"studio",
|
|
61
|
+
`--config=${drizzleConfig}`,
|
|
62
|
+
`--port=${port}`,
|
|
63
|
+
`--host=${host}`,
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
if (shouldOpen && !shouldShare) studioArgs.push("--open");
|
|
67
|
+
|
|
68
|
+
const studio = Bun.spawn(["bunx", ...studioArgs], {
|
|
69
|
+
stdin: "ignore",
|
|
70
|
+
stdout: "inherit",
|
|
71
|
+
stderr: "inherit",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Launch tunnel after studio boots
|
|
75
|
+
|
|
76
|
+
if (shouldShare) {
|
|
77
|
+
// give drizzle-kit studio a moment to start before tunnel connects
|
|
78
|
+
await Bun.sleep(2000);
|
|
79
|
+
|
|
80
|
+
const tunnel = launchTunnel({ port, tunnelName, publicHostname, shouldOpen });
|
|
81
|
+
// cast needed since launchTunnel returns node ChildProcess
|
|
82
|
+
procs.push(tunnel as unknown as ChildProcess);
|
|
83
|
+
|
|
84
|
+
if (shouldOpen && tunnelName && publicHostname) {
|
|
85
|
+
spawn("xdg-open", [`https://${publicHostname}`], { stdio: "ignore" });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Wait for studio to exit
|
|
90
|
+
|
|
91
|
+
const exitCode = await studio.exited;
|
|
92
|
+
killAll();
|
|
93
|
+
cleanupAll();
|
|
94
|
+
return exitCode ?? 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// node spawn needed for tunnel (pipe stdio support)
|
|
98
|
+
import { spawn } from "child_process";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { createTunnelConfig } from "../utils/config";
|
|
3
|
+
|
|
4
|
+
export function launchTunnel(options: {
|
|
5
|
+
port: string;
|
|
6
|
+
tunnelName: string | null;
|
|
7
|
+
publicHostname: string | null;
|
|
8
|
+
shouldOpen: boolean;
|
|
9
|
+
}) {
|
|
10
|
+
const { port, tunnelName, publicHostname, shouldOpen } = options;
|
|
11
|
+
|
|
12
|
+
let tunnelArgs: string[];
|
|
13
|
+
|
|
14
|
+
if (tunnelName && publicHostname) {
|
|
15
|
+
// named tunnel ā generate temp config.yml, never touches ~/.cloudflared/config.yml
|
|
16
|
+
const tunnelConfigPath = createTunnelConfig(
|
|
17
|
+
tunnelName,
|
|
18
|
+
publicHostname,
|
|
19
|
+
port,
|
|
20
|
+
);
|
|
21
|
+
tunnelArgs = ["tunnel", "--config", tunnelConfigPath, "run", tunnelName];
|
|
22
|
+
} else {
|
|
23
|
+
// quick share ā zero setup, temporary trycloudflare.com URL
|
|
24
|
+
tunnelArgs = ["tunnel", "--url", `http://localhost:${port}`];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const tunnel = spawn("cloudflared", tunnelArgs, {
|
|
28
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
29
|
+
shell: false,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// cloudflared prints the public URL to stderr
|
|
33
|
+
tunnel.stderr?.on("data", (data: Buffer) => {
|
|
34
|
+
const line = data.toString();
|
|
35
|
+
process.stderr.write(data);
|
|
36
|
+
|
|
37
|
+
// quick share: extract and highlight the URL when cloudflared prints it
|
|
38
|
+
if (!tunnelName) {
|
|
39
|
+
const match = line.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/);
|
|
40
|
+
if (match) {
|
|
41
|
+
console.log(`\nā
Public URL: ${match[0]}`);
|
|
42
|
+
console.log(` Share this link with your team\n`);
|
|
43
|
+
if (shouldOpen) {
|
|
44
|
+
spawn("xdg-open", [match[0]], { stdio: "ignore" });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
tunnel.on("error", (err) => {
|
|
51
|
+
console.error(`\nā Failed to start cloudflared: ${err.message}`);
|
|
52
|
+
console.error(` Install it with: yay -S cloudflared`);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
tunnel.on("exit", (code) => {
|
|
56
|
+
if (code !== 0) console.error(`\nā ļø Tunnel exited with code ${code}`);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return tunnel;
|
|
60
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const HELP = `
|
|
2
|
+
dbstudio ā spin up Drizzle Studio from any database URL
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
dbstudio <database-url> [options]
|
|
6
|
+
|
|
7
|
+
Examples:
|
|
8
|
+
dbstudio postgresql://user:pass@localhost:5432/mydb
|
|
9
|
+
dbstudio mysql://user:pass@localhost:3306/mydb
|
|
10
|
+
dbstudio sqlite:./local.db
|
|
11
|
+
|
|
12
|
+
# Quick share (no CF account needed, temporary URL)
|
|
13
|
+
dbstudio postgresql://... --share
|
|
14
|
+
|
|
15
|
+
# Named tunnel (persistent URL, needs CF account + domain)
|
|
16
|
+
dbstudio postgresql://... --share --tunnel dbstudio --hostname db.yourteam.com
|
|
17
|
+
|
|
18
|
+
Options:
|
|
19
|
+
--port <number> Port to run studio on (default: 4983)
|
|
20
|
+
--host <string> Host to bind to (default: 127.0.0.1, or 0.0.0.0 with --share)
|
|
21
|
+
--open Auto-open in browser
|
|
22
|
+
--share Expose via Cloudflare Tunnel
|
|
23
|
+
--tunnel <name> Named CF tunnel (requires --hostname)
|
|
24
|
+
--hostname <domain> Public hostname for named tunnel
|
|
25
|
+
-h, --help Show this help
|
|
26
|
+
-v, --version Show version
|
|
27
|
+
|
|
28
|
+
Tunnel setup (one time):
|
|
29
|
+
yay -S cloudflared
|
|
30
|
+
cloudflared tunnel login
|
|
31
|
+
cloudflared tunnel create <name>
|
|
32
|
+
# add CNAME in Cloudflare dashboard ā <tunnel-id>.cfargotunnel.com
|
|
33
|
+
`;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type StudioOptions = {
|
|
2
|
+
dbUrl: string;
|
|
3
|
+
port: string;
|
|
4
|
+
host: string;
|
|
5
|
+
shouldOpen: boolean;
|
|
6
|
+
shouldShare: boolean;
|
|
7
|
+
tunnelName: string | null;
|
|
8
|
+
publicHostname: string | null;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/** Read a flag value in the form `--flag <value>`. */
|
|
12
|
+
function getFlag(args: string[], flag: string): string | null {
|
|
13
|
+
const idx = args.indexOf(flag);
|
|
14
|
+
if (idx === -1) return null;
|
|
15
|
+
const val = args[idx + 1];
|
|
16
|
+
return val && !val.startsWith("--") ? val : null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Parse and validate CLI arguments into studio runtime options. */
|
|
20
|
+
export function parseStudioOptions(args: string[]): StudioOptions {
|
|
21
|
+
const dbUrl = args[0];
|
|
22
|
+
|
|
23
|
+
if (!dbUrl || dbUrl.startsWith("--")) {
|
|
24
|
+
throw new Error("Please provide a database URL as the first argument.");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const shouldShare = args.includes("--share");
|
|
28
|
+
const tunnelName = getFlag(args, "--tunnel");
|
|
29
|
+
const publicHostname = getFlag(args, "--hostname");
|
|
30
|
+
|
|
31
|
+
if (tunnelName && !publicHostname) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
"--tunnel requires --hostname <your-domain>\n Example: --tunnel dbstudio --hostname db.yourteam.com",
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// when sharing, bind to all interfaces so cloudflared can reach studio
|
|
38
|
+
const explicitHost = getFlag(args, "--host");
|
|
39
|
+
const host = explicitHost ?? (shouldShare ? "0.0.0.0" : "127.0.0.1");
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
dbUrl,
|
|
43
|
+
port: getFlag(args, "--port") ?? "4983",
|
|
44
|
+
host,
|
|
45
|
+
shouldOpen: args.includes("--open"),
|
|
46
|
+
shouldShare,
|
|
47
|
+
tunnelName,
|
|
48
|
+
publicHostname,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { writeFileSync, unlinkSync, existsSync } from "fs";
|
|
2
|
+
import { tmpdir, homedir } from "os";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import type { Dialect } from "./dialect";
|
|
5
|
+
|
|
6
|
+
// Temp file registry
|
|
7
|
+
|
|
8
|
+
const tempFiles: string[] = [];
|
|
9
|
+
|
|
10
|
+
/** Remove all temporary files created by this process. */
|
|
11
|
+
export function cleanupAll() {
|
|
12
|
+
for (const f of tempFiles) {
|
|
13
|
+
if (existsSync(f)) unlinkSync(f);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Write content to a uniquely named file in the OS temp directory. */
|
|
18
|
+
function writeTempFile(name: string, content: string): string {
|
|
19
|
+
const path = join(tmpdir(), `${name}-${Date.now()}`);
|
|
20
|
+
writeFileSync(path, content, "utf8");
|
|
21
|
+
tempFiles.push(path);
|
|
22
|
+
return path;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Drizzle config
|
|
26
|
+
|
|
27
|
+
/** Build a minimal drizzle.config.ts string for the provided database URL. */
|
|
28
|
+
function generateDrizzleConfig(url: string, dialect: Dialect): string {
|
|
29
|
+
if (dialect === "sqlite") {
|
|
30
|
+
const filePath = url
|
|
31
|
+
.replace(/^sqlite:\/\//, "")
|
|
32
|
+
.replace(/^sqlite:/, "")
|
|
33
|
+
.replace(/^file:\/\//, "")
|
|
34
|
+
.replace(/^file:/, "");
|
|
35
|
+
return `export default {
|
|
36
|
+
dialect: "sqlite",
|
|
37
|
+
dbCredentials: { url: "${filePath}" },
|
|
38
|
+
};`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return `export default {
|
|
42
|
+
dialect: "${dialect}",
|
|
43
|
+
dbCredentials: { url: "${url}" },
|
|
44
|
+
};`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Create a temp drizzle config file and return its path. */
|
|
48
|
+
export function createDrizzleConfig(url: string, dialect: Dialect): string {
|
|
49
|
+
return writeTempFile("dbstudio.config.ts", generateDrizzleConfig(url, dialect));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Cloudflare tunnel config
|
|
53
|
+
|
|
54
|
+
/** Build a temporary cloudflared config for a named tunnel run. */
|
|
55
|
+
function generateTunnelConfig(tunnelName: string, hostname: string, port: string): string {
|
|
56
|
+
const credPath = join(homedir(), ".cloudflared");
|
|
57
|
+
return `tunnel: ${tunnelName}
|
|
58
|
+
credentials-file: ${credPath}/${tunnelName}.json
|
|
59
|
+
|
|
60
|
+
ingress:
|
|
61
|
+
- hostname: ${hostname}
|
|
62
|
+
service: http://localhost:${port}
|
|
63
|
+
- service: http_status:404
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Create a temp cloudflared config file for a named tunnel and return its path. */
|
|
68
|
+
export function createTunnelConfig(tunnelName: string, hostname: string, port: string): string {
|
|
69
|
+
return writeTempFile("dbstudio-tunnel.yml", generateTunnelConfig(tunnelName, hostname, port));
|
|
70
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type Dialect = "postgresql" | "mysql" | "sqlite";
|
|
2
|
+
|
|
3
|
+
/** Detect Drizzle dialect from a database URL or SQLite-style path. */
|
|
4
|
+
export function detectDialect(url: string): Dialect {
|
|
5
|
+
if (url.startsWith("postgresql://") || url.startsWith("postgres://"))
|
|
6
|
+
return "postgresql";
|
|
7
|
+
if (url.startsWith("mysql://") || url.startsWith("mysql2://")) return "mysql";
|
|
8
|
+
if (
|
|
9
|
+
url.startsWith("sqlite:") ||
|
|
10
|
+
url.startsWith("file:") ||
|
|
11
|
+
url === ":memory:" ||
|
|
12
|
+
url.endsWith(".db") ||
|
|
13
|
+
url.endsWith(".sqlite")
|
|
14
|
+
)
|
|
15
|
+
return "sqlite";
|
|
16
|
+
|
|
17
|
+
throw new Error(
|
|
18
|
+
`Could not detect dialect from URL: ${url}\nSupported: postgresql://, mysql://, sqlite:, file:`,
|
|
19
|
+
);
|
|
20
|
+
}
|
package/main.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { HELP } from "./lib/constants/help";
|
|
4
|
+
import { parseStudioOptions } from "./lib/utils/args";
|
|
5
|
+
import { runStudioCommand } from "./lib/commands/studio";
|
|
6
|
+
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
|
|
9
|
+
if (args.length === 0 || args.includes("-h") || args.includes("--help")) {
|
|
10
|
+
console.log(HELP);
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (args.includes("-v") || args.includes("--version")) {
|
|
15
|
+
const pkg = await Bun.file(
|
|
16
|
+
new URL("../package.json", import.meta.url),
|
|
17
|
+
).json();
|
|
18
|
+
console.log(`dbstudio v${pkg.version}`);
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const options = parseStudioOptions(args);
|
|
24
|
+
const code = await runStudioCommand(options);
|
|
25
|
+
process.exit(code);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
28
|
+
|
|
29
|
+
if (msg.startsWith("Please provide")) {
|
|
30
|
+
console.error(`ā ${msg}`);
|
|
31
|
+
console.error(" Run dbstudio --help for usage.");
|
|
32
|
+
} else if (msg.startsWith("Could not detect")) {
|
|
33
|
+
console.error(`ā ${msg}`);
|
|
34
|
+
} else if (msg.startsWith("--tunnel requires")) {
|
|
35
|
+
console.error(`ā ${msg}`);
|
|
36
|
+
} else {
|
|
37
|
+
console.error(`ā Unexpected error: ${msg}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mohxmd/dbstudio",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Spin up Drizzle Studio from any database URL",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"module": "main.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"dbstudio": "./bin/dbstudio"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"start": "bun main.ts",
|
|
13
|
+
"dev": "bun --watch main.ts",
|
|
14
|
+
"compile": "bun build main.ts --compile --outfile bin/dbstudio",
|
|
15
|
+
"compile:linux": "bun build main.ts --compile --target=bun-linux-x64 --outfile bin/dbstudio-linux",
|
|
16
|
+
"compile:mac": "bun build main.ts --compile --target=bun-darwin-arm64 --outfile bin/dbstudio-mac"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"bun": ">=1.0.0"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"main.ts",
|
|
23
|
+
"lib",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"drizzle-kit": "latest",
|
|
29
|
+
"pg": "latest"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/bun": "latest"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"typescript": "latest"
|
|
36
|
+
}
|
|
37
|
+
}
|