Skip to content
← Public packages

@danj/hey-email

HEY.com email for Kody: search threads, read messages, download PDF attachments, and write drafts. Sending is barred until you allow it.

test/kody-runtime-stub.js

93 lines · 2.6 KB · JavaScript
Raw
/**
 * 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
  },
})