/** * Test-only kody:runtime stand-in. Records secret writes and can inject * authorization / persistence failures. User-secret secretSet requires a * nonempty value, matching the package handler. */ export const writes = [] export const assertCalls = [] export const savedSecrets = { heyToken: 'old-access', heyRefreshToken: 'old-refresh', } const INITIAL_SECRETS = { heyToken: 'old-access', heyRefreshToken: 'old-refresh', } let assertOnlyError = null let persistFailuresRemaining = 0 let persistErrorMessage = 'secretSetMany persist failed' let secretSetManyEnabled = true function applyPersistedSecrets(secrets) { for (const secret of secrets || []) { if (typeof secret.value === 'string' && secret.value.length > 0) { savedSecrets[secret.name] = secret.value } } } async function secretSetManyImpl(input) { if (input.assertOnly) { assertCalls.push(input) if (assertOnlyError) throw assertOnlyError return { ok: true, assertOnly: true, secrets: input.secrets } } if (persistFailuresRemaining > 0) { persistFailuresRemaining -= 1 throw new Error(persistErrorMessage) } applyPersistedSecrets(input.secrets) writes.push({ op: 'secretSetMany', secrets: input.secrets, assertOnly: false }) return { ok: true, assertOnly: false, secrets: input.secrets } } export function resetKodySecrets() { writes.length = 0 assertCalls.length = 0 assertOnlyError = null persistFailuresRemaining = 0 persistErrorMessage = 'secretSetMany persist failed' secretSetManyEnabled = true savedSecrets.heyToken = INITIAL_SECRETS.heyToken savedSecrets.heyRefreshToken = INITIAL_SECRETS.heyRefreshToken } export function failAssertOnly(message = 'secretSetMany assertOnly failed') { assertOnlyError = new Error(message) } export function failPersist(times = Number.POSITIVE_INFINITY, message = 'secretSetMany persist failed') { persistFailuresRemaining = times persistErrorMessage = message } export function disableSecretSetMany() { secretSetManyEnabled = false } function rejectValuelessUserSecret(input) { const value = input?.value if (input?.scope === 'user' && !(typeof value === 'string' && value.length > 0)) { throw new Error('secretSet rejected a user-secret update without a nonempty value') } } export const kody = { async secretSet(input) { rejectValuelessUserSecret(input) savedSecrets[input.name] = input.value writes.push({ op: 'secretSet', ...input }) return { name: input.name, scope: input.scope || 'user' } }, } Object.defineProperty(kody, 'secretSetMany', { configurable: true, enumerable: true, get() { return secretSetManyEnabled ? secretSetManyImpl : undefined }, })