You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
7.9 KiB

import {
CodeError,
errCode,
moduleSeed,
type ErrCode,
type ErrorMessages,
type ModuleSeed
} from '$libs/errs';
import { STORAGE_MODULE } from './consts.ts';
// ── Error codes ────────────────────────────────────────────────────────
//
// All error identity for the `stor` artifact lives here. Each constant
// is the code passed to `CodeError`; consumers that need to discriminate
// errors by family (logs, error boundaries, i18n) match against these.
export const STORAGE_ERR: ModuleSeed = moduleSeed(STORAGE_MODULE);
/** Generic kind: a value did not match the expected type (e.g. a serializer
* received an unparseable string). The native `TypeError` carrying the
* specific failure goes into `cause`. */
export const STORAGE_ERR_INVALID_TYPE: ErrCode = errCode(STORAGE_ERR, 'invalid_type');
/** `entry()` was registered with `defaults: undefined` — use `null` instead. */
export const STORAGE_ERR_UNDEFINED_DEFAULT: ErrCode = errCode(STORAGE_ERR, 'undefined_default');
/** Standard Schema validation failed for the value being read/written. */
export const STORAGE_ERR_VALIDATION_FAILED: ErrCode = errCode(STORAGE_ERR, 'validation_failed');
/** Standard Schema returned a Promise — async validators are not supported
* by the synchronous storage adapter contract. */
export const STORAGE_ERR_ASYNC_VALIDATE_UNSUPPORTED: ErrCode = errCode(
STORAGE_ERR,
'async_validate_unsupported'
);
/** `entry()` called twice with different defaults — first registration wins. */
export const STORAGE_ERR_ENTRY_DEFAULTS_MISMATCH: ErrCode = errCode(
STORAGE_ERR,
'entry_defaults_mismatch'
);
/** `cookieAdapter()` invoked from server context — use `cookieAdapter.fromCookies()`. */
export const STORAGE_ERR_COOKIE_SERVER_REQUIRED: ErrCode = errCode(
STORAGE_ERR,
'cookie_server_required'
);
/** Stored envelope had a non-numeric `v` (version) field. Surfaces as the
* `error` on `EnvelopeRead { kind: 'invalid' }` rather than thrown. */
export const STORAGE_ERR_ENVELOPE_INVALID_VERSION: ErrCode = errCode(
STORAGE_ERR,
'envelope_invalid_version'
);
/**
* `entry()`, `clear()`, `entries()` or any other public surface was
* invoked after `dispose()`. The engine's bus and adapter
* subscriptions are already torn down at that point — re-creating
* entries would silently leak.
*/
export const STORAGE_ERR_DISPOSED: ErrCode = errCode(STORAGE_ERR, 'disposed');
/**
* Human-readable messages for every error declared by `arts/stor`.
* Indexed by `ErrCode` so the link to identity is direct. Each entry
* is either a static string or a function that builds the message
* from contextual fields.
*/
export const STORAGE_ERROR_MESSAGES: ErrorMessages = {
[STORAGE_ERR_INVALID_TYPE]: (kind: string, value: string): string =>
`[${STORAGE_MODULE}] ${kind} could not parse "${value}".`,
[STORAGE_ERR_UNDEFINED_DEFAULT]:
`[${STORAGE_MODULE}] defaults must not be undefined. Use null when you need an empty value.`,
[STORAGE_ERR_VALIDATION_FAILED]: (issues: unknown): string =>
`[${STORAGE_MODULE}] Standard Schema validation failed: ${JSON.stringify(issues)}`,
[STORAGE_ERR_ASYNC_VALIDATE_UNSUPPORTED]:
`[${STORAGE_MODULE}] Async Standard Schema validation is not supported in v1 (SyncStorageAdapter only). Use a sync schema or a sync validate() function.`,
[STORAGE_ERR_ENTRY_DEFAULTS_MISMATCH]: (key: string): string =>
`[${STORAGE_MODULE}] entry("${key}", ...) was called more than once with different defaults. The first registration wins; the second default is ignored.`,
[STORAGE_ERR_COOKIE_SERVER_REQUIRED]:
`[${STORAGE_MODULE}] cookieAdapter() runs in the browser only. For SSR use cookieAdapter.fromCookies(event.cookies, options).`,
[STORAGE_ERR_ENVELOPE_INVALID_VERSION]: `[${STORAGE_MODULE}] envelope.v not a number`,
[STORAGE_ERR_DISPOSED]: (op: string): string =>
`[${STORAGE_MODULE}] ${op}() called on disposed storage`
};
/**
* Generic type-violation kind for stor. Thrown when a serializer or
* validator receives a value that does not match the expected type
* (e.g. `numberSerializer.deserialize("abc")`). The original `TypeError`
* with the specific detail is preserved on `cause`.
*/
export class StorageInvalidTypeError extends CodeError {
readonly kind: string;
readonly value: string;
constructor(kind: string, value: string, cause: unknown) {
const message = STORAGE_ERROR_MESSAGES[STORAGE_ERR_INVALID_TYPE] as (
kind: string,
value: string
) => string;
super(STORAGE_ERR_INVALID_TYPE, { message: message(kind, value), cause });
this.kind = kind;
this.value = value;
}
}
export class StorageUndefinedDefaultError extends CodeError {
constructor() {
super(STORAGE_ERR_UNDEFINED_DEFAULT, {
message: STORAGE_ERROR_MESSAGES[STORAGE_ERR_UNDEFINED_DEFAULT] as string
});
}
}
export class StorageValidationFailedError extends CodeError {
readonly issues: unknown;
constructor(issues: unknown) {
const message = STORAGE_ERROR_MESSAGES[STORAGE_ERR_VALIDATION_FAILED] as (
issues: unknown
) => string;
super(STORAGE_ERR_VALIDATION_FAILED, { message: message(issues) });
this.issues = issues;
}
}
export class StorageAsyncValidateUnsupportedError extends CodeError {
constructor() {
super(STORAGE_ERR_ASYNC_VALIDATE_UNSUPPORTED, {
message: STORAGE_ERROR_MESSAGES[STORAGE_ERR_ASYNC_VALIDATE_UNSUPPORTED] as string
});
}
}
export class StorageEntryDefaultsMismatchError extends CodeError {
readonly key: string;
constructor(key: string) {
const message = STORAGE_ERROR_MESSAGES[STORAGE_ERR_ENTRY_DEFAULTS_MISMATCH] as (
key: string
) => string;
super(STORAGE_ERR_ENTRY_DEFAULTS_MISMATCH, { message: message(key) });
this.key = key;
}
}
export class StorageCookieServerRequiredError extends CodeError {
constructor() {
super(STORAGE_ERR_COOKIE_SERVER_REQUIRED, {
message: STORAGE_ERROR_MESSAGES[STORAGE_ERR_COOKIE_SERVER_REQUIRED] as string
});
}
}
export class StorageEnvelopeInvalidVersionError extends CodeError {
constructor(cause: unknown) {
super(STORAGE_ERR_ENVELOPE_INVALID_VERSION, {
message: STORAGE_ERROR_MESSAGES[STORAGE_ERR_ENVELOPE_INVALID_VERSION] as string,
cause
});
}
}
export class StorageDisposedError extends CodeError {
readonly op: string;
constructor(op: string) {
const message = STORAGE_ERROR_MESSAGES[STORAGE_ERR_DISPOSED] as (op: string) => string;
super(STORAGE_ERR_DISPOSED, { message: message(op) });
this.op = op;
}
}
// ── Type guards ─────────────────────────────────────────────────────────
export function isStorageInvalidTypeError(value: unknown): value is StorageInvalidTypeError {
return value instanceof StorageInvalidTypeError;
}
export function isStorageUndefinedDefaultError(
value: unknown
): value is StorageUndefinedDefaultError {
return value instanceof StorageUndefinedDefaultError;
}
export function isStorageValidationFailedError(
value: unknown
): value is StorageValidationFailedError {
return value instanceof StorageValidationFailedError;
}
export function isStorageAsyncValidateUnsupportedError(
value: unknown
): value is StorageAsyncValidateUnsupportedError {
return value instanceof StorageAsyncValidateUnsupportedError;
}
export function isStorageEntryDefaultsMismatchError(
value: unknown
): value is StorageEntryDefaultsMismatchError {
return value instanceof StorageEntryDefaultsMismatchError;
}
export function isStorageCookieServerRequiredError(
value: unknown
): value is StorageCookieServerRequiredError {
return value instanceof StorageCookieServerRequiredError;
}
export function isStorageEnvelopeInvalidVersionError(
value: unknown
): value is StorageEnvelopeInvalidVersionError {
return value instanceof StorageEnvelopeInvalidVersionError;
}
export function isStorageDisposedError(value: unknown): value is StorageDisposedError {
return value instanceof StorageDisposedError;
}

Powered by TurnKey Linux.