feat: add Docker dev environment and fix logging/cashu-ts

- Add Dockerfile, docker-compose.yml, and .dockerignore for Bun dev container
- Fix sdkLogger to use logger.warn instead of logger.log for warnings
- Add proper warn method to logger (writes to file instead of console)
- Use console.log for daemon startup messages to keep them visible
- Update cashu-ts getDecodedToken call with explicit well-known-pubkeys
- Use proof.amount.toNumber() for updated cashu-ts Amount type
This commit is contained in:
redshift
2026-05-16 16:22:16 +08:00
parent 8e9013ac7d
commit fd8f433a36
8 changed files with 42 additions and 13 deletions
+12
View File
@@ -0,0 +1,12 @@
node_modules/
dist/
.git/
.worktrees/
.pi/
logs/
tmp/
temp/
*.log
.env
.env.*
.DS_Store
+3
View File
@@ -0,0 +1,3 @@
FROM oven/bun:1-slim
WORKDIR /app
CMD ["/bin/bash"]
+14
View File
@@ -0,0 +1,14 @@
services:
bun:
build: .
container_name: routstrd-bun
working_dir: /app
volumes:
- .:/app
- bun_home:/root/.bun
stdin_open: true
tty: true
command: /bin/bash
volumes:
bun_home:
+1 -1
View File
@@ -271,7 +271,7 @@ function makeSdkLogger(prefix?: string): SdkLogger {
const fmt = (...args: unknown[]) => (tag ? [tag, ...args] : args); const fmt = (...args: unknown[]) => (tag ? [tag, ...args] : args);
return { return {
log: (...args: unknown[]) => logger.log(...fmt(...args)), log: (...args: unknown[]) => logger.log(...fmt(...args)),
warn: (...args: unknown[]) => logger.log(...fmt(...args)), warn: (...args: unknown[]) => logger.warn(...fmt(...args)),
error: (...args: unknown[]) => logger.error(...fmt(...args)), error: (...args: unknown[]) => logger.error(...fmt(...args)),
debug: (...args: unknown[]) => logger.debug(...fmt(...args)), debug: (...args: unknown[]) => logger.debug(...fmt(...args)),
child: (p: string) => makeSdkLogger(prefix ? `${prefix}:${p}` : p), child: (p: string) => makeSdkLogger(prefix ? `${prefix}:${p}` : p),
+1 -1
View File
@@ -17,7 +17,7 @@ function makeSdkLogger(prefix?: string): SdkLogger {
const fmt = (...args: unknown[]) => (tag ? [tag, ...args] : args); const fmt = (...args: unknown[]) => (tag ? [tag, ...args] : args);
return { return {
log: (...args: unknown[]) => logger.log(...fmt(...args)), log: (...args: unknown[]) => logger.log(...fmt(...args)),
warn: (...args: unknown[]) => logger.log(...fmt(...args)), warn: (...args: unknown[]) => logger.warn(...fmt(...args)),
error: (...args: unknown[]) => logger.error(...fmt(...args)), error: (...args: unknown[]) => logger.error(...fmt(...args)),
debug: (...args: unknown[]) => logger.debug(...fmt(...args)), debug: (...args: unknown[]) => logger.debug(...fmt(...args)),
child: (p: string) => makeSdkLogger(prefix ? `${prefix}:${p}` : p), child: (p: string) => makeSdkLogger(prefix ? `${prefix}:${p}` : p),
+3 -3
View File
@@ -1,4 +1,4 @@
import { getDecodedToken } from "@cashu/cashu-ts"; import { getDecodedToken, Amount } from "@cashu/cashu-ts";
import { InsufficientBalanceError } from "@routstr/sdk"; import { InsufficientBalanceError } from "@routstr/sdk";
import { logger } from "../../utils/logger"; import { logger } from "../../utils/logger";
import { createCocodClient, type CocodClient } from "./cocod-client"; import { createCocodClient, type CocodClient } from "./cocod-client";
@@ -7,9 +7,9 @@ export function decodeCashuTokenAmount(token: string): {
amount: number; amount: number;
unit: "sat" | "msat"; unit: "sat" | "msat";
} { } {
const decoded = getDecodedToken(token); const decoded = getDecodedToken(token, []);
const amount = const amount =
decoded?.proofs?.reduce((sum, proof) => sum + proof.amount, 0) ?? 0; decoded?.proofs?.reduce((sum, proof) => sum + proof.amount.toNumber(), 0) ?? 0;
const unit = decoded?.unit === "msat" ? "msat" : "sat"; const unit = decoded?.unit === "msat" ? "msat" : "sat";
return { amount, unit }; return { amount, unit };
} }
+5 -5
View File
@@ -28,7 +28,7 @@ async function startDaemonUnlocked(
const startupTimeoutMs = 10 * 60 * 1000; const startupTimeoutMs = 10 * 60 * 1000;
if (await isDaemonHealthy(port)) { if (await isDaemonHealthy(port)) {
logger.log(`Routstr daemon already running on http://localhost:${port}/v1`); console.log(`Routstr daemon already running on http://localhost:${port}/v1`);
return; return;
} }
@@ -43,8 +43,8 @@ async function startDaemonUnlocked(
const shellCmd = `bun run "${daemonScript}" ${args.map((a) => `'${a}'`).join(" ")}`; const shellCmd = `bun run "${daemonScript}" ${args.map((a) => `'${a}'`).join(" ")}`;
const proc = Bun.spawn(["sh", "-c", shellCmd], { const proc = Bun.spawn(["sh", "-c", shellCmd], {
stdout: "inherit", stdout: "ignore",
stderr: "inherit", stderr: "ignore",
stdin: "ignore", stdin: "ignore",
detached: true, detached: true,
}); });
@@ -67,7 +67,7 @@ async function startDaemonUnlocked(
} }
if (await isDaemonHealthy(port)) { if (await isDaemonHealthy(port)) {
logger.log(`Routstr daemon started (PID: ${proc.pid}).`); console.log(`Routstr daemon started (PID: ${proc.pid}).`);
return; return;
} }
} }
@@ -84,7 +84,7 @@ export async function startDaemon(
const startupTimeoutMs = 10 * 60 * 1000; const startupTimeoutMs = 10 * 60 * 1000;
if (await isDaemonHealthy(port)) { if (await isDaemonHealthy(port)) {
logger.log(`Routstr daemon already running on http://localhost:${port}/v1`); console.log(`Routstr daemon already running on http://localhost:${port}/v1`);
return; return;
} }
+3 -3
View File
@@ -48,18 +48,18 @@ async function writeLog(level: string, ...args: unknown[]) {
export const logger = { export const logger = {
log: (...args: unknown[]) => { log: (...args: unknown[]) => {
console.log(...args);
writeLog("INFO", ...args); writeLog("INFO", ...args);
}, },
debug: (...args: unknown[]) => { debug: (...args: unknown[]) => {
writeLog("DEBUG", ...args); writeLog("DEBUG", ...args);
}, },
warn: (...args: unknown[]) => {
writeLog("WARN", ...args);
},
error: (...args: unknown[]) => { error: (...args: unknown[]) => {
console.error(...args);
writeLog("ERROR", ...args); writeLog("ERROR", ...args);
}, },
info: (...args: unknown[]) => { info: (...args: unknown[]) => {
console.log(...args);
writeLog("INFO", ...args); writeLog("INFO", ...args);
}, },
}; };