import { sdk } from '../sdk' import { configFile } from '../file-models/config.json' const { InputSpec, Value } = sdk // The "operator key" is the shared secret that authenticates THIS Recaps // server to the Recap Relay for the core-decoupling cloud path. With it // set, the server vouches for its signed-in Pro/Max users by their Recaps // account-id (X-Recap-User-Id) — the relay owns their subscription tier, // keyed by that id, with NO per-user Keysat license involved. // // It MUST exactly match the value set on the relay (its // relay_cloud_operator_key, via the relay's own "Set Cloud Operator Key" // action). If the two don't match, the relay rejects the cloud calls and // paid users silently fall back to the operator's shared relay pool. // // Only meaningful when recap_mode === 'multi' (the cloud deployment). In // single mode there are no per-user accounts to vouch for, so the value // is ignored. const inputSpec = InputSpec.of({ operator_key: Value.text({ name: 'Relay Operator Key', description: 'Shared secret that authenticates this Recaps server to the Recap Relay. Must EXACTLY match the relay\'s "Cloud Operator Key". Generate a long random string (e.g. `openssl rand -hex 32`) and set the same value on both. Server-side only — never shown to users.', required: true, default: null, placeholder: 'paste the same key set on the relay', masked: true, minLength: 16, maxLength: 256, }), }) export const setRelayOperatorKey = sdk.Action.withInput( 'set-relay-operator-key', async ({ effects }) => ({ name: 'Set Relay Operator Key', description: 'Set the shared operator key that lets this Recaps server vouch for its Pro/Max users to the Recap Relay by account-id (core-decoupling). Must match the key set on the relay. Multi-tenant mode only.', warning: null, allowedStatuses: 'any', group: 'Multi-Tenant', visibility: 'enabled', }), inputSpec, async ({ effects }) => { const config = await configFile.read().once() return { operator_key: config?.recap_relay_operator_key || undefined } }, async ({ effects, input }) => { const key = (input.operator_key || '').trim() await configFile.merge(effects, { recap_relay_operator_key: key }) return null }, )