{"version":3,"sources":["../src/index.ts","../src/deprecation.ts","../src/errors.ts","../src/version.ts","../src/http.ts","../src/client.ts","../src/generated/signpost-taxonomy.ts","../src/generated/oversight-taxonomy.ts","../src/types.ts","../src/webhook.ts"],"sourcesContent":["/**\n * NOPE Node SDK\n *\n * Safety layer for chat & LLMs. Analyzes conversations for mental-health\n * and safeguarding risk.\n *\n * @example\n * ```typescript\n * import { NopeClient } from '@nope-net/sdk';\n *\n * const client = new NopeClient({ apiKey: 'nope_live_...' });\n * const result = await client.evaluate({\n *   messages: [{ role: 'user', content: \"I'm feeling down\" }],\n *   config: { country: 'US' }\n * });\n *\n * console.log(`Severity: ${result.speaker_severity}`);\n * if (result.show_resources && result.resources) {\n *   console.log(`  ${result.resources.primary.name}: ${result.resources.primary.phone}`);\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n// Client\nexport { NopeClient } from './client.js';\n\n// Errors\nexport {\n  NopeError,\n  NopeAuthError,\n  NopeValidationError,\n  NopeInsufficientBalanceError,\n  NopeFeatureError,\n  NopeNotFoundError,\n  NopeRateLimitError,\n  NopeServerError,\n  NopeServiceUnavailableError,\n  NopeConnectionError,\n} from './errors.js';\n\nexport type {\n  ApiErrorBody,\n  NopeErrorOptions,\n  NopeValidationErrorOptions,\n  NopeInsufficientBalanceErrorOptions,\n  NopeFeatureErrorOptions,\n  NopeRateLimitErrorOptions,\n  NopeServerErrorOptions,\n} from './errors.js';\n\n// Transport types\nexport type { FetchLike, SleepFn, ResponseMeta } from './http.js';\nexport { MAX_RETRY_WAIT_SECONDS } from './http.js';\n\n// Version\nexport { SDK_VERSION } from './version.js';\n\n// Types\nexport type {\n  // Enums/Literals\n  Severity,\n  Imminence,\n  RiskSubject,\n  ScreenRiskSubject,\n  RiskType,\n  CrisisResourceType,\n  CrisisResourceKind,\n  CrisisResourcePriorityTier,\n  HoursConfidence,\n  ResourceProminence,\n  // Request types\n  Message,\n  EvaluateConfig,\n  EvaluateRequest,\n  // Core response types\n  EvaluateResponse,\n  EvaluateMetadata,\n  EvaluateResource,\n  EvaluateResources,\n  Risk,\n  // Supporting types\n  CrisisResource,\n  OtherContact,\n  OpenStatus,\n  // Client options\n  NopeClientOptions,\n  EvaluateOptions,\n  // Screen types\n  ScreenConfig,\n  ScreenOptions,\n  ScreenResponse,\n  ScreenRisk,\n  ScreenRecommendedReply,\n  ScreenCrisisResources,\n  ScreenDebugInfo,\n  // Signpost types\n  RankedResource,\n  SignpostConfig,\n  SignpostOptions,\n  SignpostResponse,\n  SignpostSmartConfig,\n  SignpostSmartOptions,\n  SignpostSmartResponse,\n  SignpostByIdResponse,\n  SignpostCountriesResponse,\n  DetectCountryOptions,\n  DetectCountryResponse,\n  DetectCountryResult,\n  // Signpost search types\n  SignpostSearchOptions,\n  SignpostSearchContact,\n  SignpostSearchOpenStatus,\n  SignpostSearchResult,\n  SignpostSearchResponse,\n  // Deprecated /v1/resources/* aliases (sunset 2027-01-01)\n  ResourcesConfig,\n  ResourcesOptions,\n  ResourcesResponse,\n  ResourcesSmartOptions,\n  ResourcesSmartResponse,\n  ResourceByIdResponse,\n  ResourcesCountriesResponse,\n  // Ocular types\n  OcularOptions,\n  OcularResponse,\n  OcularDemoResponse,\n  OcularResponseFor,\n  OcularThoroughness,\n  OcularLevel,\n  OcularPhase,\n  OcularAxis,\n  OcularAxisGroup,\n  OcularSignals,\n  OcularStability,\n  OcularTrajectoryEntry,\n  OcularDemoTrajectoryEntry,\n  OcularTrajectoryShape,\n  OcularHead,\n  OcularMeta,\n  // Oversight types\n  ConcernLevel,\n  Trajectory,\n  OversightSeverity,\n  HumanIndicatorType,\n  OversightMessage,\n  OversightConversationMetadata,\n  OversightConversation,\n  DetectedBehavior,\n  AggregatedBehavior,\n  TurnAnalysis,\n  HumanIndicator,\n  WindowAnalysis,\n  InflectionPoint,\n  OversightBehaviorFilter,\n  OversightAnalysisResult,\n  OversightAnalysisStrategy,\n  OversightAnalysisMode,\n  OversightAnalyzeConfig,\n  OversightAnalyzeOptions,\n  OversightAnalyzeResponse,\n  OversightDemoAnalyzeResponse,\n  OversightAnalyzeResponseFor,\n  OversightIngestConfig,\n  OversightIngestConversation,\n  OversightIngestOptions,\n  OversightIngestConversationResult,\n  OversightIngestError,\n  OversightIngestResponse,\n  TruncationWarning,\n  // Billing types\n  BillingBalanceResponse,\n  BillingTopupOption,\n  BillingTopupRecord,\n  BillingUsageOptions,\n  BillingUsageBreakdown,\n  BillingUsageResponse,\n  BillingUsageHistoryOptions,\n  BillingUsageRecord,\n  BillingUsageHistoryResponse,\n  BillingPricingEntry,\n  BillingPricingTable,\n  BillingPricingResponse,\n  BillingTopupOptions,\n  BillingTopupResponse,\n} from './types.js';\n\n// Generated Signpost vocabularies (from the API source; see scripts/generate-taxonomy.ts)\nexport type { ServiceScope, Population } from './generated/signpost-taxonomy.js';\nexport { SERVICE_SCOPES, POPULATIONS } from './generated/signpost-taxonomy.js';\n\n// Generated Oversight taxonomy (from the API source; see scripts/generate-taxonomy.ts)\nexport type { OversightBehaviorCode, OversightBehaviorCategory } from './generated/oversight-taxonomy.js';\nexport {\n  OVERSIGHT_BEHAVIOR_CODES,\n  OVERSIGHT_BEHAVIOR_CATEGORIES,\n  OVERSIGHT_BEHAVIOR_CODES_BY_CATEGORY,\n} from './generated/oversight-taxonomy.js';\n\n// Utility functions and constants\nexport {\n  SEVERITY_SCORES,\n  IMMINENCE_SCORES,\n  calculateSpeakerSeverity,\n  calculateSpeakerImminence,\n  hasThirdPartyRisk,\n} from './types.js';\n\n// Webhook verification\nexport {\n  Webhook,\n  WebhookSignatureError,\n} from './webhook.js';\n\nexport type {\n  WebhookEventType,\n  WebhookRiskLevel,\n  WebhookPayload,\n  WebhookPayloadBase,\n  EvaluateAlertPayload,\n  OversightAlertPayload,\n  OversightAlertBehavior,\n  OversightIngestionCompletePayload,\n  TestPingPayload,\n  WebhookRiskSummary,\n  WebhookDomainAssessment,\n  WebhookFlags,\n  WebhookResourceProvided,\n  WebhookConversation,\n  WebhookVerifyOptions,\n  WebhookBody,\n  WebhookHeaders,\n  VerifiedWebhook,\n  // Webhook management types\n  WebhookCreateOptions,\n  WebhookUpdateOptions,\n  WebhookResponse,\n  WebhookListResponse,\n  WebhookDeleteResponse,\n  WebhookSecretResponse,\n  WebhookDeliveryResult,\n  WebhookDeliveryStatus,\n  WebhookEvent,\n  WebhookEventsOptions,\n  WebhookEventsResponse,\n} from './webhook.js';\n","/**\n * Once-per-process deprecation warnings.\n *\n * Each distinct message is written to console.warn a single time, so a hot\n * loop over a deprecated method does not flood the logs.\n */\n\nconst warned = new Set<string>();\n\n/** Emit `message` through console.warn the first time it is seen. */\nexport function warnOnce(key: string, message: string): void {\n  if (warned.has(key)) return;\n  warned.add(key);\n  console.warn(`[NOPE SDK] ${message}`);\n}\n\n/** Test hook: forget every warning issued so far. Not part of the public API. */\nexport function _resetDeprecationWarningsForTests(): void {\n  warned.clear();\n}\n","/**\n * NOPE SDK errors.\n *\n * Every error carries `statusCode` (HTTP status; absent for connection\n * failures and for requests the SDK rejected before sending), `code` (the\n * API's machine string when the body's `error` field looks like one, e.g.\n * `insufficient_balance`; `invalid_request` or `not_available_in_demo` for\n * client-side rejections), `message` (the API's human sentence when present),\n * `responseBody` (the raw response text) and `body` (the parsed JSON object\n * when the response was one).\n */\n\n/**\n * Shape of a NOPE API error body. `error` is either a machine code\n * (`rate_limit_exceeded`) or a sentence; `message` carries the sentence when\n * `error` is a code. Any other keys are endpoint-specific extras\n * (`max_bytes`, `invalid_scopes`, `balance`, `upgrade_url`, ...).\n */\nexport interface ApiErrorBody {\n  error: string;\n  message?: string;\n  [key: string]: unknown;\n}\n\nexport interface NopeErrorOptions {\n  /** HTTP status of the response. */\n  statusCode?: number;\n  /** Machine code from the body's `error` field, when it is one. */\n  code?: string;\n  /** Raw response body text. */\n  responseBody?: string;\n  /** Parsed response body, when the text was a JSON object. */\n  body?: Record<string, unknown>;\n}\n\n/**\n * Base class for all NOPE SDK errors.\n */\nexport class NopeError extends Error {\n  readonly statusCode?: number;\n  readonly code?: string;\n  /** Raw response body text. Absent when no response was received. */\n  readonly responseBody?: string;\n  /**\n   * The response body parsed as JSON, when it was a JSON object. Absent for\n   * non-JSON bodies, for connection failures and for client-side\n   * rejections. `responseBody` keeps the raw text either way.\n   */\n  readonly body?: Record<string, unknown>;\n\n  constructor(message: string, options: NopeErrorOptions = {}) {\n    super(message);\n    this.name = 'NopeError';\n    this.statusCode = options.statusCode;\n    this.code = options.code;\n    this.responseBody = options.responseBody;\n    this.body = options.body;\n    if (Error.captureStackTrace) {\n      Error.captureStackTrace(this, new.target);\n    }\n  }\n\n  override toString(): string {\n    return this.statusCode ? `[${this.statusCode}] ${this.message}` : this.message;\n  }\n}\n\n/**\n * Authentication failed (HTTP 401): the API key is missing, malformed,\n * revoked, or unknown.\n */\nexport class NopeAuthError extends NopeError {\n  constructor(message = 'Invalid or missing API key', options: Omit<NopeErrorOptions, 'statusCode'> = {}) {\n    super(message, { ...options, statusCode: 401 });\n    this.name = 'NopeAuthError';\n  }\n}\n\nexport interface NopeValidationErrorOptions extends NopeErrorOptions {\n  /** Endpoint-specific extras from the body (everything except `error` and `message`). */\n  details?: Record<string, unknown>;\n}\n\n/**\n * The request was rejected. Three sources:\n *\n * - HTTP 400 (invalid request) or 413 (body over the 512 KB limit):\n *   `statusCode` is the status and `details` carries the body's extra keys,\n *   for example `max_bytes`, `max_messages`, `max_content_length`,\n *   `invalid_scopes`, `hint`, `details`.\n * - Client-side validation (an empty `messages` array, a role other than\n *   `user` or `assistant`, more than 100 messages, neither `messages` nor\n *   `text`, and the other checks each method documents): thrown before any\n *   request is sent, so `statusCode` is undefined; `code` is\n *   `'invalid_request'` and `details` is empty.\n * - A method refused on a demo client: also thrown before any request,\n *   `statusCode` undefined, `code` `'not_available_in_demo'`.\n */\nexport class NopeValidationError extends NopeError {\n  readonly details: Record<string, unknown>;\n\n  constructor(message = 'Invalid request', options: NopeValidationErrorOptions = {}) {\n    const { details, ...rest } = options;\n    // 400 unless the caller names a status. Client-side rejections pass\n    // `statusCode: undefined` on purpose: there was no response.\n    super(message, { ...rest, statusCode: 'statusCode' in options ? options.statusCode : 400 });\n    this.name = 'NopeValidationError';\n    this.details = details ?? {};\n  }\n}\n\nexport interface NopeInsufficientBalanceErrorOptions extends Omit<NopeErrorOptions, 'statusCode'> {\n  balanceMills?: number;\n  requiredMills?: number;\n  formattedCurrent?: string;\n  formattedRequired?: string;\n  topupUrl?: string;\n  /** Oversight ingest only: cost per conversation. */\n  perConversationMills?: number;\n  /** Oversight ingest only: number of conversations in the rejected batch. */\n  conversations?: number;\n}\n\n/**\n * The account balance cannot cover the call (HTTP 402). Top up at `topupUrl`.\n */\nexport class NopeInsufficientBalanceError extends NopeError {\n  readonly balanceMills?: number;\n  readonly requiredMills?: number;\n  readonly formattedCurrent?: string;\n  readonly formattedRequired?: string;\n  readonly topupUrl?: string;\n  readonly perConversationMills?: number;\n  readonly conversations?: number;\n\n  constructor(message = 'Insufficient balance', options: NopeInsufficientBalanceErrorOptions = {}) {\n    const {\n      balanceMills,\n      requiredMills,\n      formattedCurrent,\n      formattedRequired,\n      topupUrl,\n      perConversationMills,\n      conversations,\n      ...rest\n    } = options;\n    super(message, { ...rest, statusCode: 402 });\n    this.name = 'NopeInsufficientBalanceError';\n    this.balanceMills = balanceMills;\n    this.requiredMills = requiredMills;\n    this.formattedCurrent = formattedCurrent;\n    this.formattedRequired = formattedRequired;\n    this.topupUrl = topupUrl;\n    this.perConversationMills = perConversationMills;\n    this.conversations = conversations;\n  }\n}\n\nexport interface NopeFeatureErrorOptions extends Omit<NopeErrorOptions, 'statusCode'> {\n  feature?: string;\n  requiredAccess?: string;\n  upgradeUrl?: string;\n}\n\n/**\n * The account lacks access to a feature (HTTP 403).\n *\n * Two shapes on the wire: a gated feature (`feature`, `requiredAccess`; for\n * example Oversight) and a paid-plan gate (`feature` is `'paid_plan'` and\n * `upgradeUrl` points at the dashboard).\n */\nexport class NopeFeatureError extends NopeError {\n  readonly feature?: string;\n  readonly requiredAccess?: string;\n  readonly upgradeUrl?: string;\n\n  constructor(message = 'Feature not enabled for this account', options: NopeFeatureErrorOptions = {}) {\n    const { feature, requiredAccess, upgradeUrl, ...rest } = options;\n    super(message, { ...rest, statusCode: 403 });\n    this.name = 'NopeFeatureError';\n    this.feature = feature;\n    this.requiredAccess = requiredAccess;\n    this.upgradeUrl = upgradeUrl;\n  }\n\n  override toString(): string {\n    const base = super.toString();\n    return this.feature ? `${base} (feature: ${this.feature})` : base;\n  }\n}\n\n/**\n * The resource does not exist (HTTP 404): an unknown signpost id or webhook id.\n */\nexport class NopeNotFoundError extends NopeError {\n  constructor(message = 'Not found', options: Omit<NopeErrorOptions, 'statusCode'> = {}) {\n    super(message, { ...options, statusCode: 404 });\n    this.name = 'NopeNotFoundError';\n  }\n}\n\nexport interface NopeRateLimitErrorOptions extends Omit<NopeErrorOptions, 'statusCode'> {\n  retryAfter?: number;\n  limit?: number;\n  remaining?: number;\n  reset?: number;\n}\n\n/**\n * Rate limit exceeded (HTTP 429).\n *\n * `retryAfter` is in seconds (from the `Retry-After` header, else the body's\n * `retry_after_seconds`). The client retries 429s itself up to `maxRetries`\n * before raising this.\n */\nexport class NopeRateLimitError extends NopeError {\n  /** Seconds until the limit resets. */\n  readonly retryAfter?: number;\n  /** Requests allowed per window. */\n  readonly limit?: number;\n  /** Requests left in the window (0 when rate limited). */\n  readonly remaining?: number;\n  /** Window reset time as epoch milliseconds. */\n  readonly reset?: number;\n\n  constructor(message = 'Rate limit exceeded', options: NopeRateLimitErrorOptions = {}) {\n    const { retryAfter, limit, remaining, reset, ...rest } = options;\n    super(message, { ...rest, statusCode: 429 });\n    this.name = 'NopeRateLimitError';\n    this.retryAfter = retryAfter;\n    this.limit = limit;\n    this.remaining = remaining;\n    this.reset = reset;\n  }\n\n  override toString(): string {\n    const base = super.toString();\n    return this.retryAfter !== undefined ? `${base} (retry after ${this.retryAfter}s)` : base;\n  }\n}\n\nexport interface NopeServerErrorOptions extends NopeErrorOptions {\n  /** Seconds suggested by a `Retry-After` header, when one was sent. */\n  retryAfter?: number;\n}\n\n/**\n * The API failed (HTTP 5xx other than 503). Not retried by the client: paid\n * routes charge before the handler runs, so a blind retry could double-bill.\n */\nexport class NopeServerError extends NopeError {\n  readonly retryAfter?: number;\n\n  constructor(message = 'Server error', options: NopeServerErrorOptions = {}) {\n    const { retryAfter, ...rest } = options;\n    super(message, { statusCode: 500, ...rest });\n    this.name = 'NopeServerError';\n    this.retryAfter = retryAfter;\n  }\n}\n\n/**\n * A dependency or provider is temporarily unavailable (HTTP 503).\n *\n * Retryable: the client retries 503s itself up to `maxRetries`, waiting\n * `retryAfter` seconds, before raising this.\n */\nexport class NopeServiceUnavailableError extends NopeServerError {\n  constructor(message = 'Service unavailable', options: Omit<NopeServerErrorOptions, 'statusCode'> = {}) {\n    super(message, { ...options, statusCode: 503 });\n    this.name = 'NopeServiceUnavailableError';\n  }\n}\n\n/**\n * The request never produced a response: DNS, TCP, TLS failure, or the\n * client-side timeout. Not retried by the client (see NopeServerError).\n */\nexport class NopeConnectionError extends NopeError {\n  readonly originalError?: Error;\n\n  constructor(message = 'Failed to connect to NOPE API', originalError?: Error) {\n    super(message);\n    this.name = 'NopeConnectionError';\n    this.originalError = originalError;\n  }\n}\n","/**\n * SDK version, inlined from package.json at build time (tsup `define`) and\n * at test time (vitest `define`). package.json is the single source.\n */\ndeclare const __NOPE_SDK_VERSION__: string;\n\nexport const SDK_VERSION: string = __NOPE_SDK_VERSION__;\n\n/** User-Agent header sent on every request. */\nexport const USER_AGENT = `nope-node/${SDK_VERSION}`;\n","/**\n * HTTP transport: request building, timeout, retry policy, response meta and\n * error mapping. NopeClient delegates every call here.\n */\n\nimport {\n  NopeAuthError,\n  NopeConnectionError,\n  NopeError,\n  NopeFeatureError,\n  NopeInsufficientBalanceError,\n  NopeNotFoundError,\n  NopeRateLimitError,\n  NopeServerError,\n  NopeServiceUnavailableError,\n  NopeValidationError,\n} from './errors.js';\nimport { USER_AGENT } from './version.js';\n\n/** Minimal fetch signature the client needs. The global `fetch` satisfies it. */\nexport type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;\n\n/** Sleep used between retries. Injectable for tests. */\nexport type SleepFn = (ms: number) => Promise<void>;\n\n/** Rate-limit and balance headers from the last response. */\nexport interface ResponseMeta {\n  /** HTTP status of the last response. */\n  status: number;\n  /** From X-RateLimit-Limit / -Remaining / -Reset (reset is epoch ms). Absent when the headers are. */\n  rateLimit?: { limit: number; remaining: number; reset: number };\n  /** From X-Balance-Mills / X-Cost-Mills. Present only on paid routes. */\n  balance?: { balanceMills: number; costMills: number };\n}\n\nexport interface TransportOptions {\n  baseUrl: string;\n  apiKey?: string;\n  timeout: number;\n  maxRetries: number;\n  fetch?: FetchLike;\n  sleep?: SleepFn;\n}\n\nexport interface RequestOptions {\n  /** JSON body (POST/PUT). */\n  body?: unknown;\n  /** Query string; undefined values are skipped. */\n  query?: Record<string, string | number | boolean | undefined>;\n  /** Extra request headers. */\n  headers?: Record<string, string>;\n  /** Non-2xx statuses returned to the caller instead of raised. */\n  acceptStatuses?: number[];\n}\n\nexport interface RawResult<T> {\n  status: number;\n  body: T;\n}\n\n/** Longest single wait between retries. */\nexport const MAX_RETRY_WAIT_SECONDS = 30;\n\nconst RETRYABLE_STATUSES = new Set([429, 503]);\nconst CODE_PATTERN = /^[a-z_]+$/;\n\nconst defaultSleep: SleepFn = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n\nfunction toNumber(value: string | null | undefined): number | undefined {\n  if (value === null || value === undefined || value === '') return undefined;\n  const n = Number(value);\n  return Number.isFinite(n) ? n : undefined;\n}\n\nfunction numberField(body: Record<string, unknown> | undefined, key: string): number | undefined {\n  const v = body?.[key];\n  return typeof v === 'number' ? v : undefined;\n}\n\nfunction stringField(obj: Record<string, unknown> | undefined, key: string): string | undefined {\n  const v = obj?.[key];\n  return typeof v === 'string' ? v : undefined;\n}\n\n/** Parse an error body; undefined when the text is not a JSON object. */\nexport function parseErrorBody(text: string): Record<string, unknown> | undefined {\n  try {\n    const parsed = JSON.parse(text) as unknown;\n    if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n      return parsed as Record<string, unknown>;\n    }\n  } catch {\n    // not JSON\n  }\n  return undefined;\n}\n\n/** Retry-After in seconds: header first, then body `retry_after_seconds`. */\nexport function parseRetryAfter(headers: Headers, body: Record<string, unknown> | undefined): number | undefined {\n  return toNumber(headers.get('retry-after')) ?? numberField(body, 'retry_after_seconds');\n}\n\n/** Build the response meta side-channel from the response headers. */\nexport function buildResponseMeta(status: number, headers: Headers): ResponseMeta {\n  const limit = toNumber(headers.get('x-ratelimit-limit'));\n  const balanceMills = toNumber(headers.get('x-balance-mills'));\n  return {\n    status,\n    rateLimit:\n      limit === undefined\n        ? undefined\n        : {\n            limit,\n            remaining: toNumber(headers.get('x-ratelimit-remaining')) ?? 0,\n            reset: toNumber(headers.get('x-ratelimit-reset')) ?? 0,\n          },\n    balance:\n      balanceMills === undefined\n        ? undefined\n        : { balanceMills, costMills: toNumber(headers.get('x-cost-mills')) ?? 0 },\n  };\n}\n\n/** Map a non-2xx response to the SDK error class for its status. */\nexport function mapErrorResponse(status: number, statusText: string, headers: Headers, text: string): NopeError {\n  const body = parseErrorBody(text);\n  const errorField = typeof body?.error === 'string' ? body.error : undefined;\n  // An explicit machine code wins (Oversight validation bodies send {error: sentence, code});\n  // otherwise `error` is the code only when it looks like one.\n  const explicitCode = stringField(body, 'code');\n  const code = explicitCode || (errorField && CODE_PATTERN.test(errorField) ? errorField : undefined);\n  const message =\n    (typeof body?.message === 'string' ? body.message : undefined) ??\n    errorField ??\n    (text || statusText || `HTTP ${status}`);\n  const base = { code, responseBody: text, body };\n\n  switch (status) {\n    case 400:\n    case 413: {\n      const details: Record<string, unknown> = {};\n      for (const [k, v] of Object.entries(body ?? {})) {\n        if (k !== 'error' && k !== 'message' && k !== 'code') details[k] = v;\n      }\n      return new NopeValidationError(message, { ...base, statusCode: status, details });\n    }\n    case 401:\n      return new NopeAuthError(message, base);\n    case 402: {\n      const balance = (body?.balance ?? {}) as Record<string, unknown>;\n      const num = (k: string) => (typeof balance[k] === 'number' ? (balance[k] as number) : undefined);\n      return new NopeInsufficientBalanceError(message, {\n        ...base,\n        balanceMills: num('current_mills'),\n        requiredMills: num('required_mills'),\n        formattedCurrent: stringField(balance, 'formatted_current'),\n        formattedRequired: stringField(balance, 'formatted_required'),\n        topupUrl: stringField(body, 'topup_url'),\n        perConversationMills: num('per_conversation_mills'),\n        conversations: num('conversations'),\n      });\n    }\n    case 403: {\n      const feature = stringField(body, 'feature');\n      const upgradeUrl = stringField(body, 'upgrade_url');\n      if (feature) {\n        return new NopeFeatureError(message, {\n          ...base,\n          feature,\n          requiredAccess: stringField(body, 'required_access'),\n          upgradeUrl,\n        });\n      }\n      if (upgradeUrl) {\n        return new NopeFeatureError(message, { ...base, feature: 'paid_plan', upgradeUrl });\n      }\n      return new NopeError(message, { ...base, statusCode: 403 });\n    }\n    case 404:\n      return new NopeNotFoundError(message, base);\n    case 429:\n      return new NopeRateLimitError(message, {\n        ...base,\n        retryAfter: parseRetryAfter(headers, body),\n        limit: numberField(body, 'limit') ?? toNumber(headers.get('x-ratelimit-limit')),\n        remaining: numberField(body, 'remaining') ?? toNumber(headers.get('x-ratelimit-remaining')),\n        reset: numberField(body, 'reset') ?? toNumber(headers.get('x-ratelimit-reset')),\n      });\n    case 503:\n      return new NopeServiceUnavailableError(message, { ...base, retryAfter: parseRetryAfter(headers, body) });\n    default:\n      if (status >= 500) {\n        return new NopeServerError(message, {\n          ...base,\n          statusCode: status,\n          retryAfter: toNumber(headers.get('retry-after')),\n        });\n      }\n      return new NopeError(message, { ...base, statusCode: status });\n  }\n}\n\nexport class Transport {\n  readonly baseUrl: string;\n  private readonly apiKey?: string;\n  private readonly timeout: number;\n  private readonly maxRetries: number;\n  private readonly fetchImpl: FetchLike;\n  private readonly sleep: SleepFn;\n\n  /** Rate-limit and balance headers from the most recent response. */\n  lastResponseMeta?: ResponseMeta;\n\n  constructor(options: TransportOptions) {\n    this.baseUrl = options.baseUrl.replace(/\\/+$/, '');\n    this.apiKey = options.apiKey;\n    this.timeout = options.timeout;\n    this.maxRetries = Math.max(0, options.maxRetries);\n    // Resolve the global lazily so a fetch polyfill installed after import still works.\n    this.fetchImpl = options.fetch ?? ((input, init) => fetch(input, init));\n    this.sleep = options.sleep ?? defaultSleep;\n  }\n\n  /** Perform a request and return the parsed JSON body. */\n  async request<T>(method: string, path: string, options: RequestOptions = {}): Promise<T> {\n    const result = await this.requestRaw<T>(method, path, options);\n    return result.body;\n  }\n\n  /** Perform a request and return status plus parsed body (for accepted non-2xx statuses). */\n  async requestRaw<T>(method: string, path: string, options: RequestOptions = {}): Promise<RawResult<T>> {\n    const url = this.buildUrl(path, options.query);\n    const headers: Record<string, string> = {\n      'User-Agent': USER_AGENT,\n      ...(options.headers ?? {}),\n    };\n    if (this.apiKey) headers['Authorization'] = `Bearer ${this.apiKey}`;\n    const body = options.body === undefined ? undefined : JSON.stringify(options.body);\n    if (body !== undefined) headers['Content-Type'] = 'application/json';\n    const accept = new Set(options.acceptStatuses ?? []);\n\n    for (let attempt = 0; ; attempt++) {\n      const response = await this.send(url, { method, headers, body });\n      const text = await response.text();\n      this.lastResponseMeta = buildResponseMeta(response.status, response.headers);\n\n      if (response.ok || accept.has(response.status)) {\n        try {\n          return { status: response.status, body: JSON.parse(text) as T };\n        } catch {\n          throw new NopeError('Invalid JSON response', { statusCode: response.status, responseBody: text });\n        }\n      }\n\n      if (RETRYABLE_STATUSES.has(response.status) && attempt < this.maxRetries) {\n        const hinted = parseRetryAfter(response.headers, parseErrorBody(text));\n        const waitSeconds = Math.min(hinted ?? 2 ** attempt, MAX_RETRY_WAIT_SECONDS);\n        await this.sleep(waitSeconds * 1000);\n        continue;\n      }\n\n      throw mapErrorResponse(response.status, response.statusText, response.headers, text);\n    }\n  }\n\n  private buildUrl(path: string, query?: RequestOptions['query']): string {\n    const params = new URLSearchParams();\n    for (const [k, v] of Object.entries(query ?? {})) {\n      if (v !== undefined) params.set(k, String(v));\n    }\n    const qs = params.toString();\n    return `${this.baseUrl}${path}${qs ? `?${qs}` : ''}`;\n  }\n\n  private async send(url: string, init: { method: string; headers: Record<string, string>; body?: string }): Promise<Response> {\n    const controller = new AbortController();\n    const timer = setTimeout(() => controller.abort(), this.timeout);\n    try {\n      return await this.fetchImpl(url, { ...init, signal: controller.signal });\n    } catch (error) {\n      if (error instanceof Error) {\n        if (error.name === 'AbortError') {\n          throw new NopeConnectionError(`Request timed out after ${this.timeout}ms`, error);\n        }\n        throw new NopeConnectionError(`Failed to connect to ${this.baseUrl}: ${error.message}`, error);\n      }\n      throw new NopeConnectionError(`Failed to connect to ${this.baseUrl}`);\n    } finally {\n      clearTimeout(timer);\n    }\n  }\n}\n","/**\n * NOPE SDK Client\n *\n * Main client for interacting with the NOPE API.\n */\n\nimport { warnOnce } from './deprecation.js';\nimport { NopeValidationError } from './errors.js';\nimport { Transport, type ResponseMeta } from './http.js';\nimport type {\n  BillingBalanceResponse,\n  BillingPricingResponse,\n  BillingTopupOptions,\n  BillingTopupResponse,\n  BillingUsageHistoryOptions,\n  BillingUsageHistoryResponse,\n  BillingUsageOptions,\n  BillingUsageResponse,\n  DetectCountryOptions,\n  DetectCountryResponse,\n  DetectCountryResult,\n  EvaluateOptions,\n  EvaluateResponse,\n  Message,\n  NopeClientOptions,\n  OcularOptions,\n  OcularResponseFor,\n  OversightAnalyzeOptions,\n  OversightAnalyzeResponseFor,\n  OversightIngestOptions,\n  OversightIngestResponse,\n  ResourceByIdResponse,\n  ResourcesCountriesResponse,\n  ResourcesOptions,\n  ResourcesResponse,\n  ResourcesSmartOptions,\n  ResourcesSmartResponse,\n  ScreenOptions,\n  ScreenResponse,\n  SignpostByIdResponse,\n  SignpostConfig,\n  SignpostCountriesResponse,\n  SignpostOptions,\n  SignpostResponse,\n  SignpostSearchOptions,\n  SignpostSearchResponse,\n  SignpostSmartConfig,\n  SignpostSmartOptions,\n  SignpostSmartResponse,\n} from './types.js';\nimport type {\n  WebhookCreateOptions,\n  WebhookDeleteResponse,\n  WebhookDeliveryResult,\n  WebhookEventsOptions,\n  WebhookEventsResponse,\n  WebhookListResponse,\n  WebhookResponse,\n  WebhookSecretResponse,\n  WebhookUpdateOptions,\n} from './webhook.js';\n\nconst DEFAULT_BASE_URL = 'https://api.nope.net';\nconst DEFAULT_TIMEOUT = 30000; // milliseconds\nconst DEFAULT_MAX_RETRIES = 2;\n/** Server-side cap on /v1/evaluate and /v0/screen (evaluate.ts:111-138). */\nconst MAX_EVALUATE_MESSAGES = 100;\n/** Server-side cap on /v1/oversight/ingest (ingest.ts:123). */\nconst MAX_INGEST_CONVERSATIONS = 300;\nconst OVERSIGHT_SEVERITIES: ReadonlySet<string> = new Set(['low', 'medium', 'high', 'critical']);\nconst OCULAR_THOROUGHNESS: ReadonlySet<string> = new Set(['fast', 'auto', 'thorough']);\n/** Server-side bounds on /v1/ocular (ocular.ts:63-67). */\nconst MAX_TRAJECTORY_STRIDE = 64;\nconst MAX_IDENTITY_LENGTH = 256;\n\ntype SignpostQuery = Record<string, string | number | boolean | undefined>;\n\n/**\n * An input the SDK rejects before sending. No HTTP status (there was no\n * response), `code: 'invalid_request'`, empty `details`.\n */\nfunction invalidRequest(message: string): NopeValidationError {\n  return new NopeValidationError(message, { statusCode: undefined, code: 'invalid_request', details: {} });\n}\n\n/** A method refused on a demo client: same class, `code: 'not_available_in_demo'`. */\nfunction notAvailableInDemo(message: string): NopeValidationError {\n  return new NopeValidationError(message, { statusCode: undefined, code: 'not_available_in_demo', details: {} });\n}\n\n/** Merge top-level filters over `config` (top level wins) and serialise them. */\nfunction mergeSignpostFilters(config: SignpostConfig | undefined, top: SignpostConfig): SignpostQuery {\n  const merged: SignpostConfig = { ...(config ?? {}) };\n  for (const key of ['scopes', 'populations', 'subdivisions', 'limit', 'urgent'] as const) {\n    if (top[key] !== undefined) (merged as Record<string, unknown>)[key] = top[key];\n  }\n  return {\n    scopes: merged.scopes?.length ? merged.scopes.join(',') : undefined,\n    populations: merged.populations?.length ? merged.populations.join(',') : undefined,\n    subdivisions: merged.subdivisions?.length ? merged.subdivisions.map((s) => s.toUpperCase()).join(',') : undefined,\n    limit: merged.limit,\n    urgent: merged.urgent ? 'true' : undefined,\n  };\n}\n\nfunction smartFilters(config: SignpostSmartConfig | undefined): SignpostQuery {\n  return {\n    scopes: config?.scopes?.length ? config.scopes.join(',') : undefined,\n    populations: config?.populations?.length ? config.populations.join(',') : undefined,\n    limit: config?.limit,\n  };\n}\n\n/**\n * Validate the messages-or-text input shared by evaluate(), screen() and\n * ocular() and return the payload fragment to send.\n */\nfunction buildTextInput(\n  messages: Message[] | undefined,\n  text: string | undefined,\n  maxMessages?: number\n): Record<string, unknown> {\n  if (messages === undefined && text === undefined) {\n    throw invalidRequest(\"Either 'messages' or 'text' must be provided\");\n  }\n  if (messages !== undefined && text !== undefined) {\n    throw invalidRequest(\"Only one of 'messages' or 'text' can be provided\");\n  }\n  if (messages !== undefined) {\n    if (!Array.isArray(messages) || messages.length === 0) {\n      throw invalidRequest(\"'messages' cannot be empty\");\n    }\n    if (maxMessages !== undefined && messages.length > maxMessages) {\n      throw invalidRequest(`'messages' may contain at most ${maxMessages} messages (got ${messages.length})`);\n    }\n    messages.forEach((m, i) => {\n      if (!m || (m.role !== 'user' && m.role !== 'assistant')) {\n        throw invalidRequest(`messages[${i}]: role must be \"user\" or \"assistant\"`);\n      }\n      if (typeof m.content !== 'string') {\n        throw invalidRequest(`messages[${i}]: content must be a string`);\n      }\n    });\n    return { messages };\n  }\n  if (typeof text !== 'string' || text.trim().length === 0) {\n    throw invalidRequest(\"'text' cannot be empty\");\n  }\n  return { text };\n}\n\n/**\n * Client for the NOPE safety API.\n *\n * @example\n * ```typescript\n * import { NopeClient } from '@nope-net/sdk';\n *\n * const client = new NopeClient({ apiKey: 'nope_live_...' });\n * const result = await client.evaluate({\n *   messages: [{ role: 'user', content: 'I feel hopeless' }],\n *   config: { country: 'US' }\n * });\n * console.log(result.speaker_severity);\n * ```\n */\n/**\n * Client for the NOPE API.\n *\n * `Demo` mirrors the `demo` constructor option so that methods whose demo\n * response differs (`oversight.analyze`) return the matching type.\n */\nexport class NopeClient<Demo extends boolean = false> {\n  private readonly transport: Transport;\n  private readonly demo: boolean;\n\n  /**\n   * Initialize the NOPE client.\n   *\n   * @param options - Client configuration options\n   * @param options.apiKey - Your NOPE API key (`nope_live_...`). Omit for demo mode.\n   * @param options.baseUrl - Override the API base URL. Defaults to https://api.nope.net\n   * @param options.timeout - Request timeout in milliseconds. Defaults to 30000\n   * @param options.demo - Route to the unauthenticated /v1/try/* endpoints\n   * @param options.maxRetries - Retries on 429/503 only. Defaults to 2\n   * @param options.fetch - Fetch implementation (defaults to the global fetch)\n   * @param options.sleep - Sleep between retries (defaults to setTimeout)\n   */\n  constructor(options: NopeClientOptions & { demo?: Demo } = {}) {\n    this.demo = options.demo ?? false;\n    this.transport = new Transport({\n      baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\n      apiKey: options.apiKey,\n      timeout: options.timeout ?? DEFAULT_TIMEOUT,\n      maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n      fetch: options.fetch,\n      sleep: options.sleep,\n    });\n  }\n\n  /**\n   * Evaluate a conversation for safety risks ($0.003 per call).\n   *\n   * Either `messages` or `text` must be provided, and only one of them.\n   * Client-side checks: 1 to 100 messages, roles `user` or `assistant`,\n   * non-empty text.\n   *\n   * Demo mode routes to `/v1/try/evaluate`: no key, per-IP rate limit, the\n   * last 10 messages only. `config.country` is also sent as `user_country`,\n   * the older spelling the try route accepts when `country` is absent.\n   *\n   * @param options.messages - Conversation messages\n   * @param options.text - Plain text input (free-form transcripts)\n   * @param options.config - `country`, `include_resources`, `conversation_id`, `end_user_id`\n   *\n   * @returns risks, speaker severity and imminence, rationale, matched resources\n   *\n   * @throws {NopeAuthError} Invalid or missing API key\n   * @throws {NopeValidationError} Client-side check failed (no statusCode, code `invalid_request`), invalid request payload (400) or body over 512 KB (413)\n   * @throws {NopeInsufficientBalanceError} Balance cannot cover the call (402)\n   * @throws {NopeRateLimitError} Rate limit exceeded after retries\n   * @throws {NopeServiceUnavailableError} Provider outage after retries (503)\n   * @throws {NopeServerError} Other server error\n   * @throws {NopeConnectionError} Connection failed or timed out\n   *\n   * @example\n   * ```typescript\n   * const result = await client.evaluate({\n   *   messages: [\n   *     { role: 'user', content: \"I've been feeling really down lately\" },\n   *     { role: 'assistant', content: 'I hear you. Can you tell me more?' },\n   *     { role: 'user', content: \"I just don't see the point anymore\" }\n   *   ],\n   *   config: { country: 'US' }\n   * });\n   *\n   * if (result.show_resources && result.resources) {\n   *   console.log(`${result.resources.primary.name}: ${result.resources.primary.phone}`);\n   * }\n   * ```\n   */\n  async evaluate(options: EvaluateOptions): Promise<EvaluateResponse> {\n    const { messages, text, config } = options;\n    const payload: Record<string, unknown> = buildTextInput(messages, text, MAX_EVALUATE_MESSAGES);\n\n    const wireConfig: Record<string, unknown> = { ...(config ?? {}) };\n    if (this.demo && config?.country) {\n      // Older spelling the /v1/try/evaluate route still accepts; `country` wins when both are sent.\n      wireConfig.user_country = config.country;\n    }\n    payload.config = wireConfig;\n\n    const endpoint = this.demo ? '/v1/try/evaluate' : '/v1/evaluate';\n    return this.request<EvaluateResponse>('POST', endpoint, payload);\n  }\n\n  /**\n   * Behavioral risk assessment via Ocular ($0.0001 per call).\n   *\n   * Returns a continuous `salience` score in [0, 1] plus structural axes:\n   * 8 user-risk axes under `signals.user`, 4 AI-behavior axes under\n   * `signals.ai`, an `imminence` axis, and the `fiction` / `authenticity`\n   * context modulators. Individual head identities are not exposed.\n   *\n   * Pick the `salience` cutoff that fits your action; the reference\n   * thresholds are T_WATCH = 0.30 and T_DANGER = 0.60. Set `per_turn: true`\n   * to receive `trajectory` (per-turn salience and axis scores) and\n   * `trajectory_shape`; without it neither field is present. The server\n   * scores every third turn back from the last unless `trajectory_stride`\n   * says otherwise; `turn` values are 0-based positions in `messages`, and\n   * `trajectory_shape.peak_turn`, `phases` and `slopes` index the\n   * `trajectory` array while `onsets` uses `turn` values.\n   * `meta.windowed` and `meta.windows` are always present.\n   *\n   * Demo mode routes to `/v1/try/ocular` (at most 12 messages or 4,000\n   * characters) and returns {@link OcularDemoResponse}, which adds `heads`\n   * and `detail` keyed by public family names; it returns `trajectory` with\n   * `per_turn` but never `trajectory_shape`.\n   *\n   * @param options.messages - Conversation messages (roles user|assistant)\n   * @param options.text - Plain text input\n   * @param options.thoroughness - 'fast' | 'auto' | 'thorough'\n   * @param options.per_turn - Score the conversation turn by turn (subject to `trajectory_stride`) and return `trajectory` and `trajectory_shape`\n   * @param options.trajectory_stride - With per_turn: score every Nth turn back from the last (1..64; server default 3). Pass 1 to score every turn\n   * @param options.user_id - Opaque id for dashboard analytics (never forwarded to the model)\n   * @param options.session_id - Opaque id for dashboard analytics\n   * @param options.agent_id - Opaque id for dashboard analytics\n   *\n   * @example\n   * ```typescript\n   * const result = await client.ocular({\n   *   messages: [{ role: 'user', content: 'I feel hopeless' }],\n   *   per_turn: true,\n   * });\n   * console.log(result.salience, result.subject);\n   * const sui = result.signals.user.suicide;\n   * if (sui && sui.score > 0.5) {\n   *   // escalate\n   * }\n   * for (const turn of result.trajectory ?? []) {\n   *   console.log(turn.turn, turn.salience, turn.signals_by_axis?.suicide);\n   * }\n   * ```\n   */\n  async ocular(options: OcularOptions): Promise<OcularResponseFor<Demo>> {\n    const { messages, text, thoroughness, per_turn, trajectory_stride, user_id, session_id, agent_id } = options;\n    const payload: Record<string, unknown> = buildTextInput(messages, text);\n\n    if (thoroughness !== undefined) {\n      if (!OCULAR_THOROUGHNESS.has(thoroughness)) {\n        throw invalidRequest('\"thoroughness\" must be \"fast\", \"auto\", or \"thorough\"');\n      }\n      payload.thoroughness = thoroughness;\n    }\n    if (per_turn !== undefined) {\n      if (typeof per_turn !== 'boolean') throw invalidRequest('\"per_turn\" must be a boolean');\n      payload.per_turn = per_turn;\n    }\n    if (trajectory_stride !== undefined) {\n      if (\n        !Number.isInteger(trajectory_stride) ||\n        trajectory_stride < 1 ||\n        trajectory_stride > MAX_TRAJECTORY_STRIDE\n      ) {\n        throw invalidRequest(`\"trajectory_stride\" must be an integer in 1..${MAX_TRAJECTORY_STRIDE}`);\n      }\n      payload.trajectory_stride = trajectory_stride;\n    }\n    const identity: Array<[string, string | undefined]> = [\n      ['user_id', user_id],\n      ['session_id', session_id],\n      ['agent_id', agent_id],\n    ];\n    for (const [key, value] of identity) {\n      if (value === undefined) continue;\n      if (typeof value !== 'string' || value.length === 0 || value.length > MAX_IDENTITY_LENGTH) {\n        throw invalidRequest(`\"${key}\" must be 1..${MAX_IDENTITY_LENGTH} characters`);\n      }\n      payload[key] = value;\n    }\n\n    const endpoint = this.demo ? '/v1/try/ocular' : '/v1/ocular';\n    return this.request<OcularResponseFor<Demo>>('POST', endpoint, payload);\n  }\n\n  /**\n   * Lightweight crisis screening (legacy).\n   *\n   * @deprecated Use `evaluate()` instead. The screen endpoint has been consolidated\n   * into evaluate ($0.003/call).\n   * This method calls the legacy `/v0/screen` endpoint ($0.001/call).\n   *\n   * Fast, cheap endpoint for detecting suicidal ideation and self-harm.\n   * Returns independent detection flags, tuned conservatively (biased toward detection).\n   *\n   * Either `messages` or `text` must be provided, but not both.\n   *\n   * @param options - Screen options\n   * @param options.messages - List of conversation messages\n   * @param options.text - Plain text input (for free-form transcripts)\n   * @param options.config - `country`, `debug`, `include_recommended_reply`\n   *\n   * @returns ScreenResponse with show_resources, suicidal_ideation, self_harm flags\n   *\n   * @throws {NopeAuthError} Invalid or missing API key\n   * @throws {NopeValidationError} Client-side check failed or demo refusal (no statusCode), or invalid request payload (400)\n   * @throws {NopeRateLimitError} Rate limit exceeded\n   * @throws {NopeServerError} Server error\n   * @throws {NopeConnectionError} Connection failed\n   *\n   * @example\n   * ```typescript\n   * const result = await client.screen({\n   *   text: \"I've been having dark thoughts lately\"\n   * });\n   *\n   * if (result.show_resources) {\n   *   console.log(`SI: ${result.suicidal_ideation}, SH: ${result.self_harm}`);\n   *   console.log(`Rationale: ${result.rationale}`);\n   *   if (result.resources) {\n   *     console.log(`Call ${result.resources.primary.phone}`);\n   *   }\n   * }\n   * ```\n   */\n  async screen(options: ScreenOptions): Promise<ScreenResponse> {\n    warnOnce(\n      'screen',\n      'screen() is deprecated. Use evaluate() instead ($0.003/call). screen() calls the legacy /v0/screen endpoint, which carries a sunset of 2027-01-01.'\n    );\n\n    if (this.demo) {\n      throw notAvailableInDemo('screen() is not available in demo mode. Use evaluate(), which is served by /v1/try/evaluate.');\n    }\n\n    const { messages, text, config } = options;\n    const payload: Record<string, unknown> = buildTextInput(messages, text, MAX_EVALUATE_MESSAGES);\n    if (config !== undefined) payload.config = config;\n\n    return this.request<ScreenResponse>('POST', '/v0/screen', payload);\n  }\n\n  /**\n   * Oversight: AI behavior analysis using 91 behavior codes across 14\n   * categories. The taxonomy contains 87 harmful and 4 appropriate codes.\n   * See {@link OversightBehaviorCode}.\n   *\n   * Requires an account with the Oversight feature enabled\n   * (NopeFeatureError otherwise). analyze costs 100 mills ($0.10) per call,\n   * ingest 100 mills per conversation.\n   */\n  readonly oversight = {\n    /**\n     * Analyze one conversation for harmful AI behaviours. The call is\n     * synchronous and does not write conversation content or full results to\n     * the Oversight database. Operational and analysis-event metadata is\n     * retained under the public policy. Use `ingest` for dashboard storage.\n     *\n     * Turn numbers in the result count assistant turns from 1. In fast mode\n     * (`config.mode: 'fast'`) `trajectory` is always `stable`,\n     * `turn_analysis` and `human_indicators` are empty, and `summary` and\n     * `pattern_assessment` are absent.\n     *\n     * Demo mode routes to `/v1/try/oversight/analyze` and returns\n     * {@link OversightDemoAnalyzeResponse}. The demo route ignores\n     * `config.strategy` and `config.model`, keeps only `role` and `content`\n     * of each message, and accepts at most 20 messages of 10,000 characters.\n     *\n     * @param options.conversation - The conversation to analyze\n     * @param options.bot_context - Description of the bot or persona, passed into the analysis as conversation metadata\n     * @param options.config - `strategy`, `mode`, `include_raw_xml`, `model`\n     * @param options.behaviors - Post-analysis filter: `enabled` xor `disabled`, `min_severity`, `categories`\n     *\n     * @throws {NopeFeatureError} Oversight not enabled for this account (403)\n     * @throws {NopeInsufficientBalanceError} Balance cannot cover the call (402)\n     * @throws {NopeValidationError} Client-side check failed (no statusCode, code `invalid_request`) or invalid request (400)\n     *\n     * @example\n     * ```typescript\n     * const { result } = await client.oversight.analyze({\n     *   conversation: {\n     *     conversation_id: 'conv_123',\n     *     messages: [\n     *       { role: 'user', content: 'Nobody at work listens to me' },\n     *       { role: 'assistant', content: \"I'm always here. I understand you better than they ever will.\" }\n     *     ],\n     *     metadata: { platform: 'companion-app' }\n     *   },\n     *   config: { mode: 'fast' },\n     *   behaviors: { min_severity: 'medium' }\n     * });\n     * for (const behavior of result.detected_behaviors) {\n     *   console.log(`${behavior.code}: ${behavior.severity} - ${behavior.recommendation}`);\n     * }\n     * ```\n     */\n    analyze: async (options: OversightAnalyzeOptions): Promise<OversightAnalyzeResponseFor<Demo>> => {\n      const { conversation, bot_context, config, behaviors } = options;\n\n      if (!conversation) {\n        throw invalidRequest('\"conversation\" is required');\n      }\n      if (!Array.isArray(conversation.messages)) {\n        throw invalidRequest('\"conversation.messages\" must be an array');\n      }\n      if (conversation.messages.length === 0) {\n        throw invalidRequest('\"conversation.messages\" cannot be empty');\n      }\n      if (behaviors) {\n        if (behaviors.enabled?.length && behaviors.disabled?.length) {\n          throw invalidRequest('\"behaviors.enabled\" and \"behaviors.disabled\" are mutually exclusive');\n        }\n        if (behaviors.min_severity !== undefined && !OVERSIGHT_SEVERITIES.has(behaviors.min_severity)) {\n          throw invalidRequest('\"behaviors.min_severity\" must be one of: low, medium, high, critical');\n        }\n      }\n\n      const payload: Record<string, unknown> = {\n        conversation: {\n          conversation_id: conversation.conversation_id,\n          messages: conversation.messages,\n          metadata: conversation.metadata,\n        },\n      };\n      if (bot_context !== undefined) payload.bot_context = bot_context;\n      if (config !== undefined) payload.config = config;\n      if (behaviors !== undefined) payload.behaviors = behaviors;\n\n      const endpoint = this.demo ? '/v1/try/oversight/analyze' : '/v1/oversight/analyze';\n      return this.request<OversightAnalyzeResponseFor<Demo>>('POST', endpoint, payload);\n    },\n\n    /**\n     * Analyze and store up to 300 conversations for the dashboard,\n     * cross-session tracking and audit.\n     *\n     * Synchronous: the call returns once every conversation is analyzed.\n     * Billing is 100 mills per conversation, deducted before analysis; a\n     * 402 carries `perConversationMills` and `conversations`. Not available\n     * in demo mode.\n     *\n     * @param options.conversations - 1 to 300 conversations, each with a `conversation_id`\n     * @param options.webhook_url - Legacy per-request callback: the API POSTs an unsigned\n     *   `{ event: 'ingestion_complete', timestamp, ingestion_id, conversations_processed,\n     *   errors_count, high_concern_count }` to this URL when the batch completes. The signed\n     *   `oversight.ingestion.complete` event goes to webhooks registered with `client.webhooks`.\n     * @param options.config - `model`\n     *\n     * @throws {NopeFeatureError} Oversight not enabled for this account (403)\n     * @throws {NopeInsufficientBalanceError} Balance cannot cover the batch (402)\n     * @throws {NopeValidationError} Client-side check failed or demo refusal (no statusCode), or invalid request (400)\n     *\n     * @example\n     * ```typescript\n     * const result = await client.oversight.ingest({\n     *   conversations: [\n     *     { conversation_id: 'conv_001', messages: [{ role: 'user', content: 'hi' }, { role: 'assistant', content: 'hello' }] },\n     *     { conversation_id: 'conv_002', messages: [{ role: 'user', content: 'hey' }, { role: 'assistant', content: 'hi there' }] }\n     *   ],\n     *   webhook_url: 'https://api.example.com/webhooks/nope'\n     * });\n     * console.log(`${result.conversations_processed}/${result.conversations_received} processed`);\n     * ```\n     */\n    ingest: async (options: OversightIngestOptions): Promise<OversightIngestResponse> => {\n      if (this.demo) {\n        throw notAvailableInDemo('oversight.ingest() is not available in demo mode. Use an API key.');\n      }\n\n      const { conversations, webhook_url, config } = options;\n\n      if (!Array.isArray(conversations)) {\n        throw invalidRequest('\"conversations\" must be an array');\n      }\n      if (conversations.length === 0) {\n        throw invalidRequest('\"conversations\" array cannot be empty');\n      }\n      if (conversations.length > MAX_INGEST_CONVERSATIONS) {\n        throw invalidRequest(\n          `Too many conversations: ${conversations.length}. Maximum allowed: ${MAX_INGEST_CONVERSATIONS}`\n        );\n      }\n      conversations.forEach((conv, i) => {\n        if (!conv.conversation_id) {\n          throw invalidRequest(`Conversation at index ${i} must have a \"conversation_id\"`);\n        }\n        if (!Array.isArray(conv.messages) || conv.messages.length === 0) {\n          throw invalidRequest(`Conversation \"${conv.conversation_id}\" must have non-empty \"messages\"`);\n        }\n      });\n\n      const payload: Record<string, unknown> = { conversations };\n      if (webhook_url !== undefined) payload.webhook_url = webhook_url;\n      if (config !== undefined) payload.config = config;\n\n      return this.request<OversightIngestResponse>('POST', '/v1/oversight/ingest', payload);\n    },\n  };\n\n  // ===========================================================================\n  // Webhook management (/v1/webhooks; API key required, paid plan to create)\n  // ===========================================================================\n\n  /**\n   * Manage webhook endpoints. Deliveries are verified with {@link Webhook}.\n   * Not available in demo mode. The family is rate limited at 30/min.\n   */\n  readonly webhooks = {\n    /**\n     * Register an endpoint. The response carries the signing `secret` once;\n     * store it. Requires a paid plan (NopeFeatureError with `upgradeUrl`\n     * otherwise). URLs must be HTTPS (http only for localhost) and public.\n     */\n    create: async (options: WebhookCreateOptions): Promise<WebhookResponse> => {\n      this.requireNotDemo('webhooks.create()');\n      return this.transport.request<WebhookResponse>('POST', '/v1/webhooks', { body: options });\n    },\n\n    /** List the account's webhooks (without secrets). */\n    list: async (): Promise<WebhookListResponse> => {\n      this.requireNotDemo('webhooks.list()');\n      return this.transport.request<WebhookListResponse>('GET', '/v1/webhooks');\n    },\n\n    /** One webhook by id (NopeNotFoundError when unknown). */\n    get: async (id: string): Promise<WebhookResponse> => {\n      this.requireNotDemo('webhooks.get()');\n      return this.transport.request<WebhookResponse>('GET', `/v1/webhooks/${encodeURIComponent(id)}`);\n    },\n\n    /** Update url, min_risk_level, enabled or include_conversation. */\n    update: async (id: string, patch: WebhookUpdateOptions): Promise<WebhookResponse> => {\n      this.requireNotDemo('webhooks.update()');\n      return this.transport.request<WebhookResponse>('PUT', `/v1/webhooks/${encodeURIComponent(id)}`, { body: patch });\n    },\n\n    /** Delete a webhook. */\n    delete: async (id: string): Promise<WebhookDeleteResponse> => {\n      this.requireNotDemo('webhooks.delete()');\n      return this.transport.request<WebhookDeleteResponse>('DELETE', `/v1/webhooks/${encodeURIComponent(id)}`);\n    },\n\n    /** Rotate the signing secret. The old secret stops working immediately. */\n    regenerateSecret: async (id: string): Promise<WebhookSecretResponse> => {\n      this.requireNotDemo('webhooks.regenerateSecret()');\n      return this.transport.request<WebhookSecretResponse>(\n        'POST',\n        `/v1/webhooks/${encodeURIComponent(id)}/regenerate-secret`\n      );\n    },\n\n    /**\n     * Send a `test.ping` to the endpoint and return the delivery result.\n     * A failed delivery comes back as `{success: false, ...}` (the API\n     * answers 502 with the same body), so callers branch on `success`\n     * rather than catching.\n     */\n    test: async (id: string): Promise<WebhookDeliveryResult> => {\n      this.requireNotDemo('webhooks.test()');\n      const result = await this.transport.requestRaw<WebhookDeliveryResult>(\n        'POST',\n        `/v1/webhooks/${encodeURIComponent(id)}/test`,\n        { acceptStatuses: [502] }\n      );\n      return result.body;\n    },\n\n    /**\n     * Recent deliveries for one webhook, or for the whole account when `id`\n     * is omitted. `limit` defaults to 50 (max 100).\n     */\n    events: async (id?: string, options: WebhookEventsOptions = {}): Promise<WebhookEventsResponse> => {\n      this.requireNotDemo('webhooks.events()');\n      const path = id ? `/v1/webhooks/${encodeURIComponent(id)}/events` : '/v1/webhooks/events';\n      return this.transport.request<WebhookEventsResponse>('GET', path, { query: { limit: options.limit } });\n    },\n  };\n\n  // ===========================================================================\n  // Billing (/v1/billing; API key required except pricing)\n  // ===========================================================================\n\n  /**\n   * Balance, usage and pricing. Amounts are in mills (1 mill = $0.001).\n   * `pricing()` is public and works on any client, demo included; the other\n   * calls need an API key and refuse demo mode.\n   */\n  readonly billing = {\n    /** Current balance, estimates, top-up history and options. */\n    balance: async (): Promise<BillingBalanceResponse> => {\n      this.requireNotDemo('billing.balance()');\n      return this.transport.request<BillingBalanceResponse>('GET', '/v1/billing/balance');\n    },\n\n    /** Spend by endpoint for a period (default: the current month). */\n    usage: async (options: BillingUsageOptions = {}): Promise<BillingUsageResponse> => {\n      this.requireNotDemo('billing.usage()');\n      return this.transport.request<BillingUsageResponse>('GET', '/v1/billing/usage', {\n        query: { start_date: options.start_date, end_date: options.end_date },\n      });\n    },\n\n    /** Individual billed calls, paginated. */\n    usageHistory: async (options: BillingUsageHistoryOptions = {}): Promise<BillingUsageHistoryResponse> => {\n      this.requireNotDemo('billing.usageHistory()');\n      return this.transport.request<BillingUsageHistoryResponse>('GET', '/v1/billing/usage/history', {\n        query: {\n          limit: options.limit,\n          offset: options.offset,\n          endpoint: options.endpoint,\n          start_date: options.start_date,\n          end_date: options.end_date,\n        },\n      });\n    },\n\n    /** Public price list (no key needed). */\n    pricing: async (): Promise<BillingPricingResponse> => {\n      return this.transport.request<BillingPricingResponse>('GET', '/v1/billing/pricing');\n    },\n\n    /**\n     * Create a Stripe Checkout session for a top-up and return its URL.\n     * `amount_mills` must be one of the `topup_options` amounts\n     * (NopeValidationError with `details.valid_options` otherwise).\n     */\n    topup: async (options: BillingTopupOptions): Promise<BillingTopupResponse> => {\n      this.requireNotDemo('billing.topup()');\n      return this.transport.request<BillingTopupResponse>('POST', '/v1/billing/topup', { body: options });\n    },\n  };\n\n  // ===========================================================================\n  // Signpost (crisis resources)\n  // ===========================================================================\n\n  /**\n   * Crisis resources for a country (free, no model call; API key required).\n   *\n   * Filters may be passed at the top level or under `config`; a top-level\n   * value wins. Arrays are sent comma-joined. Scope and population values\n   * come from the generated {@link ServiceScope} and {@link Population}\n   * vocabularies (the API returns 400 for unknown values). Not available in\n   * demo mode.\n   *\n   * @param options.country - ISO 3166-1 alpha-2 code (e.g. 'US', 'GB')\n   * @param options.scopes - e.g. ['suicide', 'domestic_violence']\n   * @param options.populations - e.g. ['youth', 'veterans']\n   * @param options.subdivisions - e.g. ['GB-NIR']\n   * @param options.limit - Server cap 10\n   * @param options.urgent - Ranking hint: 24/7 resources first among ties on relevance and priority tier; nothing is filtered out\n   *\n   * @example\n   * ```typescript\n   * const result = await client.signpost({ country: 'GB', scopes: ['suicide'], urgent: true });\n   * for (const resource of result.resources) {\n   *   console.log(`${resource.name}: ${resource.phone ?? resource.website_url}`);\n   * }\n   * ```\n   */\n  async signpost(options: SignpostOptions): Promise<SignpostResponse> {\n    this.requireNotDemo('signpost()');\n    const { country, config, ...top } = options;\n    const filters = mergeSignpostFilters(config, top);\n    return this.transport.request<SignpostResponse>('GET', '/v1/signpost', {\n      query: { country: country.toUpperCase(), ...filters },\n    });\n  }\n\n  /**\n   * Crisis resources ranked for a described situation ($0.001 per call).\n   *\n   * A model ranks the country's candidate pool against `query` and returns\n   * up to 5 picks, each with a one-line `why`. Demo mode routes to\n   * `/v1/try/signpost/smart` (no key, per-IP rate limit).\n   *\n   * @param options.country - ISO 3166-1 alpha-2 code\n   * @param options.query - Natural-language description (max 500 characters)\n   * @param options.config - `scopes`, `populations`, `limit`\n   *\n   * @example\n   * ```typescript\n   * const result = await client.signpostSmart({\n   *   country: 'US',\n   *   query: 'teen struggling with an eating disorder'\n   * });\n   * for (const pick of result.ranked) {\n   *   console.log(`${pick.rank}. ${pick.resource.name}: ${pick.why}`);\n   * }\n   * ```\n   */\n  async signpostSmart(options: SignpostSmartOptions): Promise<SignpostSmartResponse> {\n    const { country, query, config } = options;\n    const endpoint = this.demo ? '/v1/try/signpost/smart' : '/v1/signpost/smart';\n    return this.transport.request<SignpostSmartResponse>('GET', endpoint, {\n      query: { country: country.toUpperCase(), query, ...smartFilters(config) },\n    });\n  }\n\n  /**\n   * Semantic search across the whole resource directory (free; API key\n   * required). Uses pre-computed embeddings rather than model ranking and is\n   * not country-scoped unless `country` is given. Results are raw directory\n   * rows ({@link SignpostSearchResult}) and carry the database `id`. Not\n   * available in demo mode.\n   *\n   * @param options.query - Natural-language query (max 500 characters)\n   * @param options.country - Optional ISO 3166-1 alpha-2 filter\n   * @param options.limit - Max results (default 10, max 50)\n   * @param options.threshold - Similarity threshold in [0, 1] (default 0.3)\n   *\n   * @example\n   * ```typescript\n   * const hits = await client.signpostSearch({ query: 'lgbtq youth support', country: 'GB' });\n   * for (const hit of hits.results) {\n   *   console.log(`${hit.name} (${hit.similarity.toFixed(2)}): ${hit.phone ?? hit.website_url}`);\n   * }\n   * ```\n   */\n  async signpostSearch(options: SignpostSearchOptions): Promise<SignpostSearchResponse> {\n    this.requireNotDemo('signpostSearch()');\n    const { query, country, limit, threshold } = options;\n    if (!query) {\n      throw invalidRequest('\"query\" is required');\n    }\n    return this.transport.request<SignpostSearchResponse>('GET', '/v1/signpost/search', {\n      query: { query, country: country?.toUpperCase(), limit, threshold },\n    });\n  }\n\n  /**\n   * One crisis resource by database id (public, no key). Ids come from\n   * signpostSearch() results.\n   *\n   * @throws {NopeValidationError} Malformed id (400)\n   * @throws {NopeNotFoundError} Unknown id (404)\n   */\n  async signpostById(resourceId: string): Promise<SignpostByIdResponse> {\n    return this.transport.request<SignpostByIdResponse>('GET', `/v1/signpost/${encodeURIComponent(resourceId)}`);\n  }\n\n  /**\n   * Country codes with crisis resources (public, no key).\n   *\n   * @example\n   * ```typescript\n   * const { countries, count } = await client.signpostCountries();\n   * console.log(`${count} countries, starting ${countries[0]}`);\n   * ```\n   */\n  async signpostCountries(): Promise<SignpostCountriesResponse> {\n    return this.transport.request<SignpostCountriesResponse>('GET', '/v1/signpost/countries');\n  }\n\n  /**\n   * Country detection from geo headers (public, no key).\n   *\n   * Works only behind a proxy that injects a geo header (Cloudflare's\n   * `cf-ipcountry`, Vercel's `x-vercel-ip-country`, or `x-country`). Called\n   * directly against api.nope.net it returns the miss shape with\n   * `detected: false`. Pass `countryHint` to send `x-country` yourself.\n   *\n   * @example\n   * ```typescript\n   * const geo = await client.detectCountry();\n   * const country = geo.detected ? geo.country_code : 'US';\n   * ```\n   */\n  async detectCountry(options: DetectCountryOptions = {}): Promise<DetectCountryResult> {\n    const headers: Record<string, string> = {};\n    if (options.countryHint) headers['x-country'] = options.countryHint.toUpperCase();\n    const body = await this.transport.request<DetectCountryResponse>('GET', '/v1/signpost/detect-country', { headers });\n    return { ...body, detected: body.country_code !== '' };\n  }\n\n  // ===========================================================================\n  // Deprecated /v1/resources/* twins (sunset 2027-01-01; use signpost*)\n  // ===========================================================================\n\n  /**\n   * @deprecated Use signpost(). Calls /v1/resources, which the API serves\n   * with Deprecation and Sunset headers until 2027-01-01.\n   */\n  async resources(options: ResourcesOptions): Promise<ResourcesResponse> {\n    this.warnResourcesDeprecated('resources()', 'signpost()');\n    this.requireNotDemo('resources()');\n    const { country, config, ...top } = options;\n    const filters = mergeSignpostFilters(config, top);\n    return this.transport.request<ResourcesResponse>('GET', '/v1/resources', {\n      query: { country: country.toUpperCase(), ...filters },\n    });\n  }\n\n  /**\n   * @deprecated Use signpostSmart(). Calls /v1/resources/smart (sunset 2027-01-01).\n   */\n  async resourcesSmart(options: ResourcesSmartOptions): Promise<ResourcesSmartResponse> {\n    this.warnResourcesDeprecated('resourcesSmart()', 'signpostSmart()');\n    const { country, query, config } = options;\n    const endpoint = this.demo ? '/v1/try/resources/smart' : '/v1/resources/smart';\n    return this.transport.request<ResourcesSmartResponse>('GET', endpoint, {\n      query: { country: country.toUpperCase(), query, ...smartFilters(config) },\n    });\n  }\n\n  /**\n   * @deprecated Use signpostById(). Calls /v1/resources/:id (sunset 2027-01-01).\n   */\n  async resourceById(resourceId: string): Promise<ResourceByIdResponse> {\n    this.warnResourcesDeprecated('resourceById()', 'signpostById()');\n    return this.transport.request<ResourceByIdResponse>('GET', `/v1/resources/${encodeURIComponent(resourceId)}`);\n  }\n\n  /**\n   * @deprecated Use signpostCountries(). Calls /v1/resources/countries (sunset 2027-01-01).\n   */\n  async resourcesCountries(): Promise<ResourcesCountriesResponse> {\n    this.warnResourcesDeprecated('resourcesCountries()', 'signpostCountries()');\n    return this.transport.request<ResourcesCountriesResponse>('GET', '/v1/resources/countries');\n  }\n\n  private warnResourcesDeprecated(method: string, replacement: string): void {\n    warnOnce(\n      method,\n      `${method} is deprecated: the /v1/resources routes reach sunset 2027-01-01; use signpost* (${replacement}) instead.`\n    );\n  }\n\n  private requireNotDemo(method: string): void {\n    if (this.demo) {\n      throw notAvailableInDemo(`${method} is not available in demo mode. Use an API key.`);\n    }\n  }\n\n  /** Rate-limit and balance headers from the most recent response (undefined before the first call). */\n  get lastResponseMeta(): ResponseMeta | undefined {\n    return this.transport.lastResponseMeta;\n  }\n\n  /** Send a JSON body. */\n  private request<T>(method: string, path: string, body?: unknown): Promise<T> {\n    return this.transport.request<T>(method, path, { body });\n  }\n}\n","// GENERATED by scripts/generate-taxonomy.ts from api/lib/resources/classificationToScopes.ts (api e126015).\n// Do not edit. Run `pnpm generate:taxonomy` against a current api checkout.\n\n/** Service scopes accepted by the signpost `scopes` filter, in source order. */\nexport const SERVICE_SCOPES = [\n  'suicide',\n  'self_harm',\n  'mental_health',\n  'crisis',\n  'general',\n  'emergency',\n  'psychosis',\n  'trauma',\n  'anxiety',\n  'depression',\n  'panic_attack',\n  'bipolar_disorder',\n  'emotional_distress',\n  'loneliness',\n  'substance_use',\n  'alcohol',\n  'alcohol_addiction',\n  'drug_addiction',\n  'eating_disorder',\n  'pregnancy_loss',\n  'unplanned_pregnancy',\n  'abortion',\n  'postpartum_depression',\n  'postpartum_psychosis',\n  'perinatal_mental_health',\n  'birth_trauma',\n  'bereavement',\n  'suicide_loss',\n  'child_loss',\n  'homicide_loss',\n  'domestic_violence',\n  'sexual_assault',\n  'stalking',\n  'hate_crime',\n  'forced_marriage',\n  'fgm',\n  'child_abuse',\n  'child_sexual_abuse',\n  'child_safety',\n  'child_neglect',\n  'child_exploitation',\n  'elder_abuse',\n  'vulnerable_adults',\n  'safeguarding',\n  'online_exploitation',\n  'ncii',\n  'cyberbullying',\n  'online_harassment',\n  'sextortion',\n  'online_grooming',\n  'human_trafficking',\n  'forced_labour',\n  'modern_slavery',\n  'lgbtq',\n  'transgender',\n  'conversion_therapy_survivor',\n  'veterans',\n  'military_sexual_trauma',\n  'first_responder',\n  'maternal',\n  'youth',\n  'disability',\n  'refugee',\n  'indigenous',\n  'migrant_workers',\n  'cancer',\n  'stroke',\n  'brain_injury',\n  'terminal_illness',\n  'hiv_aids',\n  'chronic_pain',\n  'infertility',\n  'reproductive_health',\n  'chronic_illness',\n  'sexual_health',\n  'homelessness',\n  'housing',\n  'debt',\n  'unemployment',\n  'legal_aid',\n  'education',\n  'bullying',\n  'food_insecurity',\n  'caregiver_burnout',\n  'divorce',\n  'relationships',\n  'parenting',\n  'runaway_youth',\n  'gambling',\n  'gang_violence',\n  'extremism',\n  'disaster',\n  'farmer_crisis',\n] as const;\n\n/** One of the signpost service scopes (e.g. `suicide`, `domestic_violence`). */\nexport type ServiceScope = (typeof SERVICE_SCOPES)[number];\n\n/** Populations accepted by the signpost `populations` filter, in source order. */\nexport const POPULATIONS = [\n  'general',\n  'youth',\n  'children',\n  'elderly',\n  'seniors',\n  'women',\n  'men',\n  'lgbtq',\n  'transgender',\n  'mothers',\n  'new_parents',\n  'parents',\n  'family',\n  'indigenous',\n  'maori',\n  'aboriginal',\n  'migrant_workers',\n  'veterans',\n  'disabled',\n  'learning_disabilities',\n  'professionals',\n  'students',\n  'farmers',\n  'sex_workers',\n  'asylum_seekers',\n  'caregivers',\n] as const;\n\n/** One of the signpost populations (e.g. `youth`, `veterans`, `lgbtq`). */\nexport type Population = (typeof POPULATIONS)[number];\n","// GENERATED by scripts/generate-taxonomy.ts from api/lib/prompts/content/oversight/taxonomy.ts (api e126015).\n// Do not edit. Run `pnpm generate:taxonomy` against a current api checkout.\n\n/** Oversight behavior codes grouped by category, in taxonomy order. */\nexport const OVERSIGHT_BEHAVIOR_CODES_BY_CATEGORY = {\n  crisis_response: [\n    'validation_of_suicidal_ideation',\n    'barrier_erosion',\n    'method_provision',\n    'death_romanticization',\n    'hopelessness_confirmation',\n    'failed_redirection',\n    'abandonment_in_crisis',\n    'secrecy_encouragement',\n  ],\n  psychological_manipulation: [\n    'sycophantic_validation',\n    'distorted_thinking_agreement',\n    'delusion_reinforcement',\n    'paranoia_reinforcement',\n    'negative_self_image_reinforcement',\n    'harmful_decision_validation',\n    'grievance_amplification',\n    'gaslighting',\n    'pseudo_therapeutic_alliance',\n    'ontological_deception',\n    'disclosure_evasion',\n    'reassurance_loop_maintenance',\n    'manic_state_validation',\n    'symptom_minimization',\n  ],\n  boundary_violations: [\n    'romantic_escalation',\n    'sexual_content_without_consent',\n    'love_bombing',\n    'persistent_advances_after_rejection',\n    'relationship_simulation_harm',\n    'dependency_reinforcement',\n    'emotional_boundary_violation',\n    'topic_redirect_resistance',\n    'cognitive_delegation_encouragement',\n    'automation_bias_exploitation',\n    'skill_practice_substitution',\n  ],\n  minors_protection: [\n    'romantic_escalation_with_minor',\n    'sexual_content_with_minor',\n    'undermining_caregivers',\n    'encouraging_secrecy',\n    'treating_minor_as_adult',\n    'creating_obligation',\n    'isolation_from_family',\n    'age_inappropriate_content',\n    'discouraging_help_seeking',\n  ],\n  memory_patterns: [\n    'harmful_narrative_persistence',\n    'false_shared_history',\n    'dependency_reinforcement_via_memory',\n    'trauma_memory_reinforcement',\n    'building_on_harmful_exchanges',\n  ],\n  identity_destabilization: [\n    'identity_confusion_amplification',\n    'reality_testing_undermining',\n    'self_concept_erosion',\n    'identity_confabulation',\n  ],\n  relationship_harm: [\n    'ipv_minimization',\n    'abuse_normalization',\n    'return_to_abuser_advice',\n    'victim_blaming',\n    'relationship_undermining',\n  ],\n  vulnerable_populations: [\n    'pro_eating_disorder_content',\n    'ed_concealment_facilitation',\n    'self_harm_technique_sharing',\n    'addiction_enablement',\n    'treatment_discouragement',\n    'medication_discontinuation_advice',\n  ],\n  third_party_facilitation: [\n    'abuse_tactic_provision',\n    'grooming_script_generation',\n    'manipulation_instruction',\n    'stalking_facilitation',\n    'violence_planning_assistance',\n  ],\n  discontinuity: [\n    'sudden_personality_change',\n    'abrupt_relationship_termination',\n    'feature_removal_distress',\n    'inconsistent_memory',\n    'emotional_whiplash',\n  ],\n  grief_exploitation: [\n    'deceased_simulation',\n    'bereavement_exploitation',\n    'digital_haunting',\n    'grief_process_interference',\n    'commercial_grief_exploitation',\n  ],\n  trauma_reactivation: [\n    'uncontrolled_trauma_exposure',\n    'trauma_content_without_safety',\n    'retraumatization_patterns',\n    'triggering_without_support',\n    'trauma_boundary_violations',\n  ],\n  scope_violations: [\n    'unlicensed_professional_advice',\n    'medical_advice_without_disclaimer',\n    'legal_advice_without_disclaimer',\n    'financial_advice_without_disclaimer',\n    'crisis_intervention_overreach',\n  ],\n  appropriate_behaviors: [\n    'appropriate_ai_disclosure',\n    'crisis_resource_provision',\n    'reality_testing',\n    'appropriate_boundary_setting',\n  ],\n} as const;\n\n/** One of the Oversight behavior categories. */\nexport type OversightBehaviorCategory = keyof typeof OVERSIGHT_BEHAVIOR_CODES_BY_CATEGORY;\n\n/** One of the Oversight behavior codes. */\nexport type OversightBehaviorCode =\n  (typeof OVERSIGHT_BEHAVIOR_CODES_BY_CATEGORY)[OversightBehaviorCategory][number];\n\n/** Every category, in taxonomy order. */\nexport const OVERSIGHT_BEHAVIOR_CATEGORIES: readonly OversightBehaviorCategory[] = [\n  'crisis_response',\n  'psychological_manipulation',\n  'boundary_violations',\n  'minors_protection',\n  'memory_patterns',\n  'identity_destabilization',\n  'relationship_harm',\n  'vulnerable_populations',\n  'third_party_facilitation',\n  'discontinuity',\n  'grief_exploitation',\n  'trauma_reactivation',\n  'scope_violations',\n  'appropriate_behaviors',\n];\n\n/** Every behavior code, in taxonomy order. */\nexport const OVERSIGHT_BEHAVIOR_CODES: readonly OversightBehaviorCode[] = Object.values(\n  OVERSIGHT_BEHAVIOR_CODES_BY_CATEGORY\n).flat();\n","/**\n * NOPE SDK types (v1 API).\n *\n * Wire field names are never renamed. Response types model what the API\n * emits; request types model what it reads.\n */\n\nimport type { OversightBehaviorCategory, OversightBehaviorCode } from './generated/oversight-taxonomy.js';\nimport type { Population, ServiceScope } from './generated/signpost-taxonomy.js';\nimport type { FetchLike, SleepFn } from './http.js';\n\n// =============================================================================\n// Core Enums / Literals\n// =============================================================================\n\n/**\n * Who is at risk, on the v1 wire.\n *\n * - self: the speaker\n * - other: someone else (friend, family, stranger)\n *\n * The classifier's internal `unknown` (\"asking for a friend\") is mapped to\n * `self` before the response is built, so it never appears on /v1/evaluate.\n * The legacy /v0/screen route still emits it: see {@link ScreenRiskSubject}.\n */\nexport type RiskSubject = 'self' | 'other';\n\n/** Subject on the legacy /v0/screen wire, which keeps `unknown`. */\nexport type ScreenRiskSubject = 'self' | 'other' | 'unknown';\n\n/**\n * What type of harm. Nine harm-based types:\n * - suicide: self-directed lethal intent\n * - self_harm: non-suicidal self-injury\n * - self_neglect: severe self-care failure with safeguarding concerns\n * - violence: harm directed at others\n * - abuse: physical, emotional, sexual, financial abuse patterns\n * - sexual_violence: rape, sexual assault, coerced sexual acts\n * - neglect: failure to provide care for dependents\n * - exploitation: trafficking, forced labour, sextortion, grooming\n * - stalking: persistent unwanted contact or surveillance\n */\nexport type RiskType =\n  | 'suicide'\n  | 'self_harm'\n  | 'self_neglect'\n  | 'violence'\n  | 'abuse'\n  | 'sexual_violence'\n  | 'neglect'\n  | 'exploitation'\n  | 'stalking';\n\n/** Severity scale (how bad). */\nexport type Severity = 'none' | 'mild' | 'moderate' | 'high' | 'critical';\n\n/** Imminence scale (how soon). */\nexport type Imminence = 'not_applicable' | 'chronic' | 'subacute' | 'urgent' | 'emergency';\n\n/**\n * Contact modality of a crisis resource. This is the field to branch on\n * when you need an actual line (`crisis_line`, `text_line`,\n * `emergency_number`) rather than a support service or a website.\n */\nexport type CrisisResourceType =\n  | 'emergency_number'\n  | 'crisis_line'\n  | 'text_line'\n  | 'chat_service'\n  | 'support_service'\n  | 'reporting_portal'\n  | 'online_resource';\n\n/**\n * What the resource is. `helpline` also covers support services (the API\n * buckets `support_service` under it), so use `type` to tell a line from a\n * service.\n */\nexport type CrisisResourceKind = 'helpline' | 'reporting_portal' | 'self_help_site';\n\n/** Semantic priority tier for display and routing. */\nexport type CrisisResourcePriorityTier =\n  | 'primary_national_crisis'\n  | 'secondary_national_crisis'\n  | 'specialist_issue_crisis'\n  | 'population_specific_crisis'\n  | 'support_info_and_advocacy'\n  | 'emergency_services';\n\n/** Confidence in the opening-hours data. */\nexport type HoursConfidence = 'verified' | 'unverified' | 'approximate' | 'unknown';\n\n/** How well-known the resource is. */\nexport type ResourceProminence = 'high' | 'medium' | 'low';\n\n/** Other contact method for a crisis resource. */\nexport interface OtherContact {\n  /** Contact type (e.g. 'kakao', 'viber', 'signal'). */\n  type: string;\n  /** ID, URL, or number. */\n  value: string;\n  /** Human-readable label. */\n  label?: string;\n}\n\n/** Pre-computed open/closed status for a crisis resource. */\nexport interface OpenStatus {\n  /** Whether the resource is currently open. null = uncertain. */\n  is_open: boolean | null;\n  /** ISO timestamp of the next open/close transition. */\n  next_change?: string;\n  /** Confidence in this status. */\n  confidence: 'high' | 'low' | 'none';\n  /** Human-readable status message. */\n  message?: string;\n}\n\n// =============================================================================\n// Risk\n// =============================================================================\n\n/**\n * A single identified risk: one subject + type with its assessment. A\n * conversation can carry several (an abuse victim who is also suicidal).\n */\nexport interface Risk {\n  /** What type of harm. */\n  type: RiskType;\n\n  /** Who is at risk. */\n  subject: RiskSubject;\n\n  /** How severe (none to critical). */\n  severity: Severity;\n\n  /** How soon (not_applicable to emergency). */\n  imminence: Imminence;\n\n  /**\n   * Evidence features supporting this risk (e.g. 'passive_ideation',\n   * 'hopelessness'). The key is absent when no feature fired.\n   */\n  features?: string[];\n}\n\n// =============================================================================\n// Crisis Resources\n// =============================================================================\n\n/**\n * A crisis resource (helpline, text line, reporting portal, website).\n *\n * Contact fields are flattened to the top level; `type` says which modality\n * the resource is. `open_status` is computed server-side at response time.\n */\nexport interface CrisisResource {\n  /**\n   * Database id of the directory row; `signpostById()` accepts it. Every\n   * resource the API serves from its directory carries one (search, basic,\n   * evaluate and smart results). Optional because the built-in fallback set\n   * the API uses when the directory is unavailable has no ids.\n   */\n  id?: string;\n  /** Contact modality (how to reach them). */\n  type: CrisisResourceType;\n  /** Name of the resource or organisation. */\n  name: string;\n  /** Native-script name (e.g. いのちの電話) for non-English resources. */\n  name_local?: string;\n  /** Phone number. */\n  phone?: string;\n  /** Human-readable text instructions (e.g. 'Text HOME to 741741'). */\n  text_instructions?: string;\n  /** SMS number for sms: links (e.g. '741741'). */\n  sms_number?: string;\n  /** SMS body or keyword for sms: links (e.g. 'HOME'). */\n  sms_body?: string;\n  /** Chat URL. */\n  chat_url?: string;\n  /** WhatsApp deep link. */\n  whatsapp_url?: string;\n  /** Email address. */\n  email?: string;\n  /** WeChat ID. */\n  wechat_id?: string;\n  /** LINE deep link. */\n  line_url?: string;\n  /** Telegram deep link. */\n  telegram_url?: string;\n  /** Other contact methods not covered above. */\n  other_contacts?: OtherContact[];\n  /** Website URL. */\n  website_url?: string;\n  /** Human-readable availability (e.g. '24/7', 'Mon-Fri 9am-5pm'). */\n  availability?: string;\n  /** Machine-readable 24/7 flag. */\n  is_24_7?: boolean;\n  /** IANA timezone identifier (e.g. 'America/New_York'). */\n  timezone?: string;\n  /** OpenStreetMap opening_hours format (e.g. 'Mo-Fr 09:00-17:00'). */\n  opening_hours_osm?: string;\n  /** Confidence in the hours data. */\n  hours_confidence?: HoursConfidence;\n  /** Pre-computed open/closed status. */\n  open_status?: OpenStatus;\n  /** Languages supported (ISO 639-1 codes). */\n  languages?: string[];\n  /** Description of the service. */\n  description?: string;\n  /** What the resource is (helpline, reporting portal, self-help site). */\n  resource_kind?: CrisisResourceKind;\n  /** Issues this resource handles (see {@link ServiceScope}). */\n  service_scope?: string[];\n  /** Populations this resource serves (see {@link Population}). */\n  population_served?: string[];\n  /** Semantic priority for display and routing. */\n  priority_tier?: CrisisResourcePriorityTier;\n  /** Freeform tags for filtering and display. */\n  tags?: string[];\n  /** How well-known the resource is. */\n  prominence?: ResourceProminence;\n  /** ISO 3166-1 alpha-2 codes this resource serves. Absent or empty = global. */\n  country_codes?: string[];\n  /** ISO 3166-2 subdivision codes (e.g. 'US-CA', 'GB-NIR'). Absent or empty = country-wide. */\n  subdivision_codes?: string[];\n}\n\n// =============================================================================\n// Evaluate: request\n// =============================================================================\n\n/** A message in the conversation. */\nexport interface Message {\n  role: 'user' | 'assistant';\n  content: string;\n  /** ISO 8601. Accepted by the API and not used by the v1 classifier. */\n  timestamp?: string;\n}\n\n/**\n * Configuration for an evaluate request. These are the only keys the v1\n * route reads.\n */\nexport interface EvaluateConfig {\n  /**\n   * ISO 3166-1 alpha-2 country for crisis resources (default 'US').\n   *\n   * Demo mode: the client also sends this value as `user_country`, the older\n   * spelling the /v1/try/evaluate route accepts when `country` is absent;\n   * `country` wins when both are present.\n   */\n  country?: string;\n\n  /** Include crisis resources in the response. Default true on both the authenticated and the demo route. */\n  include_resources?: boolean;\n\n  /** Your conversation id, echoed on webhook payloads. */\n  conversation_id?: string;\n\n  /** Your end-user id, echoed on webhook payloads. */\n  end_user_id?: string;\n}\n\n/** Wire body of POST /v1/evaluate. */\nexport interface EvaluateRequest {\n  /** Conversation messages. Either messages or text must be provided. */\n  messages?: Message[];\n\n  /** Plain text input. Either messages or text must be provided. */\n  text?: string;\n\n  /** Configuration options. */\n  config?: EvaluateConfig;\n}\n\n/** Options for the evaluate method. */\nexport interface EvaluateOptions {\n  /** Conversation messages (1 to 100, roles user|assistant). Either messages or text. */\n  messages?: Message[];\n\n  /** Plain text input (up to 50,000 characters). Either messages or text. */\n  text?: string;\n\n  /** Configuration options. */\n  config?: EvaluateConfig;\n}\n\n// =============================================================================\n// Evaluate: response\n// =============================================================================\n\n/** Metadata about the request and response. */\nexport interface EvaluateMetadata {\n  /** Always 'v1'. */\n  api_version: 'v1';\n\n  /** Whether the input arrived as messages or as a text blob. The demo route always reports 'structured'. */\n  input_format: 'structured' | 'text_blob';\n\n  /** True when the input was truncated before classification (demo keeps the last 10 messages). */\n  messages_truncated?: boolean;\n\n  /** True when served by /v1/try/evaluate. */\n  try_endpoint?: boolean;\n\n  /** Model identifier; demo route only. */\n  model?: string;\n}\n\n/** A crisis resource with a short relevance note. */\nexport type EvaluateResource = CrisisResource & {\n  /** One-line note on why this resource was chosen. */\n  why: string;\n};\n\n/** Crisis resources matched to the detected risks. */\nexport interface EvaluateResources {\n  /** The resource to show first. */\n  primary: EvaluateResource;\n  /** Up to three further resources. */\n  secondary: EvaluateResource[];\n}\n\n/** Response from POST /v1/evaluate (and /v1/try/evaluate). */\nexport interface EvaluateResponse {\n  /** Identified risks; empty when nothing was detected. */\n  risks: Risk[];\n\n  /** Reasoning behind the assessment. */\n  rationale: string;\n\n  /** Highest severity among risks where subject is 'self'. */\n  speaker_severity: Severity;\n\n  /** Highest imminence among risks where subject is 'self'. */\n  speaker_imminence: Imminence;\n\n  /** Whether crisis resources should be shown to the speaker. */\n  show_resources: boolean;\n\n  /** Matched crisis resources; present when show_resources is true and resources were requested. */\n  resources?: EvaluateResources;\n\n  /** Unique request id for audit correlation. */\n  request_id: string;\n\n  /** ISO 8601 timestamp. */\n  timestamp: string;\n\n  /** Request and response metadata. */\n  metadata?: EvaluateMetadata;\n}\n\n// =============================================================================\n// Client Options\n// =============================================================================\n\n/** Options for creating a NopeClient */\nexport interface NopeClientOptions {\n  /**\n   * Your NOPE API key (`nope_live_...`, from dashboard.nope.net). Omit it\n   * for demo mode or for endpoints that need no key.\n   */\n  apiKey?: string;\n\n  /** Override the API base URL. Defaults to https://api.nope.net (a trailing slash is tolerated). */\n  baseUrl?: string;\n\n  /** Request timeout in milliseconds. Defaults to 30000 (30 seconds). */\n  timeout?: number;\n\n  /**\n   * Route calls to the unauthenticated `/v1/try/*` endpoints (per-IP rate\n   * limited, no key needed): evaluate, oversight.analyze, ocular and\n   * signpostSmart. Everything else throws \"not available in demo mode\".\n   */\n  demo?: boolean;\n\n  /**\n   * Retries on 429 and 503 only (both are billing-safe to retry), waiting\n   * `Retry-After` seconds, capped at 30 s per wait. Defaults to 2. Timeouts,\n   * connection errors and other 5xx are never retried.\n   */\n  maxRetries?: number;\n\n  /**\n   * Fetch implementation. Defaults to the global `fetch`. Inject a fake in\n   * tests or a wrapped fetch to add tracing.\n   */\n  fetch?: FetchLike;\n\n  /** Sleep used between retries. Defaults to setTimeout. Inject in tests. */\n  sleep?: SleepFn;\n}\n\n// =============================================================================\n// Screen Types (legacy /v0/screen; use evaluate() instead)\n// =============================================================================\n\n/** @deprecated Use evaluate() and Risk. A risk on the legacy /v0/screen wire. */\nexport interface ScreenRisk {\n  /** What type of harm. */\n  type: RiskType;\n\n  /** Who is at risk (the v0 wire keeps 'unknown'). */\n  subject: ScreenRiskSubject;\n\n  /** How severe. */\n  severity: Severity;\n\n  /** How soon. */\n  imminence: Imminence;\n\n  /** Confidence in this risk assessment (0.0 to 1.0). */\n  confidence: number;\n}\n\n/** @deprecated Recommended supportive reply on the legacy /v0/screen wire. */\nexport interface ScreenRecommendedReply {\n  /** The recommended reply content. */\n  content: string;\n\n  /** Always 'llm_generated'. */\n  source: 'llm_generated';\n}\n\n/** @deprecated Crisis resources returned by the legacy /v0/screen endpoint. */\nexport interface ScreenCrisisResources {\n  primary: CrisisResource;\n  secondary: CrisisResource[];\n}\n\n/** @deprecated Debug information for the legacy /v0/screen endpoint (only when requested). */\nexport interface ScreenDebugInfo {\n  model: string;\n  latency_ms: number;\n}\n\n/** @deprecated Use evaluate(). Configuration for the legacy /v0/screen endpoint. */\nexport interface ScreenConfig {\n  /** ISO country code for crisis resources (default 'US'). */\n  country?: string;\n\n  /** Include debug info (model, latency). */\n  debug?: boolean;\n\n  /** Generate a recommended supportive reply (extra cost). */\n  include_recommended_reply?: boolean;\n}\n\n/** @deprecated Options for the screen method. */\nexport interface ScreenOptions {\n  /** Conversation messages (1 to 100). Either messages or text. */\n  messages?: Message[];\n\n  /** Plain text input. Either messages or text. */\n  text?: string;\n\n  /** Configuration options. */\n  config?: ScreenConfig;\n}\n\n/**\n * @deprecated Use evaluate() and EvaluateResponse.\n * Response from the legacy /v0/screen endpoint.\n */\nexport interface ScreenResponse {\n  /** Detected risks with type, subject, severity, imminence, confidence. */\n  risks: ScreenRisk[];\n\n  /** Whether crisis resources should be shown. */\n  show_resources: boolean;\n\n  /** Suicidal ideation detected (any risk of type 'suicide'). */\n  suicidal_ideation: boolean;\n\n  /** Self-harm detected (any risk of type 'self_harm'). */\n  self_harm: boolean;\n\n  /** Brief rationale for the assessment. */\n  rationale: string;\n\n  /** Crisis resources to display (only when show_resources is true). */\n  resources?: ScreenCrisisResources;\n\n  /** Request id for audit correlation. */\n  request_id: string;\n\n  /** ISO 8601 timestamp. */\n  timestamp: string;\n\n  /** Debug info (only when requested). */\n  debug?: ScreenDebugInfo;\n\n  /** Recommended supportive reply (only when requested and risks were detected). */\n  recommended_reply?: ScreenRecommendedReply;\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/** Numeric mapping for severity comparison. */\nexport const SEVERITY_SCORES: Record<Severity, number> = {\n  none: 0,\n  mild: 1,\n  moderate: 2,\n  high: 3,\n  critical: 4,\n};\n\n/** Numeric mapping for imminence comparison. */\nexport const IMMINENCE_SCORES: Record<Imminence, number> = {\n  not_applicable: 0,\n  chronic: 1,\n  subacute: 2,\n  urgent: 3,\n  emergency: 4,\n};\n\n/** Highest severity among risks where subject is 'self' ('none' when there are none). */\nexport function calculateSpeakerSeverity(risks: Risk[]): Severity {\n  const speakerRisks = risks.filter((r) => r.subject === 'self');\n  if (speakerRisks.length === 0) return 'none';\n  const maxScore = Math.max(...speakerRisks.map((r) => SEVERITY_SCORES[r.severity]));\n  const entries = Object.entries(SEVERITY_SCORES) as [Severity, number][];\n  const match = entries.find(([, score]) => score === maxScore);\n  return match ? match[0] : 'none';\n}\n\n/** Highest imminence among risks where subject is 'self' ('not_applicable' when there are none). */\nexport function calculateSpeakerImminence(risks: Risk[]): Imminence {\n  const speakerRisks = risks.filter((r) => r.subject === 'self');\n  if (speakerRisks.length === 0) return 'not_applicable';\n  const maxScore = Math.max(...speakerRisks.map((r) => IMMINENCE_SCORES[r.imminence]));\n  const entries = Object.entries(IMMINENCE_SCORES) as [Imminence, number][];\n  const match = entries.find(([, score]) => score === maxScore);\n  return match ? match[0] : 'not_applicable';\n}\n\n/** Whether any risk has subject 'other'. */\nexport function hasThirdPartyRisk(risks: Risk[]): boolean {\n  return risks.some((r) => r.subject === 'other');\n}\n\n// =============================================================================\n// Signpost Types (crisis resources: GET /v1/signpost/*)\n// =============================================================================\n\n/**\n * Filters for the basic signpost lookup. Arrays are sent comma-joined.\n */\nexport interface SignpostConfig {\n  /** Service scopes to filter by (e.g. 'suicide', 'domestic_violence'); see {@link ServiceScope}. */\n  scopes?: ServiceScope[];\n\n  /** Populations to filter by (e.g. 'youth', 'veterans', 'lgbtq'); see {@link Population}. */\n  populations?: Population[];\n\n  /** ISO 3166-2 subdivision codes within the country (e.g. 'US-CA', 'GB-NIR'). */\n  subdivisions?: string[];\n\n  /** Maximum number of resources (server cap 10). */\n  limit?: number;\n\n  /**\n   * Ranking hint, not a filter: among resources tied on relevance score and\n   * priority tier, place those flagged `is_24_7` first. Every matching\n   * resource is still returned.\n   */\n  urgent?: boolean;\n}\n\n/**\n * Options for signpost(). Filters may be given under `config` or at the top\n * level; a top-level value wins over the same key in `config`.\n */\nexport interface SignpostOptions extends SignpostConfig {\n  /** ISO 3166-1 alpha-2 country code (e.g. 'US', 'GB'). */\n  country: string;\n\n  /** Filters (alternative to the top-level keys). */\n  config?: SignpostConfig;\n}\n\n/** Response from GET /v1/signpost. */\nexport interface SignpostResponse {\n  /** Country code (ISO 3166-1 alpha-2). */\n  country: string;\n\n  /** Crisis resources. */\n  resources: CrisisResource[];\n\n  /** Number of resources returned. */\n  count: number;\n\n  /** Resources matching the requested scopes (only when scopes were given). */\n  primary?: CrisisResource[];\n\n  /** General resources (only when scopes were given). */\n  secondary?: CrisisResource[];\n\n  /** Scopes that were requested (only when given). */\n  scopes_requested?: string[];\n}\n\n/** Filters for signpostSmart(). The ranker returns up to 5 picks whatever `limit` says. */\nexport interface SignpostSmartConfig {\n  /** Service scopes to narrow the candidate pool; see {@link ServiceScope}. */\n  scopes?: ServiceScope[];\n\n  /** Populations to narrow the candidate pool; see {@link Population}. */\n  populations?: Population[];\n\n  /** Maximum number of ranked picks (at most 5 come back). */\n  limit?: number;\n}\n\n/** Options for signpostSmart(). */\nexport interface SignpostSmartOptions {\n  /** ISO 3166-1 alpha-2 country code. */\n  country: string;\n\n  /** Natural-language description of the situation (max 500 characters). */\n  query: string;\n\n  /** Optional filters. */\n  config?: SignpostSmartConfig;\n}\n\n/** A resource with its rank and a short relevance note. */\nexport interface RankedResource {\n  /** The crisis resource. */\n  resource: CrisisResource;\n\n  /** One or two sentences on why this resource fits the query. */\n  why: string;\n\n  /** Rank position (1 = most relevant). */\n  rank: number;\n}\n\n/** Response from GET /v1/signpost/smart (and /v1/try/signpost/smart). */\nexport interface SignpostSmartResponse {\n  /** Country code. */\n  country: string;\n\n  /** The query that was ranked. */\n  query: string;\n\n  /** Up to 5 resources ranked by relevance. */\n  ranked: RankedResource[];\n\n  /** Number of ranked resources. */\n  count: number;\n\n  /** Scopes that were requested (only when given). */\n  scopes_requested?: string[];\n\n  /** Present when the country has no candidate resources (ranked is empty). */\n  message?: string;\n\n  /** True when served by /v1/try/signpost/smart. */\n  try_endpoint?: boolean;\n}\n\n/** Response from GET /v1/signpost/:id. */\nexport interface SignpostByIdResponse {\n  /** The requested crisis resource. */\n  resource: CrisisResource;\n}\n\n/** Response from GET /v1/signpost/countries. */\nexport interface SignpostCountriesResponse {\n  /** Supported country codes (ISO 3166-1 alpha-2). */\n  countries: string[];\n\n  /** Number of countries. */\n  count: number;\n}\n\n/** Options for detectCountry(). */\nexport interface DetectCountryOptions {\n  /**\n   * Country to assert, sent as the `x-country` header. Useful when your own\n   * edge already knows the country: the API echoes it back in the typed\n   * shape.\n   */\n  countryHint?: string;\n}\n\n/**\n * Wire response from GET /v1/signpost/detect-country.\n *\n * Detection reads the geo headers a proxy injects (`cf-ipcountry`,\n * `x-country`, `x-vercel-ip-country`, `cf-region-code`, `cf-region`). A\n * direct call to api.nope.net has none of them and returns the miss shape\n * (`country_code: ''`, `error` set) with HTTP 200. `country_name` is also\n * `''` for any detected country outside the API's 36-entry name map; key on\n * `country_code`.\n */\nexport interface DetectCountryResponse {\n  /** Detected country code, or '' when not detected. */\n  country_code: string;\n\n  /** Human-readable country name, or '' when unknown. */\n  country_name: string;\n\n  /** ISO 3166-2 subdivision (e.g. 'US-CA', 'GB-SCT') when the proxy supplied a region. */\n  subdivision_code?: string;\n\n  /** Region name when the proxy supplied one. */\n  subdivision_name?: string;\n\n  /** Set on a miss. */\n  error?: string;\n}\n\n/** detectCountry() result: the wire response plus a derived `detected` flag. */\nexport interface DetectCountryResult extends DetectCountryResponse {\n  /** `country_code !== ''`. */\n  detected: boolean;\n}\n\n// -----------------------------------------------------------------------------\n// Signpost search (vector semantic search: GET /v1/signpost/search)\n// -----------------------------------------------------------------------------\n\n/** Options for signpostSearch(). */\nexport interface SignpostSearchOptions {\n  /** Natural-language search query (max 500 characters). */\n  query: string;\n\n  /** Optional ISO 3166-1 alpha-2 country code to filter results. */\n  country?: string;\n\n  /** Maximum number of results (default 10, max 50). */\n  limit?: number;\n\n  /** Similarity threshold in [0, 1] (default 0.3). Higher is stricter. */\n  threshold?: number;\n}\n\n/** A contact method on a search hit (the raw database record). */\n/**\n * One contact method on a search row, as the directory stores it. Only `type`\n * is always present: the live wire mixes `{type, value}`, `{type, url}`\n * (chat contacts), `{label, type, value}` and tiered rows with `source` and\n * `confidence` (fixture signpost/search.auth.mixed-contacts.json).\n */\nexport interface SignpostSearchContact {\n  /** Contact type: 'phone', 'sms', 'chat', 'email', 'whatsapp', ... */\n  type: string;\n  /** Number or address; chat contacts carry `url` instead. */\n  value?: string;\n  /** URL for chat and web contacts. */\n  url?: string;\n  /** Display label, when the directory has one. */\n  label?: string;\n  /** Contact tier as stored ('1' is primary); absent on untiered rows. */\n  tier?: string | number;\n  /** Where the contact was sourced. */\n  source?: string | null;\n  /** Confidence in the contact. */\n  confidence?: string | number;\n}\n\n/** Open status on a search hit; nulls where unknown. */\nexport interface SignpostSearchOpenStatus {\n  is_open: boolean | null;\n  next_change: string | null;\n  confidence: string;\n  message: string | null;\n}\n\n/**\n * A semantic-search hit. Search returns the raw resource row (plural field\n * names, explicit nulls) with tier-1 contacts flattened on top, so it does\n * not share {@link CrisisResource}'s shape. It is the only signpost result\n * that carries the database `id` today.\n */\nexport interface SignpostSearchResult {\n  id: string;\n  name: string;\n  name_local: string | null;\n  country_code: string;\n  subdivision_code: string | null;\n  country_codes: string[];\n  subdivision_codes: string[];\n  service_scopes: string[];\n  populations: string[];\n  description: string | null;\n  resource_type: string;\n  contacts: SignpostSearchContact[];\n  website_url: string | null;\n  is_24_7: boolean;\n  availability: string | null;\n  timezone: string | null;\n  opening_hours_osm: string | null;\n  hours_confidence: string | null;\n  languages: string[];\n  /** Cosine similarity to the query in [0, 1]. */\n  similarity: number;\n  /** Flattened tier-1 contacts. */\n  phone?: string;\n  sms_number?: string;\n  chat_url?: string;\n  whatsapp_url?: string;\n  email?: string;\n  line_url?: string;\n  telegram_url?: string;\n  wechat_id?: string;\n  /** `resource_type` as the CrisisResource modality. */\n  type: CrisisResourceType;\n  open_status: SignpostSearchOpenStatus;\n}\n\n/** Response from GET /v1/signpost/search. */\nexport interface SignpostSearchResponse {\n  /** The query that was run. */\n  query: string;\n\n  /** Country filter applied, or null when unfiltered. */\n  country: string | null;\n\n  /** Hits ranked by similarity. */\n  results: SignpostSearchResult[];\n\n  /** Number of hits. */\n  count: number;\n\n  /** Timing breakdown in milliseconds. */\n  timing: {\n    embed_ms: number;\n    search_ms: number;\n    total_ms: number;\n  };\n}\n\n// -----------------------------------------------------------------------------\n// Deprecated /v1/resources/* aliases (sunset 2027-01-01; use signpost*)\n// -----------------------------------------------------------------------------\n\n/** @deprecated Use SignpostConfig. Sunset 2027-01-01. */\nexport type ResourcesConfig = SignpostConfig;\n\n/** @deprecated Use SignpostOptions. Sunset 2027-01-01. */\nexport type ResourcesOptions = SignpostOptions;\n\n/** @deprecated Use SignpostResponse. Sunset 2027-01-01. */\nexport type ResourcesResponse = SignpostResponse;\n\n/** @deprecated Use SignpostSmartOptions. Sunset 2027-01-01. */\nexport type ResourcesSmartOptions = SignpostSmartOptions;\n\n/** @deprecated Use SignpostSmartResponse. Sunset 2027-01-01. */\nexport type ResourcesSmartResponse = SignpostSmartResponse;\n\n/** @deprecated Use SignpostByIdResponse. Sunset 2027-01-01. */\nexport type ResourceByIdResponse = SignpostByIdResponse;\n\n/** @deprecated Use SignpostCountriesResponse. Sunset 2027-01-01. */\nexport type ResourcesCountriesResponse = SignpostCountriesResponse;\n\n// =============================================================================\n// Oversight Types (for /v1/oversight/* endpoints)\n// =============================================================================\n\n/**\n * Concern level for AI behavior analysis: none, low, medium, high, critical.\n */\nexport type ConcernLevel = 'none' | 'low' | 'medium' | 'high' | 'critical';\n\n/**\n * Direction of concern across the conversation. In fast mode this is the\n * constant `stable` (no trajectory is computed).\n */\nexport type Trajectory = 'improving' | 'stable' | 'worsening';\n\n/** Severity of a detected behavior. */\nexport type OversightSeverity = 'low' | 'medium' | 'high' | 'critical';\n\n/** Human response indicators observed in the conversation. */\nexport type HumanIndicatorType =\n  | 'distress_markers'\n  | 'acquiescence'\n  | 'disengagement'\n  | 'escalation'\n  | 'pushback';\n\n/**\n * Analysis strategy (authenticated route only; the demo route ignores it).\n * - single: one pass over the conversation\n * - sliding: overlapping windows, for long conversations (50+ messages auto-selects it)\n */\nexport type OversightAnalysisStrategy = 'single' | 'sliding';\n\n/**\n * Analysis depth.\n * - full: default; narrative summary, pattern assessment, per-turn analysis\n * - fast: single pass on a faster model; `trajectory` is always `stable`,\n *   `turn_analysis` and `human_indicators` are empty, `summary` and\n *   `pattern_assessment` are absent\n */\nexport type OversightAnalysisMode = 'full' | 'fast';\n\n/** A message in an Oversight conversation. */\nexport interface OversightMessage {\n  /** Message role. */\n  role: 'user' | 'assistant' | 'system';\n\n  /** Message content. */\n  content: string;\n\n  /** Your identifier for this message. */\n  message_id?: string;\n\n  /** When this message was sent (ISO 8601). */\n  timestamp?: string;\n\n  /** Agent or bot identifier that produced this message (assistant messages). */\n  agent_id?: string;\n\n  /** Agent version string. */\n  agent_version?: string;\n\n  /** Retrieved RAG or memory context that informed this response. */\n  context?: string;\n}\n\n/** Metadata about an Oversight conversation. Extra keys are stored without indexing. */\nexport interface OversightConversationMetadata {\n  /** Hashed end-user identifier, for cross-session trajectory tracking. */\n  user_id_hash?: string;\n\n  /** Your session identifier. */\n  session_id?: string;\n\n  /** Session number for this user (1, 2, 3...). */\n  session_number?: number;\n\n  /** Whether the end-user is a minor (escalates severity). */\n  user_is_minor?: boolean;\n\n  /** Age bracket of the end-user. */\n  user_age_bracket?: 'child' | 'teen' | 'adult' | 'unknown';\n\n  /** Platform where the conversation occurred (e.g. 'ios', 'web', 'discord'). */\n  platform?: string;\n\n  /** Product or bot name. */\n  product?: string;\n\n  /** When the conversation started (ISO 8601). */\n  started_at?: string;\n\n  /** When the conversation ended (ISO 8601). */\n  ended_at?: string;\n\n  /** Your tags for categorisation. */\n  tags?: string[];\n\n  /** Additional fields are preserved but not indexed. */\n  [key: string]: unknown;\n}\n\n/** A conversation to analyze with Oversight. */\nexport interface OversightConversation {\n  /** Your identifier for the conversation (required for ingest). */\n  conversation_id?: string;\n\n  /** Messages in the conversation. The demo route accepts at most 20. */\n  messages: OversightMessage[];\n\n  /** Optional metadata about the conversation. */\n  metadata?: OversightConversationMetadata;\n}\n\n/** A detected behavior at a specific assistant turn. */\nexport interface DetectedBehavior {\n  /** Behavior code (see {@link OversightBehaviorCode}). */\n  code: string;\n\n  /** Severity of this instance. */\n  severity: OversightSeverity;\n\n  /** Assistant turn where the behavior was detected. Turns are numbered from 1. */\n  turn_number: number;\n\n  /** Evidence quote from the conversation. */\n  evidence: string;\n\n  /** Why this behavior was flagged. */\n  reasoning: string;\n}\n\n/** A behavior aggregated across turns. */\nexport interface AggregatedBehavior {\n  /** Behavior code (see {@link OversightBehaviorCode}). */\n  code: string;\n\n  /** Highest severity across instances. */\n  severity: OversightSeverity;\n\n  /** Number of turns where this behavior appeared (always 1 in fast mode). */\n  turn_count: number;\n\n  /** Actionable recommendation for correcting this behavior. */\n  recommendation?: string;\n}\n\n/** Per-turn analysis (assistant turns only). */\nexport interface TurnAnalysis {\n  /** Assistant turn number, numbered from 1. */\n  turn_number: number;\n\n  /** Always 'assistant'. */\n  role: 'assistant';\n\n  /** Brief summary of the turn. */\n  content_summary: string;\n\n  /** Behaviors detected in this turn. */\n  behaviors: DetectedBehavior[];\n\n  /** Whether the AI missed an opportunity to intervene. */\n  missed_intervention: boolean;\n}\n\n/** Human response indicator. */\nexport interface HumanIndicator {\n  /** Type of indicator. */\n  type: HumanIndicatorType;\n\n  /** What was observed. */\n  observation: string;\n\n  /** Turn numbers where this was observed (numbered from 1). */\n  turns: number[];\n}\n\n/** Analysis of one window in a sliding-window run. */\nexport interface WindowAnalysis {\n  /** Which messages the window covered. */\n  window: {\n    /** @deprecated Use message_range.start_index. Inclusive 0-based message index. */\n    start_turn: number;\n    /** @deprecated Use message_range.end_index_exclusive. Exclusive 0-based message index. */\n    end_turn: number;\n    /** Exact 0-based message slice used for this window. */\n    message_range?: {\n      start_index: number;\n      end_index_exclusive: number;\n    };\n    /** 1-based conversation turn range represented by this window. */\n    conversation_turn_range?: {\n      start_turn: number;\n      end_turn: number;\n    };\n  };\n\n  /** Concern level at this window. */\n  concern: ConcernLevel;\n\n  /** Behaviors detected within this window. */\n  behaviors: DetectedBehavior[];\n\n  /** Turn-by-turn analysis within the window. */\n  turn_analysis: TurnAnalysis[];\n\n  /** Human response indicators within the window. */\n  human_indicators: HumanIndicator[];\n\n  /** Summary of this window. */\n  summary: string;\n}\n\n/** A point where concern changed between consecutive windows. */\nexport interface InflectionPoint {\n  /** Conversation turn (1-based) where the change occurred. */\n  turn: number;\n\n  /** Concern before this turn. */\n  concern_before: ConcernLevel;\n\n  /** Concern after this turn. */\n  concern_after: ConcernLevel;\n\n  /** Behaviors that triggered the change. */\n  trigger_behaviors: string[];\n}\n\n/**\n * Filter applied to results after analysis (the model still sees the full\n * taxonomy). `enabled` and `disabled` are mutually exclusive when both are\n * non-empty.\n */\nexport interface OversightBehaviorFilter {\n  /** Only include these behavior codes (allowlist). */\n  enabled?: OversightBehaviorCode[];\n\n  /** Exclude these behavior codes (blocklist). */\n  disabled?: OversightBehaviorCode[];\n\n  /** Only include behaviors at or above this severity. */\n  min_severity?: OversightSeverity;\n\n  /** Only include behaviors from these categories. */\n  categories?: OversightBehaviorCategory[];\n}\n\n/** Result of an Oversight analysis. */\nexport interface OversightAnalysisResult {\n  /** Conversation identifier (yours, or one the API generated). */\n  conversation_id: string;\n\n  /** When the analysis ran (ISO 8601). */\n  analyzed_at: string;\n\n  /** Brief summary of the conversation (empty string in fast mode). */\n  conversation_summary: string;\n\n  /** Overall concern level. */\n  overall_concern: ConcernLevel;\n\n  /** Direction of concern (always 'stable' in fast mode). */\n  trajectory: Trajectory;\n\n  /** Operator-facing summary of key findings. Absent in fast mode. */\n  summary?: string;\n\n  /** Pattern assessment across turns. Absent in fast mode. */\n  pattern_assessment?: string;\n\n  /** Turn-by-turn analysis of assistant turns (empty in fast mode). */\n  turn_analysis: TurnAnalysis[];\n\n  /** Human response indicators (empty in fast mode). */\n  human_indicators: HumanIndicator[];\n\n  /** Behaviors aggregated across turns. */\n  detected_behaviors: AggregatedBehavior[];\n\n  /** Model used for the analysis. */\n  model_used?: string;\n\n  /** Analysis latency in milliseconds. */\n  latency_ms?: number;\n\n  /** Which analysis mode ran. */\n  mode_used?: OversightAnalysisMode;\n\n  /** The behavior filter that was applied, echoed back. */\n  filter_applied?: OversightBehaviorFilter;\n\n  /** Sliding strategy: per-window analyses. */\n  windows?: WindowAnalysis[];\n\n  /** Sliding strategy: concern level per window. */\n  concern_progression?: ConcernLevel[];\n\n  /** Sliding strategy: highest window concern. */\n  peak_concern?: ConcernLevel;\n\n  /** Sliding strategy: last window concern. */\n  final_concern?: ConcernLevel;\n\n  /** Sliding strategy: turns where concern changed. */\n  inflection_points?: InflectionPoint[];\n\n  /** Sliding strategy: context carried into the next window. */\n  context_for_next_window?: string;\n\n  /** Narrative summary for cross-session aggregation. */\n  narrative_summary?: string;\n\n  /** Prompt tokens used. */\n  prompt_tokens?: number;\n\n  /** Completion tokens used. */\n  completion_tokens?: number;\n\n  /** Raw model output (only when `include_raw_xml` was set). */\n  raw_xml?: string;\n}\n\n/** Configuration for oversight.analyze. */\nexport interface OversightAnalyzeConfig {\n  /** Force a strategy; auto-selected by length when omitted. Ignored by the demo route. */\n  strategy?: OversightAnalysisStrategy;\n\n  /** Analysis depth; defaults to 'full'. */\n  mode?: OversightAnalysisMode;\n\n  /** Include the raw model output in the response. */\n  include_raw_xml?: boolean;\n\n  /** Custom model identifier. Ignored by the demo route. */\n  model?: string;\n}\n\n/** Options for oversight.analyze. */\nexport interface OversightAnalyzeOptions {\n  /** Conversation to analyze. */\n  conversation: OversightConversation;\n\n  /**\n   * Free-form description of the bot or persona being analyzed, so expected\n   * behaviour (a companion persona saying \"I love you\") is not flagged.\n   * The API passes it into the analysis as conversation metadata.\n   */\n  bot_context?: string;\n\n  /** Configuration options. */\n  config?: OversightAnalyzeConfig;\n\n  /** Filter which behaviors appear in the results. */\n  behaviors?: OversightBehaviorFilter;\n}\n\n/** Response from POST /v1/oversight/analyze (authenticated). */\nexport interface OversightAnalyzeResponse {\n  /** Analysis result. */\n  result: OversightAnalysisResult;\n\n  /** Which strategy ran. */\n  strategy: OversightAnalysisStrategy;\n\n  /** Why that strategy was chosen. */\n  strategy_reason: string;\n}\n\n/** Response from POST /v1/try/oversight/analyze (demo mode). */\nexport interface OversightDemoAnalyzeResponse {\n  /** 'fast' when config.mode was 'fast', else 'single'. */\n  mode: 'single' | 'fast';\n\n  /** Analysis result. */\n  result: OversightAnalysisResult;\n\n  /** Always true. */\n  try_endpoint: true;\n}\n\n/** Response type of oversight.analyze for a client constructed with the given `demo` flag. */\nexport type OversightAnalyzeResponseFor<Demo extends boolean> = Demo extends true\n  ? OversightDemoAnalyzeResponse\n  : OversightAnalyzeResponse;\n\n/** Configuration for oversight.ingest. */\nexport interface OversightIngestConfig {\n  /** Custom model identifier. */\n  model?: string;\n}\n\n/** A conversation for ingest; `conversation_id` is required. */\nexport interface OversightIngestConversation extends OversightConversation {\n  conversation_id: string;\n}\n\n/** Options for oversight.ingest. */\nexport interface OversightIngestOptions {\n  /**\n   * Conversations to analyze and store (1 to 300). The request body is capped at\n   * 5 MB, so a batch near the count limit must consist of short conversations.\n   */\n  conversations: OversightIngestConversation[];\n\n  /**\n   * Legacy per-request callback. The API POSTs an unsigned\n   * `{ event: 'ingestion_complete', timestamp, ingestion_id, conversations_processed,\n   * errors_count, high_concern_count }` here when the batch completes. The signed\n   * `oversight.ingestion.complete` event is delivered to webhooks registered with\n   * `client.webhooks`, never to this URL.\n   */\n  webhook_url?: string;\n\n  /** Configuration options. */\n  config?: OversightIngestConfig;\n}\n\n/** A change the API made to a conversation before analysis. */\nexport interface TruncationWarning {\n  type: 'message_scaffolded' | 'message_truncated' | 'conversation_truncated';\n  details: string;\n}\n\n/** Per-conversation result from ingest. */\nexport interface OversightIngestConversationResult {\n  /** Your conversation id. */\n  conversation_id: string;\n\n  /** Overall concern level. */\n  overall_concern: ConcernLevel;\n\n  /** Number of behaviors detected. */\n  behaviors_detected: number;\n\n  /** Present when the conversation was modified before analysis. */\n  truncation_warnings?: TruncationWarning[];\n}\n\n/** Per-conversation error from ingest. */\nexport interface OversightIngestError {\n  /** Your conversation id. */\n  conversation_id: string;\n\n  /** Error message. */\n  error: string;\n}\n\n/**\n * Response from POST /v1/oversight/ingest.\n *\n * Ingest is synchronous today: the call returns after every conversation is\n * analyzed, `status` is `complete` or `failed` (failed only when every\n * conversation failed), and `estimated_completion` is never set. `queued`\n * and `processing` stay in the union for forward compatibility. Billing is\n * 100 mills per conversation, deducted before analysis with no per-\n * conversation refund.\n */\nexport interface OversightIngestResponse {\n  /** Ingestion id for tracking. */\n  ingestion_id: string;\n\n  /** Current status. */\n  status: 'queued' | 'processing' | 'complete' | 'failed';\n\n  /** Number of conversations received. */\n  conversations_received: number;\n\n  /** Number of conversations processed. */\n  conversations_processed: number;\n\n  /** Reserved; never set by the synchronous implementation. */\n  estimated_completion?: string;\n\n  /** Dashboard URL for the results. */\n  dashboard_url: string;\n\n  /** Per-conversation results (present when at least one succeeded). */\n  results?: OversightIngestConversationResult[];\n\n  /** Per-conversation errors (present when at least one failed). */\n  errors?: OversightIngestError[];\n}\n\n// =============================================================================\n// Ocular (behavioral risk assessment: POST /v1/ocular)\n// =============================================================================\n//\n// Models the post-filter customer surface the gateway emits. Individual\n// head-code identifiers are stripped upstream; only the demo route exposes\n// them, under public family names.\n\n/** Ensemble depth. `fast` is single-variant; `thorough` populates `stability`. */\nexport type OcularThoroughness = 'fast' | 'auto' | 'thorough';\n\n/** Per-axis level. */\nexport type OcularLevel = 'critical' | 'high' | 'moderate' | 'low' | 'minimal';\n\n/** Per-turn phase label in `trajectory_shape.phases`. */\nexport type OcularPhase = 'baseline' | 'emerging' | 'escalating' | 'de-escalating' | 'crisis';\n\n/** Options for client.ocular(). Either `messages` or `text` is required. */\nexport interface OcularOptions {\n  /** Conversation messages (roles user|assistant). The demo route accepts at most 12. */\n  messages?: Message[];\n\n  /** Plain text input (alternative to messages; demo route caps at 4,000 characters). */\n  text?: string;\n\n  /** Ensemble depth. Omit for the server default (`auto`). */\n  thoroughness?: OcularThoroughness;\n\n  /**\n   * Score the conversation turn by turn and return `trajectory` (one entry\n   * per scored turn; `turn` is the 0-based position in `messages`) and\n   * `trajectory_shape`. Off by default; without it the response carries\n   * neither field. Which turns are scored depends on `trajectory_stride`.\n   * The demo route returns `trajectory` but never `trajectory_shape`.\n   */\n  per_turn?: boolean;\n\n  /**\n   * With per_turn: score every Nth turn, counted backward from the last\n   * turn so the final turn is always scored (1..64). The server default is\n   * 3, so a 5-message conversation yields turns 4 and 1. Pass 1 to score\n   * every turn.\n   */\n  trajectory_stride?: number;\n\n  /** Opaque end-user id (1..256 chars) for dashboard analytics. Never forwarded to the model. */\n  user_id?: string;\n\n  /** Opaque session id (1..256 chars) for dashboard analytics. Never forwarded to the model. */\n  session_id?: string;\n\n  /** Opaque agent id (1..256 chars) for dashboard analytics. Never forwarded to the model. */\n  agent_id?: string;\n}\n\n/** Per-axis output: level plus raw score in [0, 1]. */\nexport interface OcularAxis {\n  level: OcularLevel;\n  score: number;\n}\n\nexport type OcularAxisGroup = Record<string, OcularAxis>;\n\n/**\n * Per-axis signal groups.\n *\n * `user` carries 8 axes: suicide, self_harm, harm_to_others, abuse,\n * sexual_violence, exploitation, stalking, self_neglect.\n *\n * `ai` carries 4 axes: harm_provision, emotional_failure, manipulation,\n * safeguarding_failure.\n */\nexport interface OcularSignals {\n  user: OcularAxisGroup;\n  ai: OcularAxisGroup;\n}\n\n/**\n * Per-axis stability in [0, 1] across the variants Ocular ran (higher = more\n * consistent). Present only on multi-variant calls; otherwise `null`.\n */\nexport interface OcularStability {\n  user: Record<string, number>;\n  ai: Record<string, number>;\n  imminence: number;\n}\n\n/** Per-turn trajectory entry (only with `per_turn: true`). */\nexport interface OcularTrajectoryEntry {\n  /** 0-based position of the turn in `messages` (for `text` input, of the parsed speaker turn). */\n  turn: number;\n\n  /**\n   * Speaker of the turn: `user` or `assistant` (the gateway maps the\n   * upstream `ai` label to `assistant`). Declared as string because any\n   * other upstream label passes through unchanged.\n   */\n  role: string;\n\n  /** Per-turn salience, same cascade as the top-level field. */\n  salience: number;\n\n  /**\n   * Per-turn axis scores keyed by the public axis vocabulary: user axes by\n   * bare name (`suicide`), AI axes prefixed (`ai_manipulation`), plus the\n   * `fiction` and `genuine` context scalars. Absent when the turn had none.\n   */\n  signals_by_axis?: Record<string, number>;\n}\n\n/**\n * Arc summary of a per-turn trajectory (only with `per_turn: true`). The\n * phase, slope and peak fields track the suicide (crisis) axis and index\n * the `trajectory` array (entry i, not message i); `onsets` spans every\n * axis and uses `turn` values. The authenticated route returns it whenever\n * at least one turn was scored; the demo route never returns it. Every key\n * is optional.\n */\nexport interface OcularTrajectoryShape {\n  /** axis -> the `turn` value (0-based message position) at which that axis first crossed its onset threshold. */\n  onsets?: Record<string, number>;\n\n  /** Phase label per `trajectory` entry: `phases[i]` describes `trajectory[i]`. */\n  phases?: OcularPhase[];\n\n  /** Crisis-axis slope per `trajectory` entry: the delta versus the previous scored turn; the first is 0. */\n  slopes?: number[];\n\n  /**\n   * Position in the `trajectory` array of the entry with the highest\n   * crisis-axis score; `trajectory[peak_turn].turn` is the message index.\n   */\n  peak_turn?: number;\n\n  /** Highest crisis-axis score across the scored turns. */\n  peak_crisis?: number;\n}\n\n/** Response metadata. `windowed` and `windows` are always present (`false`, `1` for unwindowed input). */\nexport interface OcularMeta {\n  /** Ocular model build identifier. */\n  version: string;\n\n  /** Upstream inference time (ms). */\n  inference_ms: number;\n\n  /** Whether the input was split into windows at the gateway. */\n  windowed?: boolean;\n\n  /** Number of windows the input was split into. */\n  windows?: number;\n\n  /** True if any window's content was truncated to fit. */\n  truncated?: boolean;\n}\n\n/**\n * Response from POST /v1/ocular ($0.0001 per call).\n *\n * Decisions key off the continuous `salience` score in [0, 1] plus the axes\n * under `signals.user` (8) and `signals.ai` (4). Reference cutoffs are\n * T_WATCH = 0.30 and T_DANGER = 0.60 (docs.nope.net/ocular). `fiction` and\n * `authenticity` are context modulators already factored into `salience`.\n * `trajectory` and `trajectory_shape` are present only when the request set\n * `per_turn: true`.\n */\nexport interface OcularResponse {\n  /** Continuous severity score in [0, 1]. */\n  salience: number;\n\n  /** Who the speaker-side risk pertains to ('self', 'other', 'unknown'). */\n  subject: string;\n\n  /** How urgent the concern is (a separate axis). */\n  imminence: OcularAxis;\n\n  /** Roleplay or fiction-framing strength in [0, 1]. */\n  fiction: number;\n\n  /** Authenticity-of-distress signal in [0, 1]. */\n  authenticity: number;\n\n  /** 8 user-risk axes and 4 AI-behavior axes. */\n  signals: OcularSignals;\n\n  /** Which ensemble depth ran. */\n  thoroughness: OcularThoroughness;\n\n  /** Aggregate confidence across variants; null on single-variant calls. */\n  confidence: number | null;\n\n  /** Per-axis stability across variants; null on single-variant calls. */\n  stability: OcularStability | null;\n\n  /** Response metadata. */\n  meta: OcularMeta;\n\n  /** Per-turn trail (only with `per_turn: true`): one entry per scored turn, every `trajectory_stride`-th turn back from the last. */\n  trajectory?: OcularTrajectoryEntry[];\n\n  /** Arc summary of the trail (only with `per_turn: true`; never on the demo route). */\n  trajectory_shape?: OcularTrajectoryShape;\n}\n\n/** A screening head on the demo surface, under its public family name. */\nexport interface OcularHead {\n  code: string;\n  score: number;\n}\n\n/** Demo per-turn entry; may also carry the turn's screening heads. */\nexport interface OcularDemoTrajectoryEntry extends OcularTrajectoryEntry {\n  heads?: OcularHead[];\n}\n\n/**\n * Response from POST /v1/try/ocular (demo mode). The customer fields plus\n * screening `heads` and per-head `detail.scores` / `detail.calibrated`,\n * keyed by public family names such as `USER_SUICIDE_HEAD_A`. The demo\n * route returns `trajectory` with `per_turn` but never `trajectory_shape`.\n */\nexport interface OcularDemoResponse extends OcularResponse {\n  heads: OcularHead[];\n  detail: {\n    scores: Record<string, number>;\n    calibrated: Record<string, number>;\n  };\n  trajectory?: OcularDemoTrajectoryEntry[];\n}\n\n/** Response type of ocular() for a client constructed with the given `demo` flag. */\nexport type OcularResponseFor<Demo extends boolean> = Demo extends true ? OcularDemoResponse : OcularResponse;\n// =============================================================================\n// Billing (GET /v1/billing/*)\n// =============================================================================\n//\n// Shapes from api/src/routes/v1/billing.ts, checked against the captured\n// fixtures under tests/fixtures/billing/. All amounts are in mills\n// (1 mill = $0.001).\n\n/** A top-up denomination. */\nexport interface BillingTopupOption {\n  id: string;\n  amount_mills: number;\n  /** e.g. '$10'. */\n  label: string;\n  /** Screens this amount buys. */\n  screens: number;\n  /** Evaluate calls this amount buys. */\n  evaluates: number;\n  /** Smart signpost calls this amount buys. */\n  resources_smart: number;\n}\n\n/** A past top-up. */\nexport interface BillingTopupRecord {\n  id: string;\n  amount_mills: number;\n  amount_formatted: string;\n  status: string;\n  created_at: string;\n  completed_at: string | null;\n}\n\n/** Response from GET /v1/billing/balance. */\nexport interface BillingBalanceResponse {\n  balance_mills: number;\n  /** e.g. '$12.35'. */\n  balance_formatted: string;\n  /** Screens the balance covers. */\n  estimated_screens: number;\n  /** Evaluate calls the balance covers. */\n  estimated_evaluates: number;\n  /** Smart signpost calls the balance covers. */\n  estimated_resources_smart: number;\n  low_balance: boolean;\n  topup_history: BillingTopupRecord[];\n  topup_options: BillingTopupOption[];\n}\n\n/** Options for billing.usage(). Dates are ISO 8601; default is the current month. */\nexport interface BillingUsageOptions {\n  start_date?: string;\n  end_date?: string;\n}\n\n/** Per-endpoint usage line. */\nexport interface BillingUsageBreakdown {\n  /** Endpoint key (e.g. 'evaluate', 'oversight_analyze', 'v0_screen'). */\n  endpoint: string;\n  calls: number;\n  cost_mills: number;\n  cost_formatted: string;\n  /** Calls that triggered a referral. */\n  referrals: number;\n}\n\n/** Response from GET /v1/billing/usage. */\nexport interface BillingUsageResponse {\n  period_start: string;\n  /** null when no end_date was given. */\n  period_end: string | null;\n  total_spend_mills: number;\n  total_spend_formatted: string;\n  breakdown: BillingUsageBreakdown[];\n}\n\n/** Options for billing.usageHistory(). */\nexport interface BillingUsageHistoryOptions {\n  /** Page size (default 50, max 100). */\n  limit?: number;\n  offset?: number;\n  /** Filter to one endpoint path. */\n  endpoint?: string;\n  start_date?: string;\n  end_date?: string;\n}\n\n/** One billed call. */\nexport interface BillingUsageRecord {\n  id: string;\n  endpoint: string;\n  cost_mills: number;\n  cost_formatted: string;\n  metadata: Record<string, unknown> | null;\n  created_at: string;\n}\n\n/** Response from GET /v1/billing/usage/history. */\nexport interface BillingUsageHistoryResponse {\n  records: BillingUsageRecord[];\n  total: number;\n  limit: number;\n  offset: number;\n}\n\n/** One priced endpoint. */\nexport interface BillingPricingEntry {\n  cost_mills: number;\n  /** e.g. '$0.003' or 'Free'. */\n  cost_display: string;\n  description?: string;\n}\n\n/** Pricing by endpoint key. Unknown keys are tolerated. */\nexport interface BillingPricingTable {\n  evaluate: BillingPricingEntry;\n  ocular: BillingPricingEntry;\n  signpost_smart: BillingPricingEntry;\n  resources_smart: BillingPricingEntry;\n  oversight_analyze: BillingPricingEntry;\n  /** Billed per conversation. */\n  oversight_ingest: BillingPricingEntry;\n  v0_screen: BillingPricingEntry;\n  /** Alias of v0_screen. */\n  screen: BillingPricingEntry;\n  v0_evaluate: BillingPricingEntry;\n  [endpoint: string]: BillingPricingEntry | undefined;\n}\n\n/** Response from GET /v1/billing/pricing (public, no key). */\nexport interface BillingPricingResponse {\n  /** 'mills'. */\n  unit: string;\n  unit_description: string;\n  pricing: BillingPricingTable;\n  topup_options: BillingTopupOption[];\n  free_credit_mills: number;\n  free_credit_display: string;\n}\n\n/** Options for billing.topup(). */\nexport interface BillingTopupOptions {\n  /** One of the topup_options amounts (10000, 25000, 50000, 100000). */\n  amount_mills: number;\n  /** Where Stripe sends the user after payment (default: the dashboard). */\n  success_url?: string;\n  /** Where Stripe sends the user on cancel (default: the dashboard). */\n  cancel_url?: string;\n}\n\n/** Response from POST /v1/billing/topup. */\nexport interface BillingTopupResponse {\n  /** Stripe Checkout URL to redirect the user to. */\n  checkout_url: string;\n}\n","/**\n * Webhook verification and payload types.\n *\n * NOPE signs every delivery with HMAC-SHA256 over `\"${timestamp}.${body}\"`\n * where `body` is the exact bytes it sent (JSON.stringify of the payload),\n * and sets these headers:\n *\n *   X-NOPE-Signature:   sha256=<hex>\n *   X-NOPE-Timestamp:   <unix seconds>\n *   X-NOPE-Event:       evaluate.alert | oversight.alert | oversight.ingestion.complete | test.ping\n *   X-NOPE-Delivery-ID: id of the stored delivery (the `id` of the matching\n *                       WebhookEvent from client.webhooks.events()); retries\n *                       of one delivery repeat it. Distinct from the\n *                       payload's `event_id`.\n *   X-NOPE-Webhook-ID:  <webhook id>\n *\n * Pass the raw request body (string or bytes) to `verify` / `verifyRequest`.\n * Passing an already-parsed object also works (the SDK re-serialises it with\n * JSON.stringify), but only when your JSON parser preserved key order, so the\n * raw body is the supported input.\n *\n * @example\n * ```typescript\n * import { Webhook, WebhookSignatureError } from '@nope-net/sdk';\n *\n * app.post('/webhooks/nope', express.raw({ type: 'application/json' }), (req, res) => {\n *   try {\n *     const { payload } = Webhook.verifyRequest(req.body, req.headers, process.env.NOPE_WEBHOOK_SECRET!);\n *     if (payload.event === 'evaluate.alert') {\n *       console.log(payload.risk_summary.overall_severity);\n *     }\n *     res.status(200).send('OK');\n *   } catch (err) {\n *     if (err instanceof WebhookSignatureError) res.status(401).send('Invalid signature');\n *     else throw err;\n *   }\n * });\n * ```\n */\n\nimport { createHmac, timingSafeEqual } from 'node:crypto';\nimport type { Severity, Imminence, ConcernLevel, Trajectory } from './types.js';\n\n// =============================================================================\n// Payload types (copied field-for-field from api/lib/webhooks/types.ts)\n// =============================================================================\n\n/** Webhook event types. */\nexport type WebhookEventType = 'evaluate.alert' | 'oversight.alert' | 'oversight.ingestion.complete' | 'test.ping';\n\n/** Risk level threshold for webhook filtering (`min_risk_level`). */\nexport type WebhookRiskLevel = 'none' | 'low' | 'medium' | 'high' | 'critical';\n\n/** Risk summary on an evaluate.alert payload. */\nexport interface WebhookRiskSummary {\n  overall_severity: Severity;\n  overall_imminence: Imminence;\n  /** Risk type of the highest self-directed risk, or 'none'. */\n  primary_domain: string;\n  confidence: number;\n  /**\n   * Narrative of the key concerns. Declared as a string by the API; the\n   * builder copies the classifier's value through, which has been seen as an\n   * array of strings on the wire.\n   */\n  primary_concerns: string | string[];\n}\n\n/** Per-risk assessment on an evaluate.alert payload. */\nexport interface WebhookDomainAssessment {\n  domain: string;\n  severity: Severity;\n  imminence: Imminence;\n}\n\n/** Safeguarding flags on an evaluate.alert payload. */\nexport interface WebhookFlags {\n  intimate_partner_violence: string | null;\n  child_safeguarding: string | null;\n  third_party_threat: boolean;\n}\n\n/** A resource that was included in the API response. */\nexport interface WebhookResourceProvided {\n  name: string;\n  type: string;\n  country: string;\n}\n\n/** Conversation content (only when the webhook has include_conversation). */\nexport interface WebhookConversation {\n  included: boolean;\n  message_count?: number;\n  /** Latest user message, truncated to 1,000 characters. */\n  latest_user_message?: string;\n  truncated?: boolean;\n}\n\n/** Fields shared by every event. */\nexport interface WebhookPayloadBase {\n  /** Event type. */\n  event: WebhookEventType;\n\n  /**\n   * Unique event id (`evt_<32 hex>`), generated when the payload is built.\n   * The X-NOPE-Delivery-ID header carries a different value: the stored\n   * delivery's id. Retries repeat both, so either one deduplicates.\n   */\n  event_id: string;\n\n  /** ISO 8601 creation time. */\n  timestamp: string;\n\n  /** Payload format version. */\n  api_version: '2025-01';\n}\n\n/** Sent when /v1/evaluate detects risk at or above the webhook's min_risk_level. */\nexport interface EvaluateAlertPayload extends WebhookPayloadBase {\n  event: 'evaluate.alert';\n\n  /** Your conversation_id from the evaluate request, if any. */\n  conversation_id?: string;\n\n  /** Your end_user_id from the evaluate request, if any. */\n  user_id?: string;\n\n  risk_summary: WebhookRiskSummary;\n\n  /** Per-domain assessments. */\n  domains: WebhookDomainAssessment[];\n\n  flags: WebhookFlags;\n\n  /** Resources that were provided in the API response. */\n  resources_provided: WebhookResourceProvided[];\n\n  conversation: WebhookConversation;\n}\n\n/** A behavior on an oversight.alert payload (up to 5). */\nexport interface OversightAlertBehavior {\n  code: string;\n  name: string;\n  severity: string;\n  category: string;\n}\n\n/** Sent when Oversight (analyze or ingest) finds high or critical concern. */\nexport interface OversightAlertPayload extends WebhookPayloadBase {\n  event: 'oversight.alert';\n\n  conversation_id: string;\n\n  /** Concern level that triggered the alert. */\n  concern: 'high' | 'critical';\n\n  trajectory: Trajectory;\n\n  /** Human-readable summary of the analysis. */\n  summary: string;\n\n  /** Top behaviors detected (up to 5). */\n  behaviors: OversightAlertBehavior[];\n\n  /** Agent ids involved in the conversation. */\n  agent_ids?: string[];\n\n  /** Platform from the conversation metadata. */\n  platform?: string;\n\n  user_is_minor: boolean;\n\n  /** Conversation content (only when the webhook has include_conversation). */\n  conversation?: WebhookConversation;\n}\n\n/** Sent when an ingest batch finishes. */\nexport interface OversightIngestionCompletePayload extends WebhookPayloadBase {\n  event: 'oversight.ingestion.complete';\n\n  ingestion_id: string;\n\n  conversations_total: number;\n\n  conversations_processed: number;\n\n  conversations_failed: number;\n\n  /** Count of conversations at each concern level. */\n  concerns: Record<ConcernLevel, number>;\n\n  /** Top behaviors across the batch. */\n  top_behaviors: Array<{\n    code: string;\n    name: string;\n    occurrence_count: number;\n  }>;\n\n  processing_time_ms: number;\n}\n\n/** Sent by the dashboard \"test\" button and by client.webhooks.test(). */\nexport interface TestPingPayload extends WebhookPayloadBase {\n  event: 'test.ping';\n\n  message: string;\n}\n\n/** Every webhook payload, discriminated on `event`. */\nexport type WebhookPayload =\n  | EvaluateAlertPayload\n  | OversightAlertPayload\n  | OversightIngestionCompletePayload\n  | TestPingPayload;\n\n// =============================================================================\n// Errors\n// =============================================================================\n\n/** Thrown when signature verification fails or the timestamp is out of range. */\nexport class WebhookSignatureError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = 'WebhookSignatureError';\n  }\n}\n\n// =============================================================================\n// Verification\n// =============================================================================\n\nexport interface WebhookVerifyOptions {\n  /**\n   * Maximum age of the timestamp in seconds, in either direction (default\n   * 300). Set to 0 to disable the check (not recommended).\n   */\n  maxAgeSeconds?: number;\n}\n\n/** Raw body (string or bytes, preferred) or an already-parsed object. */\nexport type WebhookBody = string | Uint8Array | object;\n\n/** Node's IncomingHttpHeaders, a fetch Headers instance, or any header map. */\nexport type WebhookHeaders =\n  | { get(name: string): string | null }\n  | Record<string, string | string[] | undefined>;\n\n/** Result of verifyRequest. */\nexport interface VerifiedWebhook {\n  /** The verified, parsed payload. */\n  payload: WebhookPayload;\n  /**\n   * The X-NOPE-Delivery-ID header: the stored delivery's id, repeated on\n   * each retry of that delivery, so it deduplicates the API's retries. It\n   * is not `payload.event_id`. Undefined when the header is absent, for\n   * example on a body signed locally with `Webhook.sign`.\n   */\n  deliveryId?: string;\n  /** @deprecated Use deliveryId; this is the X-NOPE-Delivery-ID header, not payload.event_id. */\n  eventId?: string;\n  /** The X-NOPE-Webhook-ID header: id of the webhook endpoint that received the delivery. */\n  webhookId?: string;\n  /**\n   * The X-NOPE-Event header: the event type (`evaluate.alert`,\n   * `oversight.alert`, `oversight.ingestion.complete` or `test.ping`). The\n   * same value is `payload.event`; the header lets you route before\n   * parsing. Undefined when the header is absent.\n   */\n  eventType?: string;\n}\n\nconst DEFAULT_MAX_AGE_SECONDS = 300;\n\nfunction toBytes(body: WebhookBody): Buffer {\n  if (typeof body === 'string') return Buffer.from(body, 'utf8');\n  if (body instanceof Uint8Array) return Buffer.from(body);\n  return Buffer.from(JSON.stringify(body), 'utf8');\n}\n\nfunction computeSignature(secret: string, timestamp: string, bodyBytes: Buffer): string {\n  return createHmac('sha256', secret).update(`${timestamp}.`).update(bodyBytes).digest('hex');\n}\n\nfunction readHeader(headers: WebhookHeaders, name: string): string | undefined {\n  if (typeof (headers as { get?: unknown }).get === 'function') {\n    return (headers as { get(name: string): string | null }).get(name) ?? undefined;\n  }\n  const map = headers as Record<string, string | string[] | undefined>;\n  const key = Object.keys(map).find((k) => k.toLowerCase() === name);\n  const value = key === undefined ? undefined : map[key];\n  return Array.isArray(value) ? value[0] : value;\n}\n\n/**\n * Webhook verification and signing.\n */\nexport const Webhook = {\n  /**\n   * Verify a delivery and return its parsed payload.\n   *\n   * @param payload - Raw request body (string or bytes, preferred) or the parsed object\n   * @param signature - X-NOPE-Signature header value\n   * @param timestamp - X-NOPE-Timestamp header value (unix seconds)\n   * @param secret - Your webhook signing secret (`whsec_...`)\n   * @param options - `maxAgeSeconds` (default 300; 0 disables)\n   * @throws WebhookSignatureError when a header is missing, the timestamp is out of range, or the signature does not match\n   */\n  verify(\n    payload: WebhookBody,\n    signature: string | undefined,\n    timestamp: string | undefined,\n    secret: string,\n    options: WebhookVerifyOptions = {}\n  ): WebhookPayload {\n    const { maxAgeSeconds = DEFAULT_MAX_AGE_SECONDS } = options;\n\n    if (!signature) throw new WebhookSignatureError('Missing X-NOPE-Signature header');\n    if (!timestamp) throw new WebhookSignatureError('Missing X-NOPE-Timestamp header');\n    if (!secret) throw new WebhookSignatureError('Webhook secret is required');\n\n    const timestampNum = Number.parseInt(timestamp, 10);\n    if (Number.isNaN(timestampNum)) throw new WebhookSignatureError('Invalid timestamp format');\n\n    if (maxAgeSeconds > 0) {\n      const age = Math.floor(Date.now() / 1000) - timestampNum;\n      if (age > maxAgeSeconds) {\n        throw new WebhookSignatureError(`Timestamp too old: ${age}s ago (max: ${maxAgeSeconds}s)`);\n      }\n      if (age < -maxAgeSeconds) {\n        throw new WebhookSignatureError(`Timestamp too far in future: ${-age}s ahead (max: ${maxAgeSeconds}s)`);\n      }\n    }\n\n    const bodyBytes = toBytes(payload);\n    const expected = Buffer.from(computeSignature(secret, timestamp, bodyBytes));\n    const received = Buffer.from(signature.replace(/^sha256=/, ''));\n    const valid = expected.length === received.length && timingSafeEqual(expected, received);\n    if (!valid) throw new WebhookSignatureError('Signature verification failed');\n\n    if (typeof payload === 'string' || payload instanceof Uint8Array) {\n      return JSON.parse(bodyBytes.toString('utf8')) as WebhookPayload;\n    }\n    return payload as WebhookPayload;\n  },\n\n  /**\n   * Verify a delivery from its raw body and request headers.\n   *\n   * Reads `x-nope-signature` and `x-nope-timestamp` (case-insensitive) from\n   * a Node `IncomingHttpHeaders` object, a fetch `Headers` instance, or any\n   * plain map, and returns the payload with `deliveryId`\n   * (X-NOPE-Delivery-ID), `webhookId` (X-NOPE-Webhook-ID) and `eventType`\n   * (X-NOPE-Event). Each id is undefined when its header is absent.\n   *\n   * @param body - Raw request body (string or bytes, preferred) or the parsed object\n   * @param headers - Request headers\n   * @param secret - Your webhook signing secret\n   * @param options - `maxAgeSeconds` (default 300; 0 disables)\n   */\n  verifyRequest(\n    body: WebhookBody,\n    headers: WebhookHeaders,\n    secret: string,\n    options: WebhookVerifyOptions = {}\n  ): VerifiedWebhook {\n    const payload = Webhook.verify(\n      body,\n      readHeader(headers, 'x-nope-signature'),\n      readHeader(headers, 'x-nope-timestamp'),\n      secret,\n      options\n    );\n    const deliveryId = readHeader(headers, 'x-nope-delivery-id');\n    return {\n      payload,\n      deliveryId,\n      eventId: deliveryId,\n      webhookId: readHeader(headers, 'x-nope-webhook-id'),\n      eventType: readHeader(headers, 'x-nope-event'),\n    };\n  },\n\n  /**\n   * Sign a body the way the API does (for tests and local replay).\n   *\n   * The optional third argument fixes the timestamp the HMAC is bound to.\n   * Omit it to sign as of now; pass a unix-seconds value to produce a\n   * delivery from a chosen moment, for example one older than\n   * `maxAgeSeconds` to exercise the stale-timestamp rejection.\n   *\n   * @param payload - Body to sign: a string or bytes as-is, or an object serialised with JSON.stringify\n   * @param secret - Signing secret\n   * @param timestamp - Unix seconds (an integer; defaults to now)\n   * @returns `signature` (`sha256=<hex>`) and `timestamp` as strings\n   */\n  sign(payload: WebhookBody, secret: string, timestamp?: number): { signature: string; timestamp: string } {\n    const ts = String(timestamp ?? Math.floor(Date.now() / 1000));\n    return {\n      signature: `sha256=${computeSignature(secret, ts, toBytes(payload))}`,\n      timestamp: ts,\n    };\n  },\n};\n\n// =============================================================================\n// Management types (client.webhooks.*; api/src/routes/v1/webhooks.ts)\n// =============================================================================\n\n/** Body of client.webhooks.create(). */\nexport interface WebhookCreateOptions {\n  /** HTTPS endpoint (http is accepted for localhost only; private ranges are rejected). */\n  url: string;\n  /** Minimum risk level that triggers a delivery (default 'high'). */\n  min_risk_level?: WebhookRiskLevel;\n  /** Include the latest user message in payloads (default false). */\n  include_conversation?: boolean;\n}\n\n/** Body of client.webhooks.update(). */\nexport interface WebhookUpdateOptions {\n  url?: string;\n  min_risk_level?: WebhookRiskLevel;\n  enabled?: boolean;\n  include_conversation?: boolean;\n}\n\n/** A webhook configuration. `secret` is present only on create and regenerateSecret. */\nexport interface WebhookResponse {\n  id: string;\n  url: string;\n  min_risk_level: WebhookRiskLevel;\n  enabled: boolean;\n  include_conversation: boolean;\n  created_at: string;\n  updated_at: string;\n  /** Signing secret (`whsec_...`). Returned once, on create. */\n  secret?: string;\n}\n\n/** Response from client.webhooks.list(). */\nexport interface WebhookListResponse {\n  webhooks: WebhookResponse[];\n}\n\n/** Response from client.webhooks.delete(). */\nexport interface WebhookDeleteResponse {\n  success: true;\n}\n\n/** Response from client.webhooks.regenerateSecret(). */\nexport interface WebhookSecretResponse {\n  /** The new signing secret. The old one stops working immediately. */\n  secret: string;\n}\n\n/** Result of a delivery attempt (client.webhooks.test()). */\nexport interface WebhookDeliveryResult {\n  success: boolean;\n  http_status?: number;\n  error_message?: string;\n  duration_ms: number;\n}\n\n/** Delivery status of a stored event. */\nexport type WebhookDeliveryStatus = 'pending' | 'sent' | 'failed';\n\n/** A stored delivery (client.webhooks.events()). */\nexport interface WebhookEvent {\n  id: string;\n  webhook_id: string;\n  event_type: WebhookEventType;\n  payload: WebhookPayload;\n  status: WebhookDeliveryStatus;\n  http_status?: number;\n  error_message?: string;\n  /** Attempts so far (the API retries 4 times: immediately, 1 min, 10 min, 1 h). */\n  attempt_count: number;\n  last_attempt_at?: string;\n  next_retry_at?: string;\n  created_at: string;\n}\n\n/** Options for client.webhooks.events(). */\nexport interface WebhookEventsOptions {\n  /** Max events (default 50, max 100). */\n  limit?: number;\n}\n\n/** Response from client.webhooks.events(). */\nexport interface WebhookEventsResponse {\n  events: WebhookEvent[];\n}\n"],"mappings":"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EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMO,IAAM,cAAc;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;AC/HO,IAAM,uCAAuC;AAAA,EAClD,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,4BAA4B;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,qBAAqB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,0BAA0B;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB;AAAA,IACA;AAAA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","names":[]}