/** * Provider error types for the DashCaddy Private Network abstraction * (DC-140, specs/PRIVATE-NETWORK-SPEC.md §3). * * Every provider-facing failure surfaces as a ProviderError carrying a * machine-readable `code` and a `retryable` hint, so feature modules can * degrade cleanly without knowing which provider is active. * * Canonical codes (providers may add, but these are the shared vocabulary): * - not_configured provider has no credentials yet * - unauthorized token rejected (401/403) * - not_found entity does not exist upstream * - rate_limited upstream 429 (retryable, honor retryAfter) * - server_error upstream 5xx (retryable) * - network_error transport failure (retryable) * - bad_input caller passed invalid arguments * - not_implemented_in_provider capability exists but lands in a later DC * - provider_not_active registry has no active provider */ 'use strict'; /** Codes for which a retry (possibly after a backoff) is reasonable. */ const RETRYABLE_CODES = new Set(['rate_limited', 'server_error', 'network_error']); class ProviderError extends Error { /** * @param {string} message - human-readable description * @param {object} [opts] * @param {string} [opts.code='unknown'] - machine-readable error code * @param {boolean} [opts.retryable] - defaults to derived-from-code * @param {*} [opts.cause] - original error (e.g. TailscaleCoordError) * @param {*} [opts.retryAfter] - upstream retry-after hint, seconds */ constructor(message, { code, retryable, cause, retryAfter } = {}) { super(message); this.name = 'ProviderError'; this.code = code || 'unknown'; this.retryable = retryable !== undefined ? !!retryable : RETRYABLE_CODES.has(this.code); if (retryAfter !== undefined) this.retryAfter = retryAfter; if (cause !== undefined) this.cause = cause; } } /** * Thrown by the registry when no provider has been activated yet * (default state until the setup wizard connects one — DC-152). */ class ProviderNotActiveError extends ProviderError { constructor(message) { super(message || 'No active network provider configured', { code: 'provider_not_active', retryable: false, }); this.name = 'ProviderNotActiveError'; } } module.exports = { ProviderError, ProviderNotActiveError };