nodejs: lazy per-backend libsimplex download (#7543)

* ci: drop dlltool from nodejs libs release

* nodejs: download libsimplex into the user cache

* nodejs: load libsimplex at runtime per backend

* support bot: select db backend with --db

* python: match backend switch error text

* nodejs: download prebuilt add-on at runtime

* ci: build nodejs add-on for libs release

* calculator bot: load libs and add-on in image

* support bot: document add-on override

* nodejs: keep worker test output free of colors

* nodejs: verify sha-256 of downloaded assets

* python: pin core libs release with sha-256

* ci: add packages release script

* ci: release nodejs add-on and open release PR

* ci: publish packages after release PR

* nodejs: keep npm from building the add-on

* calculator bot: build the add-on in the image

* ci: merge package release workflows

* ci: open release PR when publishing fails

* ci: build the add-on with node-addon-api only

* ci: skip publishing in a called packages workflow

* ci: update package release actions to Node 24

* nodejs: fix receive test timeout

* ci: test packages on pull requests

* nodejs: reuse the database in the close stress test

* ci: keep failed package tests from hanging

* ci: skip preset server tests

* ci: plan package builds from the changes

* ci: test packages with a given libsimplex

* ci: test packages with libsimplex of core changes
This commit is contained in:
sh authored and GitHub committed 2026-10-14 09:53:53 +01:00
1 parent 2f4a443dda
commit f65c2da587
73 files changed
+2823 -650

No files matched your search

+10 -22
View File
@@ -1,4 +1,4 @@
import {Command} from "commander"
import {Command, Option} from "commander"
import {api} from "simplex-chat"
export interface IdName {
@@ -6,8 +6,6 @@ export interface IdName {
name: string
}
export type Backend = "sqlite" | "postgres"
export interface Config {
stateFile: string // local path to the bot's state JSON
db: api.DbConfig // passed to ChatApi.init / bot.run
@@ -21,18 +19,6 @@ export interface Config {
grokApiKey: string | null
}
// Mirrors packages/simplex-chat-nodejs/src/download-libs.js so runtime detection
// matches what was used at install time. Works whether the user installed via
// SIMPLEX_BACKEND env var, .npmrc (→ npm_config_simplex_backend), or the
// --simplex_backend=postgres CLI flag (also surfaced as npm_config_*).
export function detectBackend(): Backend {
const raw = (process.env.SIMPLEX_BACKEND || process.env.npm_config_simplex_backend || "sqlite").toLowerCase()
if (raw !== "sqlite" && raw !== "postgres") {
throw new Error(`Invalid SIMPLEX_BACKEND: "${raw}". Must be "sqlite" or "postgres".`)
}
return raw
}
export function parseIdName(s: string): IdName {
const i = s.indexOf(":")
if (i < 1) throw new Error(`Invalid ID:name format: "${s}"`)
@@ -57,21 +43,23 @@ function buildCommand(): Command {
.description("business-address triage bot")
.requiredOption("--team-group <name>", "team group display name")
.option("--state-file <path>", "state JSON path", "./data/state.json")
.addOption(new Option("--db <backend>", "database backend").choices(["sqlite", "postgres"]).default("sqlite"))
.option("--sqlite-file-prefix <path>", "SQLite DB file prefix", "./data/simplex")
.option("--sqlite-key <key>", "SQLCipher encryption key (default: unencrypted)")
.option("--pg-conn <conn>", "PostgreSQL connection string (required for postgres)")
.option("--pg-conn <conn>", "PostgreSQL connection string (required with --db postgres)")
.option("--pg-schema <prefix>", "PostgreSQL schema prefix (default: simplex_v1)")
.option("-a, --auto-add-team-members <list>", "comma-separated ID:name pairs (e.g. 1:Alice,2:Bob)")
.option("--timezone <iana>", "IANA timezone for weekend detection", "UTC")
.option("--complete-hours <n>", "auto-complete chats after N hours idle (0 disables)", parseNonNegativeInt("--complete-hours"), 3)
.option("--card-flush-seconds <n>", "debounce card state writes", parseNonNegativeInt("--card-flush-seconds"), 300)
.option("--context-file <path>", "text file with Grok system context (required if GROK_API_KEY set)")
.addHelpText("after", "\nEnvironment:\n GROK_API_KEY xAI API key — enables Grok replies\n SIMPLEX_BACKEND sqlite | postgres — alternative to .npmrc for backend selection\n")
.addHelpText("after", "\nEnvironment:\n GROK_API_KEY xAI API key — enables Grok replies\n SIMPLEX_LIBS_DIR local libsimplex build for the --db backend\n SIMPLEX_ADDON_PATH locally built Node.js add-on\n")
}
interface RawOpts {
teamGroup: string
stateFile: string
db: api.DbConfig["type"]
sqliteFilePrefix: string
sqliteKey?: string
pgConn?: string
@@ -93,19 +81,19 @@ export function parseConfig(args: string[]): Config {
throw err
}
const opts = cmd.opts<RawOpts>()
const given = (option: keyof RawOpts) => cmd.getOptionValueSource(option) === "cli"
const grokApiKey = process.env.GROK_API_KEY || null
const backend = detectBackend()
let db: api.DbConfig
if (backend === "sqlite") {
if (opts.db === "sqlite") {
if (given("pgConn") || given("pgSchema")) throw new Error("--pg-conn and --pg-schema require --db postgres")
db = opts.sqliteKey
? {type: "sqlite", filePrefix: opts.sqliteFilePrefix, encryptionKey: opts.sqliteKey}
: {type: "sqlite", filePrefix: opts.sqliteFilePrefix}
} else {
if (!opts.pgConn) {
throw new Error("--pg-conn is required when backend is postgres (PostgreSQL connection string)")
}
if (given("sqliteFilePrefix") || given("sqliteKey")) throw new Error("--sqlite-file-prefix and --sqlite-key require --db sqlite")
if (!opts.pgConn) throw new Error("--pg-conn is required with --db postgres")
db = opts.pgSchema
? {type: "postgres", connectionString: opts.pgConn, schemaPrefix: opts.pgSchema}
: {type: "postgres", connectionString: opts.pgConn}