Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,6 @@ errors.match(e, {
})
```

## Note for Developers

This starter recommends using [npm Trusted Publisher](https://github.com/e18e/ecosystem-issues/issues/201), where the release is done on CI to ensure the security of the packages.

To do so, you need to run `pnpm publish` manually for the very first time to create the package on npm, and then go to `https://www.npmjs.com/package/<your-package-name>/access` to set the connection to your GitHub repo.

Then for future releases, you can run `pnpm run release` and the GitHub Actions will take care of the release process.

## License

[MIT](./LICENSE) License © [Franco P. Romano L.](https://github.com/fprl)
Expand Down
12 changes: 3 additions & 9 deletions packages/errata/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "errata",
"type": "module",
"version": "0.0.0",
"version": "1.0.0",
"packageManager": "pnpm@10.20.0",
"description": "A typed error registry for TypeScript. Errors are data—define them like it.",
"author": "Franco P. Romano L. ",
Expand All @@ -15,14 +15,8 @@
"keywords": [],
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs"
},
"./client": {
"types": "./dist/client.d.mts",
"import": "./dist/client.mjs"
},
".": "./dist/index.mjs",
"./client": "./dist/client.mjs",
Comment on lines +18 to +19
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The simplified export configuration removes TypeScript type definitions from the exports map. This could break TypeScript imports for consumers using moduleResolution "bundler" or "node16"/"nodenext". The previous configuration explicitly specified types fields for each export, which is the recommended practice for dual CJS/ESM packages. Consider restoring the type definitions in the exports or ensure the top-level "types" field adequately covers all exports.

Suggested change
".": "./dist/index.mjs",
"./client": "./dist/client.mjs",
".": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"./client": {
"types": "./dist/client.d.mts",
"default": "./dist/client.mjs"
},

Copilot uses AI. Check for mistakes.
"./package.json": "./package.json"
},
"main": "./dist/index.mjs",
Expand Down
16 changes: 8 additions & 8 deletions packages/errata/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export type ClientMatchHandlers<TCodes extends CodesRecord, R> = ClientMatchHand
/**
* Client-side surface derived from a server `errors` type.
*/
export interface ErrorClient<TCodes extends CodesRecord> {
export interface ErrataClient<TCodes extends CodesRecord> {
/** Client-side ErrataError constructor for instanceof checks. */
ErrataError: new (
payload: SerializedError<ClientCode<TCodes>, any>
Expand Down Expand Up @@ -133,7 +133,7 @@ type InferCodes<T> = T extends ErrataInstance<infer TCodes>
? TCodes
: CodesRecord

export interface ErrorClientOptions {
export interface ErrataClientOptions {
/** Optional app identifier for debugging. */
app?: string
/** Optional lifecycle plugins (payload adaptation, logging). */
Expand All @@ -152,9 +152,9 @@ export interface ErrorClientOptions {
* Create a client that understands the server codes (type-only).
* @param options - Optional configuration including plugins.
*/
export function createErrorClient<TServer extends ErrataInstance<any>>(
options: ErrorClientOptions = {},
): ErrorClient<InferCodes<TServer>> {
export function createErrataClient<TServer extends ErrataInstance<any>>(
options: ErrataClientOptions = {},
): ErrataClient<InferCodes<TServer>> {
const { app, plugins = [], onUnknown } = options

type TCodes = InferCodes<TServer>
Expand Down Expand Up @@ -302,7 +302,7 @@ export function createErrorClient<TServer extends ErrataInstance<any>>(

const patterns = Array.isArray(pattern) ? pattern : [pattern]
return patterns.some(p => matchesPattern(err.code, p as string))
}) as ErrorClient<TCodes>['is']
}) as ErrataClient<TCodes>['is']

/** Pattern matcher with priority: exact match > longest wildcard > default. */
const match = ((
Expand All @@ -318,7 +318,7 @@ export function createErrorClient<TServer extends ErrataInstance<any>>(
: (handlers as any).default

return handler ? handler(errataErr) : undefined
}) as ErrorClient<TCodes>['match']
}) as ErrataClient<TCodes>['match']

/** Check whether an error carries a given tag. */
const hasTag = <TTag extends string>(
Expand Down Expand Up @@ -347,7 +347,7 @@ export function createErrorClient<TServer extends ErrataInstance<any>>(
catch (err) {
return [null, ensure(err)]
}
}) as ErrorClient<TCodes>['safe']
}) as ErrataClient<TCodes>['safe']

return {
ErrataError: ErrataClientError,
Expand Down
44 changes: 5 additions & 39 deletions packages/errata/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,16 @@
export {
createErrorClient,
type ClientMatchHandlers,
createErrataClient,
type ErrataClient,
ErrataClientError,
type ErrorClient,
type ErrorClientOptions,
type ErrataClientOptions,
} from './client'
export { code, defineClientPlugin, defineCodes, definePlugin, props } from './define'
export {
errata,
type ErrataInstance,
type ErrataOptions,
type MatchHandlers,
} from './errata'
export { errata, type ErrataInstance, type ErrataOptions, type MatchHandlers } from './errata'
export { ErrataError, type SerializedError } from './errata-error'
export type {
ClientConfig,
ClientContext,
CodeConfig,
CodeConfigRecord,
CodesOf,
DetailsOf,
ErrataClientErrorForCodes,
ErrataClientPlugin,
ErrataConfig,
ErrataContext,
ErrataErrorForCodes,
ErrataPlugin,
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical breaking change: The removal of many utility types from the public API (including CodesOf, InternalCode, DetailsOf, and many pattern matching types) will break existing consumers of this library. These types are actively used in the test files (see client.test.ts line 1, errata.test.ts line 1, define-codes.test.ts line 1) and are likely used by external consumers. For a 1.0.0 release, consider whether these types should remain part of the public API or if this is an intentional breaking change that should be documented.

Suggested change
ErrataPlugin,
ErrataPlugin,
CodesOf,
InternalCode,
DetailsOf,

Copilot uses AI. Check for mistakes.
InternalCode,
InternalDetails,
MatchingCodes,
MatchingCodesFromUnion,
MatchingErrataClientError,
MatchingErrataClientErrorForCodes,
MatchingErrataError,
MatchingErrataErrorForCodes,
MergePluginCodes,
MessageResolver,
Pattern,
PatternForCodes,
PatternInputForCodes,
PluginCodes,
ResolveMatchingCodes,
ResolveMatchingCodesFromUnion,
} from './types'
export {
findBestMatchingPattern,
getWildcardPrefix,
isWildcardPattern,
matchesPattern,
} from './utils/pattern-matching'
26 changes: 13 additions & 13 deletions packages/errata/test/client-plugins.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { ErrataClientPlugin } from '../src'
import type { errors } from './fixtures'

import { describe, expect, it, vi } from 'vitest'
import { createErrorClient, defineClientPlugin, ErrataClientError } from '../src'
import { createErrataClient, defineClientPlugin, ErrataClientError } from '../src'

// ─── 5. onDeserialize Adaptation (The "RFC 7807" Case) ────────────────────────

Expand Down Expand Up @@ -41,7 +41,7 @@ describe('client plugin onDeserialize adaptation', () => {
},
}

const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
plugins: [rfc7807Plugin],
})

Expand All @@ -60,7 +60,7 @@ describe('client plugin onDeserialize adaptation', () => {
onDeserialize: () => null,
}

const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
plugins: [noopPlugin],
})

Expand All @@ -78,7 +78,7 @@ describe('client plugin onDeserialize adaptation', () => {
})

it('returns errata.unknown_error for invalid payloads without plugins', () => {
const client = createErrorClient<typeof errors>()
const client = createErrataClient<typeof errors>()

const invalidPayload = { no_code_here: true }
const err = client.deserialize(invalidPayload)
Expand Down Expand Up @@ -109,7 +109,7 @@ describe('client plugin onDeserialize adaptation', () => {
onDeserialize: spyB,
}

const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
plugins: [pluginA, pluginB],
})

Expand All @@ -129,7 +129,7 @@ describe('client plugin onDeserialize adaptation', () => {
},
}

const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
plugins: [crashingPlugin],
})

Expand Down Expand Up @@ -159,7 +159,7 @@ describe('client plugin onCreate', () => {
},
}

const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
plugins: [loggingPlugin],
})

Expand Down Expand Up @@ -198,7 +198,7 @@ describe('client plugin onCreate', () => {
onCreate: error => logSpy(error.code),
}

const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
plugins: [adapterPlugin, loggingPlugin],
})

Expand All @@ -221,7 +221,7 @@ describe('client plugin onCreate', () => {
onCreate: () => spyB(),
}

const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
plugins: [pluginA, pluginB],
})

Expand All @@ -247,7 +247,7 @@ describe('client plugin onCreate', () => {
onCreate: () => safeSpy(),
}

const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
plugins: [crashingPlugin, safePlugin],
})

Expand Down Expand Up @@ -275,7 +275,7 @@ describe('client plugin onCreate', () => {
},
}

const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
app: 'my-client-app',
plugins: [configPlugin],
})
Expand All @@ -292,7 +292,7 @@ describe('client plugin validation', () => {
it('warns on duplicate plugin names', () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})

createErrorClient<typeof errors>({
createErrataClient<typeof errors>({
plugins: [
{ name: 'duplicate' },
{ name: 'duplicate' },
Expand Down Expand Up @@ -322,7 +322,7 @@ describe('client plugin validation', () => {
},
})

const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
app: 'test-app',
plugins: [myPlugin],
})
Expand Down
18 changes: 9 additions & 9 deletions packages/errata/test/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { CodesOf, InternalCode } from '../src'
import type { CodesOf, InternalCode } from '../src/types'
import type { ErrorCode } from './fixtures'

import { describe, expect, expectTypeOf, it } from 'vitest'

import { createErrorClient } from '../src'
import { createErrataClient } from '../src'
import { errors } from './fixtures'

describe('client error client', () => {
const client = createErrorClient<typeof errors>()
const client = createErrataClient<typeof errors>()

it('deserializes and matches codes', () => {
const serverErr = errors.create('auth.invalid_token', { reason: 'expired' })
Expand Down Expand Up @@ -46,7 +46,7 @@ describe('client error client', () => {
})

describe('client pattern matching: is()', () => {
const client = createErrorClient<typeof errors>()
const client = createErrataClient<typeof errors>()

describe('wildcard pattern matching', () => {
it('matches codes starting with prefix using auth.*', () => {
Expand Down Expand Up @@ -116,7 +116,7 @@ describe('client pattern matching: is()', () => {
})

describe('client pattern matching: match()', () => {
const client = createErrorClient<typeof errors>()
const client = createErrataClient<typeof errors>()

describe('wildcard handlers', () => {
it('calls wildcard handler when no exact match', () => {
Expand Down Expand Up @@ -223,7 +223,7 @@ describe('client pattern matching: match()', () => {
})

describe('client hasTag()', () => {
const client = createErrorClient<typeof errors>()
const client = createErrataClient<typeof errors>()

it('returns true when error has tag', () => {
const err = client.deserialize(
Expand Down Expand Up @@ -277,7 +277,7 @@ describe('client hasTag()', () => {
})

describe('client deserialize (robust)', () => {
const client = createErrorClient<typeof errors>()
const client = createErrataClient<typeof errors>()

it('deserializes a valid payload', () => {
const payload = errors.serialize(errors.create('auth.invalid_token', { reason: 'expired' }))
Expand Down Expand Up @@ -316,7 +316,7 @@ describe('client deserialize (robust)', () => {
})

describe('client safe()', () => {
const client = createErrorClient<typeof errors>()
const client = createErrataClient<typeof errors>()

it('normalizes network TypeError via ensure (no magic mapping)', async () => {
const [data, err] = await client.safe(Promise.reject(new TypeError('dns')))
Expand Down Expand Up @@ -358,7 +358,7 @@ describe('client safe()', () => {
})

describe('client onUnknown hook', () => {
const client = createErrorClient<typeof errors>({
const client = createErrataClient<typeof errors>({
onUnknown: err => err instanceof TypeError ? 'analytics.event_dropped' : null,
})

Expand Down
2 changes: 1 addition & 1 deletion packages/errata/test/define-codes.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { DetailsOf } from '../src'
import type { DetailsOf } from '../src/types'

import { describe, expect, expectTypeOf, it } from 'vitest'

Expand Down
2 changes: 1 addition & 1 deletion packages/errata/test/errata.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { InternalCode } from '../src'
import type { InternalCode } from '../src/types'
import type { ErrorCode } from './fixtures'

import { describe, expect, expectTypeOf, it } from 'vitest'
Expand Down