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
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;
|
|
}
|