business-stack 0.1.3 → 0.1.5
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 +4 -3
- package/bin/business-stack.cjs +127 -30
- package/gateway/README.md +14 -4
- package/gateway/package.json +12 -9
- package/gateway/src/auth.ts +2 -2
- package/gateway/src/index.ts +7 -4
- package/gateway/src/integrations/store.ts +15 -14
- package/gateway/src/stack-secrets.ts +5 -5
- package/gateway/tsconfig.json +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -8,8 +8,9 @@ Install these on your machine and ensure they are on your `PATH`:
|
|
|
8
8
|
|
|
9
9
|
| Tool | Purpose |
|
|
10
10
|
|------|---------|
|
|
11
|
-
| [Node.js](https://nodejs.org/) 20+ | Runs the `business-stack` CLI
|
|
12
|
-
|
|
|
11
|
+
| [Node.js](https://nodejs.org/) 20+ | Runs the `business-stack` CLI |
|
|
12
|
+
| **npm** (comes with Node) | `business-stack start` / `dev` use **`npm install`** and **`npm run`** for workspaces and Turborepo |
|
|
13
|
+
| *(optional)* [Bun](https://bun.sh) | Only if you develop the **full monorepo** from git (`bun run dev` at repo root); **not** required for the published `business-stack` package |
|
|
13
14
|
| [uv](https://docs.astral.sh/uv/) | Installs and runs the Python backend |
|
|
14
15
|
| Python **3.12** | Required by the backend (managed via `uv`) |
|
|
15
16
|
|
|
@@ -61,7 +62,7 @@ npx business-stack start
|
|
|
61
62
|
```
|
|
62
63
|
|
|
63
64
|
- **`setup`** generates secrets, stores them in SQLite (`node_modules/business-stack/gateway/auth.sqlite`, table `stack_secrets`), and writes `gateway/.env`, `frontend/web/.env.local`, and `backend/.env` under that package path. You do not need to create `.env` files by hand.
|
|
64
|
-
- **`start`** runs
|
|
65
|
+
- **`start`** runs **`npm install`** (workspaces), **`uv sync`**, **`npm run build`**, Alembic migrations, then **`npm run start`** (Turborepo: Next, gateway, backend). First run can take several minutes.
|
|
65
66
|
|
|
66
67
|
Optional flags for `start`: `--skip-install`, `--skip-build`, `--skip-migrate`.
|
|
67
68
|
|
package/bin/business-stack.cjs
CHANGED
|
@@ -111,23 +111,92 @@ function writeEnvFile(filePath, content) {
|
|
|
111
111
|
fs.writeFileSync(filePath, `${content.trim()}\n`, "utf8");
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return
|
|
114
|
+
function getCliPackageVersion() {
|
|
115
|
+
try {
|
|
116
|
+
const p = path.join(__dirname, "..", "package.json");
|
|
117
|
+
return JSON.parse(fs.readFileSync(p, "utf8")).version;
|
|
118
|
+
} catch {
|
|
119
|
+
return "?";
|
|
118
120
|
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function logPhase(msg) {
|
|
124
|
+
const line = `business-stack: ${msg}`;
|
|
125
|
+
console.log(line);
|
|
126
|
+
console.error(line);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Microsoft Store / WindowsApps shims often exit 0 immediately with no real Bun — skip them. */
|
|
130
|
+
function isWindowsAppsStub(exePath) {
|
|
131
|
+
const n = exePath.toLowerCase().replace(/\//g, "\\");
|
|
132
|
+
return (
|
|
133
|
+
n.includes("\\windowsapps\\") ||
|
|
134
|
+
n.includes("microsoft\\windowsapps") ||
|
|
135
|
+
n.endsWith("appinstaller.exe")
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function whereAll(cmd) {
|
|
119
140
|
const r = spawnSync("where.exe", [cmd], {
|
|
120
141
|
encoding: "utf8",
|
|
121
142
|
windowsHide: true,
|
|
122
143
|
});
|
|
123
144
|
if (r.status !== 0 || !r.stdout) {
|
|
124
|
-
return
|
|
145
|
+
return [];
|
|
125
146
|
}
|
|
126
|
-
|
|
147
|
+
return r.stdout
|
|
127
148
|
.split(/\r?\n/)
|
|
128
149
|
.map((s) => s.trim())
|
|
129
|
-
.
|
|
130
|
-
|
|
150
|
+
.filter(Boolean);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function executableResponds(exe, args) {
|
|
154
|
+
const r = spawnSync(exe, args, {
|
|
155
|
+
encoding: "utf8",
|
|
156
|
+
windowsHide: true,
|
|
157
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
158
|
+
timeout: 20_000,
|
|
159
|
+
});
|
|
160
|
+
if (r.error) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
if (r.status !== 0) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
const out = `${String(r.stdout || "")}${String(r.stderr || "")}`.trim();
|
|
167
|
+
return out.length >= 2;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Resolve `npm` / `bun` / `uv` on Windows: `where` can list a useless WindowsApps stub first.
|
|
172
|
+
* Pick a path that successfully runs `--version`.
|
|
173
|
+
*/
|
|
174
|
+
function resolveExecutable(cmd) {
|
|
175
|
+
if (process.platform !== "win32") {
|
|
176
|
+
return cmd;
|
|
177
|
+
}
|
|
178
|
+
const all = whereAll(cmd);
|
|
179
|
+
if (all.length === 0) {
|
|
180
|
+
return cmd;
|
|
181
|
+
}
|
|
182
|
+
const preferred = all.filter((p) => !isWindowsAppsStub(p));
|
|
183
|
+
const order = preferred.length > 0 ? preferred : all;
|
|
184
|
+
for (let i = order.length - 1; i >= 0; i--) {
|
|
185
|
+
const exe = order[i];
|
|
186
|
+
if (isWindowsAppsStub(exe)) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (executableResponds(exe, ["--version"])) {
|
|
190
|
+
return exe;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
for (let i = order.length - 1; i >= 0; i--) {
|
|
194
|
+
const exe = order[i];
|
|
195
|
+
if (executableResponds(exe, ["--version"])) {
|
|
196
|
+
return exe;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return order[order.length - 1] || cmd;
|
|
131
200
|
}
|
|
132
201
|
|
|
133
202
|
function cmdExists(cmd) {
|
|
@@ -140,8 +209,10 @@ function cmdExists(cmd) {
|
|
|
140
209
|
function runDoctor() {
|
|
141
210
|
const ok = [];
|
|
142
211
|
const bad = [];
|
|
143
|
-
if (cmdExists("
|
|
144
|
-
else bad.push("
|
|
212
|
+
if (cmdExists("node")) ok.push("node");
|
|
213
|
+
else bad.push("node (https://nodejs.org/)");
|
|
214
|
+
if (cmdExists("npm")) ok.push("npm");
|
|
215
|
+
else bad.push("npm (ships with Node.js)");
|
|
145
216
|
if (cmdExists("uv")) ok.push("uv");
|
|
146
217
|
else bad.push("uv (https://docs.astral.sh/uv/)");
|
|
147
218
|
if (cmdExists("python") || cmdExists("python3")) ok.push("python");
|
|
@@ -155,6 +226,9 @@ function runDoctor() {
|
|
|
155
226
|
return;
|
|
156
227
|
}
|
|
157
228
|
console.log("\nAll common toolchain binaries are on PATH.");
|
|
229
|
+
console.log(
|
|
230
|
+
"\nThe gateway runs on **Node** (tsx + better-sqlite3). Bun is optional for monorepo contributors only.",
|
|
231
|
+
);
|
|
158
232
|
}
|
|
159
233
|
|
|
160
234
|
async function promptDefaults(rl, defaults) {
|
|
@@ -283,19 +357,33 @@ BACKEND_GATEWAY_SECRET=${backendGatewaySecret}
|
|
|
283
357
|
}
|
|
284
358
|
|
|
285
359
|
function envFileLooksConfigured(stackRoot) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
360
|
+
try {
|
|
361
|
+
const g = path.join(stackRoot, "gateway", ".env");
|
|
362
|
+
if (fs.existsSync(g)) {
|
|
363
|
+
const t = fs.readFileSync(g, "utf8");
|
|
364
|
+
if (
|
|
365
|
+
/^BETTER_AUTH_SECRET=./m.test(t) ||
|
|
366
|
+
/^INTEGRATIONS_ENCRYPTION_KEY=./m.test(t)
|
|
367
|
+
) {
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
291
370
|
}
|
|
371
|
+
return hasExistingSecrets(stackRoot);
|
|
372
|
+
} catch (e) {
|
|
373
|
+
console.error(
|
|
374
|
+
"business-stack: could not read setup state:",
|
|
375
|
+
e instanceof Error ? e.message : e,
|
|
376
|
+
);
|
|
377
|
+
return false;
|
|
292
378
|
}
|
|
293
|
-
return hasExistingSecrets(stackRoot);
|
|
294
379
|
}
|
|
295
380
|
|
|
296
381
|
function runCmd(label, cmd, args, cwd, extraEnv) {
|
|
297
|
-
|
|
382
|
+
logPhase(`${label}…`);
|
|
298
383
|
const exe = resolveExecutable(cmd);
|
|
384
|
+
if (process.platform === "win32") {
|
|
385
|
+
logPhase(`using ${cmd} → ${exe}`);
|
|
386
|
+
}
|
|
299
387
|
const r = spawnSync(exe, args, {
|
|
300
388
|
cwd,
|
|
301
389
|
stdio: "inherit",
|
|
@@ -333,7 +421,7 @@ function waitForChild(child, label) {
|
|
|
333
421
|
|
|
334
422
|
child.on("error", (err) => {
|
|
335
423
|
console.error(`business-stack: ${label} — failed to spawn process:`, err.message);
|
|
336
|
-
console.error("
|
|
424
|
+
console.error(" Run: business-stack doctor");
|
|
337
425
|
finish(1);
|
|
338
426
|
});
|
|
339
427
|
|
|
@@ -357,8 +445,9 @@ async function runStart(opts) {
|
|
|
357
445
|
process.exit(1);
|
|
358
446
|
}
|
|
359
447
|
|
|
360
|
-
|
|
361
|
-
|
|
448
|
+
logPhase("starting (install → sync → build → migrate → servers)");
|
|
449
|
+
logPhase(`stack root ${stackRoot}`);
|
|
450
|
+
logPhase(`CLI package v${getCliPackageVersion()} — if there is no output below, run: npm i -g business-stack@latest`);
|
|
362
451
|
|
|
363
452
|
const fromDb = readStackSecretsEnv(stackRoot);
|
|
364
453
|
const childEnv = { ...process.env };
|
|
@@ -369,11 +458,17 @@ async function runStart(opts) {
|
|
|
369
458
|
}
|
|
370
459
|
|
|
371
460
|
if (!opts.skipInstall) {
|
|
372
|
-
runCmd(
|
|
461
|
+
runCmd(
|
|
462
|
+
"npm install (workspaces)",
|
|
463
|
+
"npm",
|
|
464
|
+
["install", "--no-fund", "--no-audit"],
|
|
465
|
+
stackRoot,
|
|
466
|
+
childEnv,
|
|
467
|
+
);
|
|
373
468
|
}
|
|
374
469
|
runCmd("uv sync (backend)", "uv", ["sync"], path.join(stackRoot, "backend"), childEnv);
|
|
375
470
|
if (!opts.skipBuild) {
|
|
376
|
-
runCmd("
|
|
471
|
+
runCmd("npm run build", "npm", ["run", "build"], stackRoot, childEnv);
|
|
377
472
|
}
|
|
378
473
|
if (!opts.skipMigrate) {
|
|
379
474
|
runCmd(
|
|
@@ -385,10 +480,12 @@ async function runStart(opts) {
|
|
|
385
480
|
);
|
|
386
481
|
}
|
|
387
482
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
483
|
+
logPhase("launching production servers (turbo start via npm)");
|
|
484
|
+
const npmExe = resolveExecutable("npm");
|
|
485
|
+
if (process.platform === "win32") {
|
|
486
|
+
logPhase(`using npm → ${npmExe}`);
|
|
487
|
+
}
|
|
488
|
+
const child = spawn(npmExe, ["run", "start"], {
|
|
392
489
|
cwd: stackRoot,
|
|
393
490
|
stdio: "inherit",
|
|
394
491
|
env: childEnv,
|
|
@@ -427,17 +524,17 @@ function runDev() {
|
|
|
427
524
|
childEnv[k] = String(v);
|
|
428
525
|
}
|
|
429
526
|
}
|
|
430
|
-
runCmd("
|
|
527
|
+
runCmd("npm run dev", "npm", ["run", "dev"], stackRoot, childEnv);
|
|
431
528
|
}
|
|
432
529
|
|
|
433
530
|
program
|
|
434
531
|
.name("business-stack")
|
|
435
532
|
.description("Run the business-stack monorepo (Next + Hono gateway + FastAPI)")
|
|
436
|
-
.version("0.1.
|
|
533
|
+
.version("0.1.5");
|
|
437
534
|
|
|
438
535
|
program
|
|
439
536
|
.command("doctor")
|
|
440
|
-
.description("Check for
|
|
537
|
+
.description("Check for node, npm, uv, and python on PATH")
|
|
441
538
|
.action(runDoctor);
|
|
442
539
|
|
|
443
540
|
program
|
|
@@ -457,7 +554,7 @@ program
|
|
|
457
554
|
program
|
|
458
555
|
.command("start")
|
|
459
556
|
.description("Install deps, build, migrate, run production stack (turbo start)")
|
|
460
|
-
.option("--skip-install", "Skip
|
|
557
|
+
.option("--skip-install", "Skip npm install")
|
|
461
558
|
.option("--skip-build", "Skip turbo build")
|
|
462
559
|
.option("--skip-migrate", "Skip alembic upgrade")
|
|
463
560
|
.action(async (o) => {
|
package/gateway/README.md
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
Install dependencies from the **repo root** (workspaces) or in this folder:
|
|
2
|
+
|
|
2
3
|
```sh
|
|
3
|
-
|
|
4
|
+
npm install
|
|
4
5
|
```
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Run (development with reload):
|
|
8
|
+
|
|
7
9
|
```sh
|
|
8
|
-
|
|
10
|
+
npm run dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Production-style (no watch):
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm run start
|
|
9
17
|
```
|
|
10
18
|
|
|
11
19
|
The gateway listens on **port 3001** by default (`PORT`). Open `http://127.0.0.1:3001` (or set `PORT`).
|
|
12
20
|
|
|
21
|
+
Stack: **Hono**, **Node** via **tsx**, **better-sqlite3** for auth + integration settings, **Better Auth**.
|
|
22
|
+
|
|
13
23
|
Better Auth needs a public **base URL** (where `/api/auth` is reached in the browser). With the Next.js app proxying auth, set `BETTER_AUTH_URL` to that origin (e.g. `http://localhost:3000`). See `.env.example`. If unset, the gateway defaults to `http://localhost:3000`.
|
package/gateway/package.json
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@business-stack/gateway",
|
|
3
3
|
"private": true,
|
|
4
|
-
"packageManager": "bun@1.3.1",
|
|
5
4
|
"scripts": {
|
|
6
|
-
"dev": "
|
|
7
|
-
"start": "
|
|
8
|
-
"migrate": "
|
|
9
|
-
"build": "
|
|
5
|
+
"dev": "tsx watch src/index.ts",
|
|
6
|
+
"start": "tsx src/index.ts",
|
|
7
|
+
"migrate": "npx @better-auth/cli@latest migrate --yes",
|
|
8
|
+
"build": "node -e \"require('fs').mkdirSync('dist',{recursive:true}); require('fs').writeFileSync('dist/.buildstamp','')\"",
|
|
10
9
|
"lint": "biome check .",
|
|
11
10
|
"lint:fix": "biome check --write .",
|
|
12
11
|
"typecheck": "tsc --noEmit",
|
|
13
|
-
"test": "
|
|
14
|
-
"clean": "
|
|
12
|
+
"test": "node -e \"process.exit(0)\"",
|
|
13
|
+
"clean": "npx rimraf@6 dist"
|
|
15
14
|
},
|
|
16
15
|
"dependencies": {
|
|
16
|
+
"@hono/node-server": "^1.19.9",
|
|
17
17
|
"better-auth": "1.5.6",
|
|
18
|
-
"
|
|
18
|
+
"better-sqlite3": "^11.7.0",
|
|
19
|
+
"hono": "^4.12.10",
|
|
20
|
+
"tsx": "^4.19.3"
|
|
19
21
|
},
|
|
20
22
|
"devDependencies": {
|
|
21
|
-
"@types/
|
|
23
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
24
|
+
"@types/node": "^20",
|
|
22
25
|
"typescript": "^5.8.3"
|
|
23
26
|
}
|
|
24
27
|
}
|
package/gateway/src/auth.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Database } from "bun:sqlite";
|
|
2
1
|
import { betterAuth } from "better-auth";
|
|
2
|
+
import Database from "better-sqlite3";
|
|
3
3
|
import { loadStackSecretsIntoEnv } from "./stack-secrets";
|
|
4
4
|
|
|
5
5
|
loadStackSecretsIntoEnv();
|
|
6
6
|
|
|
7
7
|
const dbPath = process.env.BETTER_AUTH_DATABASE_PATH ?? "auth.sqlite";
|
|
8
|
-
const sqlite = new Database(dbPath
|
|
8
|
+
const sqlite = new Database(dbPath);
|
|
9
9
|
|
|
10
10
|
function parseTrustedOrigins(): string[] {
|
|
11
11
|
const raw = process.env.BETTER_AUTH_TRUSTED_ORIGINS;
|
package/gateway/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { serve } from "@hono/node-server";
|
|
1
2
|
import { Hono } from "hono";
|
|
2
3
|
import { cors } from "hono/cors";
|
|
3
4
|
import { proxy } from "hono/proxy";
|
|
@@ -130,12 +131,14 @@ app.get("/session", (c) => {
|
|
|
130
131
|
});
|
|
131
132
|
|
|
132
133
|
const port = Number(process.env.PORT ?? 3001);
|
|
134
|
+
const hostname = process.env.HOST?.trim() || "127.0.0.1";
|
|
133
135
|
|
|
134
|
-
|
|
135
|
-
port,
|
|
136
|
+
serve({
|
|
136
137
|
fetch: app.fetch,
|
|
137
|
-
|
|
138
|
+
port,
|
|
139
|
+
hostname,
|
|
140
|
+
});
|
|
138
141
|
|
|
139
142
|
console.log(
|
|
140
|
-
`Gateway listening on http
|
|
143
|
+
`Gateway listening on http://${hostname}:${port} (backend ${backendOrigin}, prefix ${apiGatewayPrefix})`,
|
|
141
144
|
);
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
2
|
import { decryptIntegrationValue, encryptIntegrationValue } from "./crypto";
|
|
3
3
|
import { INTEGRATION_DB_KEYS, type IntegrationDbKey } from "./keys";
|
|
4
4
|
|
|
5
5
|
const dbPath = process.env.BETTER_AUTH_DATABASE_PATH ?? "auth.sqlite";
|
|
6
6
|
|
|
7
|
-
let _db: Database | null = null;
|
|
7
|
+
let _db: Database.Database | null = null;
|
|
8
8
|
|
|
9
|
-
function getDb(): Database {
|
|
9
|
+
function getDb(): Database.Database {
|
|
10
10
|
if (!_db) {
|
|
11
|
-
_db = new Database(dbPath
|
|
12
|
-
_db.
|
|
11
|
+
_db = new Database(dbPath);
|
|
12
|
+
_db.exec(`
|
|
13
13
|
CREATE TABLE IF NOT EXISTS integration_settings (
|
|
14
14
|
key TEXT PRIMARY KEY NOT NULL,
|
|
15
15
|
ciphertext TEXT NOT NULL,
|
|
@@ -22,8 +22,8 @@ function getDb(): Database {
|
|
|
22
22
|
|
|
23
23
|
export function getEncryptedRow(key: IntegrationDbKey): string | null {
|
|
24
24
|
const row = getDb()
|
|
25
|
-
.
|
|
26
|
-
.get(key) as { ciphertext: string } |
|
|
25
|
+
.prepare("SELECT ciphertext FROM integration_settings WHERE key = ?")
|
|
26
|
+
.get(key) as { ciphertext: string } | undefined;
|
|
27
27
|
return row?.ciphertext ?? null;
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -33,16 +33,17 @@ export function setEncryptedRow(
|
|
|
33
33
|
): void {
|
|
34
34
|
const ciphertext = encryptIntegrationValue(plaintext);
|
|
35
35
|
const updatedAt = new Date().toISOString();
|
|
36
|
-
getDb()
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
getDb()
|
|
37
|
+
.prepare(
|
|
38
|
+
`INSERT INTO integration_settings (key, ciphertext, updated_at)
|
|
39
|
+
VALUES (?, ?, ?)
|
|
40
|
+
ON CONFLICT(key) DO UPDATE SET ciphertext = excluded.ciphertext, updated_at = excluded.updated_at`,
|
|
41
|
+
)
|
|
42
|
+
.run(key, ciphertext, updatedAt);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
export function deleteRow(key: IntegrationDbKey): void {
|
|
45
|
-
getDb().
|
|
46
|
+
getDb().prepare("DELETE FROM integration_settings WHERE key = ?").run(key);
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
export function getPlaintext(key: IntegrationDbKey): string | null {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* If an env var is unset or whitespace-only, fill it from `stack_secrets` in the auth DB.
|
|
@@ -6,20 +6,20 @@ import { Database } from "bun:sqlite";
|
|
|
6
6
|
*/
|
|
7
7
|
export function loadStackSecretsIntoEnv(): void {
|
|
8
8
|
const dbPath = process.env.BETTER_AUTH_DATABASE_PATH ?? "auth.sqlite";
|
|
9
|
-
let db: Database;
|
|
9
|
+
let db: Database.Database;
|
|
10
10
|
try {
|
|
11
|
-
db = new Database(dbPath
|
|
11
|
+
db = new Database(dbPath);
|
|
12
12
|
} catch {
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
15
|
try {
|
|
16
|
-
db.
|
|
16
|
+
db.exec(`
|
|
17
17
|
CREATE TABLE IF NOT EXISTS stack_secrets (
|
|
18
18
|
key TEXT PRIMARY KEY NOT NULL,
|
|
19
19
|
value TEXT NOT NULL
|
|
20
20
|
)
|
|
21
21
|
`);
|
|
22
|
-
const rows = db.
|
|
22
|
+
const rows = db.prepare("SELECT key, value FROM stack_secrets").all() as {
|
|
23
23
|
key: string;
|
|
24
24
|
value: string;
|
|
25
25
|
}[];
|
package/gateway/tsconfig.json
CHANGED
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "business-stack",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Next.js + Hono gateway + FastAPI monorepo",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
|
-
"packageManager": "bun@1.3.1",
|
|
7
6
|
"workspaces": ["frontend/web", "gateway", "backend"],
|
|
8
7
|
"scripts": {
|
|
9
8
|
"prepublishOnly": "node ../scripts/sync-npm-package.cjs",
|