first commit
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
# error-codes
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Defines the stable error-code registry and typed `MacOSContactsError` class for `@suaveplan/macos-contacts`. Every failure path the package exposes raises a `MacOSContactsError` carrying one of six registered codes (`INVALID_INPUT`, `CONTACTS_NOT_FOUND`, `CONTACTS_PERMISSION_DENIED`, `CONTACTS_ACCESS_FAILED`, `CONTACTS_PARSE_FAILED`, `CONTACTS_UNAVAILABLE`). Codes are namespaced strings (`"MACOS_CONTACTS.CONTACTS_PERMISSION_DENIED"`) so consumers can dispatch programmatically without parsing messages, and the typed error narrows the `query` / `groupName` / `contactId` discriminants for diagnostics.
|
||||
|
||||
## Features
|
||||
|
||||
- `MACOS_CONTACTS_CODES` — `defineCodes("MACOS_CONTACTS", [...])` registry; the canonical source of truth for every code emitted by the package.
|
||||
- `MacOSContactsError extends SuaveplanError<MacOSContactsErrorCode>` — typed error class. `instanceof` narrows `code` to a literal-string union.
|
||||
- `MacOSContactsErrorCode` — union of every registered code.
|
||||
- `MacOSContactsErrorOptions` — options bag extending `SuaveplanErrorOptions` with `query`, `groupName`, `contactId` discriminants and standard `cause` chaining.
|
||||
- Replaces upstream's `HttpError(... code as unknown as HttpErrorCode)` cast: codes flow through the type system end-to-end, with no `unknown` escape hatches.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
MACOS_CONTACTS_CODES,
|
||||
MacOSContactsError,
|
||||
} from "@suaveplan/macos-contacts";
|
||||
|
||||
function ensurePermission(stderr: string) {
|
||||
if (/not authorized/i.test(stderr)) {
|
||||
throw new MacOSContactsError(
|
||||
MACOS_CONTACTS_CODES.CONTACTS_PERMISSION_DENIED,
|
||||
"macOS denied access to Contacts.app",
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
MACOS_CONTACTS_CODES,
|
||||
MacOSContactsError,
|
||||
} from "@suaveplan/macos-contacts";
|
||||
|
||||
try {
|
||||
await bridge.searchContacts(query);
|
||||
} catch (err) {
|
||||
if (err instanceof MacOSContactsError) {
|
||||
switch (err.code) {
|
||||
case MACOS_CONTACTS_CODES.CONTACTS_PERMISSION_DENIED:
|
||||
return openSystemSettingsDialog();
|
||||
case MACOS_CONTACTS_CODES.INVALID_INPUT:
|
||||
return showValidationToast(err.message);
|
||||
default:
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `MACOS_CONTACTS_CODES`
|
||||
|
||||
A frozen registry produced by `defineCodes("MACOS_CONTACTS", [...] as const)`. Each entry maps a bare key (e.g. `CONTACTS_PERMISSION_DENIED`) to its namespaced string (`"MACOS_CONTACTS.CONTACTS_PERMISSION_DENIED"`).
|
||||
|
||||
### `MacOSContactsErrorCode`
|
||||
|
||||
Union type `(typeof MACOS_CONTACTS_CODES)[keyof typeof MACOS_CONTACTS_CODES]`. Use to type-check `error.code` in catch blocks.
|
||||
|
||||
### `MacOSContactsError(code, message, options?)`
|
||||
|
||||
Constructor parameters:
|
||||
|
||||
- `code: MacOSContactsErrorCode` — required, the discriminant.
|
||||
- `message: string` — required, English diagnostic.
|
||||
- `options.query?: string` — attaches `error.query`.
|
||||
- `options.groupName?: string` — attaches `error.groupName`.
|
||||
- `options.contactId?: string` — attaches `error.contactId`.
|
||||
- `options.cause?: unknown` — standard ES `Error.cause`; preserved through serialization and span events.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The discriminants live as direct instance properties so consumers can do `if (err.query)` without an extra unwrap. Codes are validated at registry time by `defineCodes`, which freezes the result and enforces unique namespace tokens.
|
||||
|
||||
Adding a new code requires three concurrent edits: append the literal to the `MACOS_CONTACTS_CODES` array, raise it from at least one production call site, and add a test that round-trips an instance with the new code. The package's own `macos-contacts.spec-conformance.test.ts` enforces the "every code referenced" rule — removing a code to placate a gate is banned per `AGENTS.md` §2c.
|
||||
|
||||
Error-code strings are part of the public API. Renaming one is a breaking change. Add a new code instead and let consumers migrate explicitly.
|
||||
Reference in New Issue
Block a user