diff --git a/README.md b/README.md index efba1995..b5a06a5b 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,11 @@ latest styles. - Central place for instance-specific values like the Super Admin npub and the default whitelist-only mode setting. Update the documented exports here when preparing a new deployment. + - Tune `PLATFORM_FEE_PERCENT` (0–100) to keep a percentage of Lightning tips + and set `PLATFORM_LUD16_OVERRIDE` when you need a deployment-wide fallback + Lightning address. Leave the fee at `0` to pass through every satoshi. + - Populate `DEFAULT_RELAY_URLS_OVERRIDE` with WSS URLs to replace the bundled + relay bootstrap list. Keep it empty to stick with the upstream defaults. - **`config.js`**: - Toggle `isDevMode` for development (`true`) or production (`false`). - **`js/constants.js`**: diff --git a/config/instance-config.js b/config/instance-config.js index 6a1e86d4..eec179e2 100644 --- a/config/instance-config.js +++ b/config/instance-config.js @@ -25,6 +25,36 @@ export const ADMIN_SUPER_NPUB = "npub15jnttpymeytm80hatjqcvhhqhzrhx6gxp8pq0wn93rhnu8s9h9dsha32lx"; +/** + * Percentage of every Lightning payment the platform retains as a fee. + * + * Accepts numbers between 0 and 100 (inclusive). Decimals are supported when + * you want to keep a fractional cut—e.g., `2.5` represents a 2.5% fee. The + * default of `0` disables the fee so creators receive the full payment. + */ +export const PLATFORM_FEE_PERCENT = 0; + +/** + * Lightning address to fall back to when authors omit their own `lud16`. + * + * Supply a string like `"tips@example.com"` to force a deployment-wide + * fallback Lightning address, or leave the value as `null` to respect the + * creator’s configured profile metadata. + */ +export const PLATFORM_LUD16_OVERRIDE = null; + +/** + * Optional list of relays to seed new sessions with instead of the defaults. + * + * Provide WSS URLs (e.g., `"wss://relay.example.com"`). Leave the array empty + * to keep BitVid’s bundled defaults. Operators that need a custom bootstrap set + * should list the relays in priority order; entries later in the list are used + * as fallbacks when earlier relays fail. + */ +export const DEFAULT_RELAY_URLS_OVERRIDE = Object.freeze([ + // "wss://relay.example.com", +]); + /** * Storage key used to persist whitelist-only mode in the browser. * diff --git a/config/validate-config.js b/config/validate-config.js new file mode 100644 index 00000000..fb9b78b3 --- /dev/null +++ b/config/validate-config.js @@ -0,0 +1,49 @@ +// config/validate-config.js +// ----------------------------------------------------------------------------- +// Runtime validation helpers for instance-level configuration +// ----------------------------------------------------------------------------- + +import { ADMIN_SUPER_NPUB, PLATFORM_FEE_PERCENT } from "./instance-config.js"; + +function assertSuperAdminConfigured() { + if (typeof ADMIN_SUPER_NPUB !== "string") { + throw new Error( + "ADMIN_SUPER_NPUB must be a string exported from config/instance-config.js." + ); + } + + const trimmed = ADMIN_SUPER_NPUB.trim(); + if (!trimmed) { + throw new Error( + "ADMIN_SUPER_NPUB is required. Populate it with the Super Admin npub in config/instance-config.js." + ); + } + + if (!trimmed.startsWith("npub")) { + throw new Error( + "ADMIN_SUPER_NPUB should be a bech32 npub (e.g., starting with 'npub')." + ); + } +} + +function assertPlatformFeeInRange() { + const value = + typeof PLATFORM_FEE_PERCENT === "number" + ? PLATFORM_FEE_PERCENT + : Number.parseFloat(PLATFORM_FEE_PERCENT); + + if (!Number.isFinite(value)) { + throw new Error( + "PLATFORM_FEE_PERCENT must be a finite number between 0 and 100." + ); + } + + if (value < 0 || value > 100) { + throw new Error("PLATFORM_FEE_PERCENT must be between 0 and 100 inclusive."); + } +} + +export function validateInstanceConfig() { + assertSuperAdminConfigured(); + assertPlatformFeeInRange(); +} diff --git a/js/config.js b/js/config.js index 9e342839..f9c70c20 100644 --- a/js/config.js +++ b/js/config.js @@ -2,6 +2,9 @@ import { ADMIN_SUPER_NPUB, + PLATFORM_FEE_PERCENT, + PLATFORM_LUD16_OVERRIDE, + DEFAULT_RELAY_URLS_OVERRIDE, ADMIN_WHITELIST_MODE_STORAGE_KEY, DEFAULT_WHITELIST_MODE_ENABLED, WATCH_HISTORY_KIND, @@ -26,6 +29,9 @@ export const isDevMode = true; // Set to false for production export const ADMIN_LIST_MODE = "nostr"; export { ADMIN_SUPER_NPUB }; +export { PLATFORM_FEE_PERCENT }; +export { PLATFORM_LUD16_OVERRIDE }; +export { DEFAULT_RELAY_URLS_OVERRIDE }; export const ADMIN_EDITORS_NPUBS = []; // Default moderators (optional) export const ADMIN_LIST_NAMESPACE = "bitvid:admin"; // Reserved for Nostr lists diff --git a/js/index.js b/js/index.js index ec507044..c1224d2f 100644 --- a/js/index.js +++ b/js/index.js @@ -1,5 +1,6 @@ // js/index.js +import { validateInstanceConfig } from "../config/validate-config.js"; import "./bufferPolyfill.js"; import Application from "./app.js"; import { setApplication, setApplicationReady } from "./applicationContext.js"; @@ -7,6 +8,8 @@ import nostrService from "./services/nostrService.js"; import r2Service from "./services/r2Service.js"; import { loadView, viewInitRegistry } from "./viewManager.js"; +validateInstanceConfig(); + let application = null; let applicationReadyPromise = Promise.resolve();