sc-dev-deploy/lib/configStore.js
2026-06-17 17:37:16 -05:00

49 lines
1.8 KiB
JavaScript

// Durable per-tenant key/value storage in Saltcorn's _sc_config, used for the
// dev-deploy ENV IDENTITY (which is created during onLoad).
//
// Why _sc_config and not a registered table or the plugin config blob:
// - It survives backup: backup_config dumps every non-fixed _sc_config key,
// and restore_config restores them BEFORE install_pack runs the plugin's
// onLoad -- so the restored identity is already present when onLoad reads it
// (no onLoad-creates-then-restore-imports duplicate, which a registered
// table suffers because restore_tables runs AFTER onLoad).
// - It does NOT write the plugin's own _sc_plugins row (Plugin.upsert during
// onLoad cascades plugin re-loading and duplicates rows -- the reason the
// config-blob approach was abandoned). setConfig writes _sc_config only.
//
// Reads go DIRECT to _sc_config: getState().getConfig only surfaces keys that
// are in Saltcorn's known configTypes schema, so a custom plugin key is invisible
// through it even though it is stored and backed up. Writes go through setConfig
// (correct jsonb/text encoding on both backends; value wrapped as {v: ...}).
const db = require("@saltcorn/data/db");
const readKey = async (key) => {
const row = await db.selectMaybeOne("_sc_config", { key: key });
if (!row || row.value === null || row.value === undefined) {
return undefined;
}
let v = row.value;
if (typeof v === "string") {
try {
v = JSON.parse(v);
} catch (e) {
return undefined;
}
}
// Saltcorn wraps config values as { v: <value> }.
return v && typeof v === "object" && "v" in v ? v.v : v;
};
const writeKey = async (key, value) => {
const { getState } = require("@saltcorn/data/db/state");
await getState().setConfig(key, value);
};
module.exports = {
readKey,
writeKey
};