DC-140: network provider abstraction (src/network/) + tailscale provider + registry + tests
This commit is contained in:
7 files changed
+1308
No files matched your search
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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 };
|
||||
Reference in new issue
Block a user