feat: migrate auth and state flows to better-auth and convex

This commit is contained in:
Codex
2026-02-18 13:58:42 +00:00
parent 445e5725b3
commit b1eed7fa2c
10 changed files with 704 additions and 253 deletions

View File

@@ -3,201 +3,91 @@
const test = require("node:test");
const assert = require("node:assert/strict");
function withTempEnv(patch, run) {
const previous = {};
for (const key of Object.keys(patch)) {
previous[key] = process.env[key];
if (patch[key] === undefined) {
delete process.env[key];
} else {
process.env[key] = patch[key];
}
}
try {
delete require.cache[require.resolve("../src/config")];
run();
} finally {
for (const key of Object.keys(patch)) {
if (previous[key] === undefined) {
delete process.env[key];
} else {
process.env[key] = previous[key];
}
}
delete require.cache[require.resolve("../src/config")];
}
}
test("config uses defaults when env is missing", () => {
const previous = {
PORT: process.env.PORT,
STATE_FILE_PATH: process.env.STATE_FILE_PATH,
LOG_LEVEL: process.env.LOG_LEVEL,
APP_BASE_URL: process.env.APP_BASE_URL,
TTS_MODEL: process.env.TTS_MODEL,
S3_SIGNED_URL_TTL_SEC: process.env.S3_SIGNED_URL_TTL_SEC,
X_BOT_USER_ID: process.env.X_BOT_USER_ID,
WEBHOOK_RPM: process.env.WEBHOOK_RPM,
POLAR_SERVER: process.env.POLAR_SERVER,
POLAR_PRODUCT_IDS: process.env.POLAR_PRODUCT_IDS,
};
delete process.env.PORT;
delete process.env.STATE_FILE_PATH;
delete process.env.LOG_LEVEL;
delete process.env.APP_BASE_URL;
delete process.env.TTS_MODEL;
delete process.env.S3_SIGNED_URL_TTL_SEC;
delete process.env.X_BOT_USER_ID;
delete process.env.WEBHOOK_RPM;
delete process.env.POLAR_SERVER;
delete process.env.POLAR_PRODUCT_IDS;
delete require.cache[require.resolve("../src/config")];
const { config } = require("../src/config");
assert.equal(config.port, 3000);
assert.equal(config.stateFilePath, "./data/state.json");
assert.equal(config.logLevel, "info");
assert.equal(config.appBaseUrl, "http://localhost:3000");
assert.equal(config.ttsModel, "gpt-4o-mini-tts");
assert.equal(config.s3SignedUrlTtlSec, 3600);
assert.equal(config.xBotUserId, "");
assert.equal(config.polarServer, "production");
assert.deepEqual(config.polarProductIds, []);
assert.equal(config.rateLimits.webhookPerMinute, 120);
if (previous.PORT === undefined) {
delete process.env.PORT;
} else {
process.env.PORT = previous.PORT;
}
if (previous.STATE_FILE_PATH === undefined) {
delete process.env.STATE_FILE_PATH;
} else {
process.env.STATE_FILE_PATH = previous.STATE_FILE_PATH;
}
if (previous.LOG_LEVEL === undefined) {
delete process.env.LOG_LEVEL;
} else {
process.env.LOG_LEVEL = previous.LOG_LEVEL;
}
if (previous.APP_BASE_URL === undefined) {
delete process.env.APP_BASE_URL;
} else {
process.env.APP_BASE_URL = previous.APP_BASE_URL;
}
if (previous.TTS_MODEL === undefined) {
delete process.env.TTS_MODEL;
} else {
process.env.TTS_MODEL = previous.TTS_MODEL;
}
if (previous.S3_SIGNED_URL_TTL_SEC === undefined) {
delete process.env.S3_SIGNED_URL_TTL_SEC;
} else {
process.env.S3_SIGNED_URL_TTL_SEC = previous.S3_SIGNED_URL_TTL_SEC;
}
if (previous.X_BOT_USER_ID === undefined) {
delete process.env.X_BOT_USER_ID;
} else {
process.env.X_BOT_USER_ID = previous.X_BOT_USER_ID;
}
if (previous.WEBHOOK_RPM === undefined) {
delete process.env.WEBHOOK_RPM;
} else {
process.env.WEBHOOK_RPM = previous.WEBHOOK_RPM;
}
if (previous.POLAR_SERVER === undefined) {
delete process.env.POLAR_SERVER;
} else {
process.env.POLAR_SERVER = previous.POLAR_SERVER;
}
if (previous.POLAR_PRODUCT_IDS === undefined) {
delete process.env.POLAR_PRODUCT_IDS;
} else {
process.env.POLAR_PRODUCT_IDS = previous.POLAR_PRODUCT_IDS;
}
withTempEnv({
PORT: undefined,
LOG_LEVEL: undefined,
APP_BASE_URL: undefined,
BETTER_AUTH_SECRET: undefined,
BETTER_AUTH_BASE_PATH: undefined,
QWEN_TTS_MODEL: undefined,
MINIO_SIGNED_URL_TTL_SEC: undefined,
MINIO_USE_SSL: undefined,
WEBHOOK_RPM: undefined,
}, () => {
const { config } = require("../src/config");
assert.equal(config.port, 3000);
assert.equal(config.logLevel, "info");
assert.equal(config.appBaseUrl, "http://localhost:3000");
assert.equal(config.betterAuthBasePath, "/api/auth");
assert.equal(config.qwenTtsModel, "qwen-tts-latest");
assert.equal(config.minioSignedUrlTtlSec, 3600);
assert.equal(config.minioUseSSL, true);
assert.equal(config.rateLimits.webhookPerMinute, 120);
});
});
test("config reads state path and numeric env overrides", () => {
const previous = {
PORT: process.env.PORT,
STATE_FILE_PATH: process.env.STATE_FILE_PATH,
LOG_LEVEL: process.env.LOG_LEVEL,
WEBHOOK_RPM: process.env.WEBHOOK_RPM,
APP_BASE_URL: process.env.APP_BASE_URL,
TTS_MODEL: process.env.TTS_MODEL,
S3_SIGNED_URL_TTL_SEC: process.env.S3_SIGNED_URL_TTL_SEC,
X_BOT_USER_ID: process.env.X_BOT_USER_ID,
POLAR_SERVER: process.env.POLAR_SERVER,
POLAR_PRODUCT_IDS: process.env.POLAR_PRODUCT_IDS,
};
process.env.PORT = "8080";
process.env.STATE_FILE_PATH = "/data/prod-state.json";
process.env.LOG_LEVEL = "debug";
process.env.APP_BASE_URL = "https://xartaudio.app";
process.env.TTS_MODEL = "custom-tts";
process.env.S3_SIGNED_URL_TTL_SEC = "7200";
process.env.X_BOT_USER_ID = "bot-user-id";
process.env.WEBHOOK_RPM = "77";
process.env.POLAR_SERVER = "sandbox";
process.env.POLAR_PRODUCT_IDS = "prod_1,prod_2";
delete require.cache[require.resolve("../src/config")];
const { config } = require("../src/config");
assert.equal(config.port, 8080);
assert.equal(config.stateFilePath, "/data/prod-state.json");
assert.equal(config.logLevel, "debug");
assert.equal(config.appBaseUrl, "https://xartaudio.app");
assert.equal(config.ttsModel, "custom-tts");
assert.equal(config.s3SignedUrlTtlSec, 7200);
assert.equal(config.xBotUserId, "bot-user-id");
assert.equal(config.polarServer, "sandbox");
assert.deepEqual(config.polarProductIds, ["prod_1", "prod_2"]);
assert.equal(config.rateLimits.webhookPerMinute, 77);
if (previous.PORT === undefined) {
delete process.env.PORT;
} else {
process.env.PORT = previous.PORT;
}
if (previous.STATE_FILE_PATH === undefined) {
delete process.env.STATE_FILE_PATH;
} else {
process.env.STATE_FILE_PATH = previous.STATE_FILE_PATH;
}
if (previous.LOG_LEVEL === undefined) {
delete process.env.LOG_LEVEL;
} else {
process.env.LOG_LEVEL = previous.LOG_LEVEL;
}
if (previous.APP_BASE_URL === undefined) {
delete process.env.APP_BASE_URL;
} else {
process.env.APP_BASE_URL = previous.APP_BASE_URL;
}
if (previous.TTS_MODEL === undefined) {
delete process.env.TTS_MODEL;
} else {
process.env.TTS_MODEL = previous.TTS_MODEL;
}
if (previous.S3_SIGNED_URL_TTL_SEC === undefined) {
delete process.env.S3_SIGNED_URL_TTL_SEC;
} else {
process.env.S3_SIGNED_URL_TTL_SEC = previous.S3_SIGNED_URL_TTL_SEC;
}
if (previous.X_BOT_USER_ID === undefined) {
delete process.env.X_BOT_USER_ID;
} else {
process.env.X_BOT_USER_ID = previous.X_BOT_USER_ID;
}
if (previous.WEBHOOK_RPM === undefined) {
delete process.env.WEBHOOK_RPM;
} else {
process.env.WEBHOOK_RPM = previous.WEBHOOK_RPM;
}
if (previous.POLAR_SERVER === undefined) {
delete process.env.POLAR_SERVER;
} else {
process.env.POLAR_SERVER = previous.POLAR_SERVER;
}
if (previous.POLAR_PRODUCT_IDS === undefined) {
delete process.env.POLAR_PRODUCT_IDS;
} else {
process.env.POLAR_PRODUCT_IDS = previous.POLAR_PRODUCT_IDS;
}
test("config reads convex/qwen/minio overrides", () => {
withTempEnv({
PORT: "8080",
LOG_LEVEL: "debug",
APP_BASE_URL: "https://xartaudio.app",
BETTER_AUTH_SECRET: "prod-secret",
BETTER_AUTH_BASE_PATH: "/api/auth",
BETTER_AUTH_DEV_PASSWORD: "xartaudio-dev-password",
CONVEX_DEPLOYMENT_URL: "https://example.convex.cloud",
CONVEX_AUTH_TOKEN: "convex-token",
CONVEX_STATE_QUERY: "state:get",
CONVEX_STATE_MUTATION: "state:put",
QWEN_TTS_MODEL: "qwen3-tts",
MINIO_ENDPOINT: "minio.internal",
MINIO_PORT: "9000",
MINIO_USE_SSL: "false",
MINIO_BUCKET: "audio",
MINIO_SIGNED_URL_TTL_SEC: "7200",
WEBHOOK_RPM: "77",
}, () => {
const { config } = require("../src/config");
assert.equal(config.port, 8080);
assert.equal(config.logLevel, "debug");
assert.equal(config.appBaseUrl, "https://xartaudio.app");
assert.equal(config.betterAuthSecret, "prod-secret");
assert.equal(config.convexDeploymentUrl, "https://example.convex.cloud");
assert.equal(config.convexAuthToken, "convex-token");
assert.equal(config.convexStateQuery, "state:get");
assert.equal(config.convexStateMutation, "state:put");
assert.equal(config.qwenTtsModel, "qwen3-tts");
assert.equal(config.minioEndPoint, "minio.internal");
assert.equal(config.minioPort, 9000);
assert.equal(config.minioUseSSL, false);
assert.equal(config.minioBucket, "audio");
assert.equal(config.minioSignedUrlTtlSec, 7200);
assert.equal(config.rateLimits.webhookPerMinute, 77);
});
});