@nwire/errors 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +71 -0
- package/dist/errors.d.ts +31 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +46 -0
- package/dist/errors.js.map +1 -0
- package/package.json +30 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alex Gefter / 200apps Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# @nwire/errors
|
|
2
|
+
|
|
3
|
+
> Typed domain errors — uniform HTTP / queue / CLI error envelope across every transport.
|
|
4
|
+
|
|
5
|
+
## What it is
|
|
6
|
+
|
|
7
|
+
A small set of typed `Error` subclasses (`NotFoundError`, `ValidationError`, `ConflictError`, `ForbiddenError`, `UnauthorizedError`) every Nwire transport recognizes. Use `instanceof` in handlers and middleware instead of string comparisons; each class maps to the right status code and error envelope.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @nwire/errors
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Standalone use
|
|
16
|
+
|
|
17
|
+
For developers who want typed domain errors in any TypeScript app — throw them anywhere, map them at the transport boundary, no Nwire stack required.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { NotFoundError, ValidationError } from "@nwire/errors";
|
|
21
|
+
|
|
22
|
+
async function getCourse(id: string) {
|
|
23
|
+
const course = await db.courses.findFirst({ where: { id } });
|
|
24
|
+
if (!course) throw new NotFoundError("Course", id);
|
|
25
|
+
return course;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// In a custom Express handler:
|
|
29
|
+
app.get("/courses/:id", async (req, res) => {
|
|
30
|
+
try {
|
|
31
|
+
res.json(await getCourse(req.params.id));
|
|
32
|
+
} catch (e) {
|
|
33
|
+
if (e instanceof NotFoundError)
|
|
34
|
+
return res.status(404).json({ code: e.code, message: e.message });
|
|
35
|
+
throw e;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Within nwire-app
|
|
41
|
+
|
|
42
|
+
For developers using this package as part of the Nwire stack. Throw from any handler / resolver / domain function; `@nwire/http` maps to HTTP status, queue maps to retry/DLQ decisions, CLI maps to exit code.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { NotFoundError } from "@nwire/errors";
|
|
46
|
+
import { defineAction } from "@nwire/forge";
|
|
47
|
+
import { z } from "zod";
|
|
48
|
+
|
|
49
|
+
const getCourse = defineAction("getCourse", {
|
|
50
|
+
input: z.object({ id: z.string() }),
|
|
51
|
+
handler: async ({ input, ctx }) => {
|
|
52
|
+
const course = await ctx.resolve("db").courses.findFirst({ where: { id: input.id } });
|
|
53
|
+
if (!course) throw new NotFoundError("Course", input.id);
|
|
54
|
+
return course;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
// → 404 with { code: "NOT_FOUND", message: "Course not found" } over HTTP
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
- `NotFoundError(entity, id?)` — `code: "NOT_FOUND"` → HTTP 404.
|
|
63
|
+
- `ValidationError(message)` — `code: "VALIDATION_ERROR"` → HTTP 400.
|
|
64
|
+
- `ConflictError(message)` — `code: "CONFLICT"` → HTTP 409.
|
|
65
|
+
- `ForbiddenError(message)` — `code: "FORBIDDEN"` → HTTP 403.
|
|
66
|
+
- `UnauthorizedError(message)` — `code: "UNAUTHORIZED"` → HTTP 401.
|
|
67
|
+
|
|
68
|
+
## See also
|
|
69
|
+
|
|
70
|
+
- [Architecture sketch §05 — Foundation tier](../../architecture-sketch.html#packages)
|
|
71
|
+
- Sibling packages: [@nwire/http](../nwire-http), [@nwire/forge](../nwire-forge)
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nwire/errors` — typed domain errors.
|
|
3
|
+
*
|
|
4
|
+
* NotFoundError / ValidationError / ConflictError / ForbiddenError /
|
|
5
|
+
* UnauthorizedError. Every Nwire transport recognizes these and maps them to
|
|
6
|
+
* the right status code / error envelope. Use `instanceof` checks in
|
|
7
|
+
* middleware instead of string comparisons.
|
|
8
|
+
*
|
|
9
|
+
* See: architecture-sketch.html §05 (Foundation tier).
|
|
10
|
+
*/
|
|
11
|
+
export declare class NotFoundError extends Error {
|
|
12
|
+
readonly code = "NOT_FOUND";
|
|
13
|
+
constructor(entity: string, id?: string);
|
|
14
|
+
}
|
|
15
|
+
export declare class ValidationError extends Error {
|
|
16
|
+
readonly code = "VALIDATION_ERROR";
|
|
17
|
+
constructor(message: string);
|
|
18
|
+
}
|
|
19
|
+
export declare class ConflictError extends Error {
|
|
20
|
+
readonly code = "CONFLICT";
|
|
21
|
+
constructor(message: string);
|
|
22
|
+
}
|
|
23
|
+
export declare class ForbiddenError extends Error {
|
|
24
|
+
readonly code = "FORBIDDEN";
|
|
25
|
+
constructor(message: string);
|
|
26
|
+
}
|
|
27
|
+
export declare class UnauthorizedError extends Error {
|
|
28
|
+
readonly code = "UNAUTHORIZED";
|
|
29
|
+
constructor(message: string);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,eAAe;gBAChB,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM;CAIxC;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,sBAAsB;gBACvB,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,cAAc;gBACf,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,eAAe;gBAChB,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,kBAAkB;gBACnB,OAAO,EAAE,MAAM;CAI5B"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nwire/errors` — typed domain errors.
|
|
3
|
+
*
|
|
4
|
+
* NotFoundError / ValidationError / ConflictError / ForbiddenError /
|
|
5
|
+
* UnauthorizedError. Every Nwire transport recognizes these and maps them to
|
|
6
|
+
* the right status code / error envelope. Use `instanceof` checks in
|
|
7
|
+
* middleware instead of string comparisons.
|
|
8
|
+
*
|
|
9
|
+
* See: architecture-sketch.html §05 (Foundation tier).
|
|
10
|
+
*/
|
|
11
|
+
export class NotFoundError extends Error {
|
|
12
|
+
code = "NOT_FOUND";
|
|
13
|
+
constructor(entity, id) {
|
|
14
|
+
super(id ? `${entity} not found: ${id}` : `${entity} not found`);
|
|
15
|
+
this.name = "NotFoundError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class ValidationError extends Error {
|
|
19
|
+
code = "VALIDATION_ERROR";
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = "ValidationError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class ConflictError extends Error {
|
|
26
|
+
code = "CONFLICT";
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = "ConflictError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export class ForbiddenError extends Error {
|
|
33
|
+
code = "FORBIDDEN";
|
|
34
|
+
constructor(message) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = "ForbiddenError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export class UnauthorizedError extends Error {
|
|
40
|
+
code = "UNAUTHORIZED";
|
|
41
|
+
constructor(message) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.name = "UnauthorizedError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,IAAI,GAAG,WAAW,CAAC;IAC5B,YAAY,MAAc,EAAE,EAAW;QACrC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,eAAe,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,YAAY,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,IAAI,GAAG,kBAAkB,CAAC;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,IAAI,GAAG,UAAU,CAAC;IAC3B,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,KAAK;IAC9B,IAAI,GAAG,WAAW,CAAC;IAC5B,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,GAAG,cAAc,CAAC;IAC/B,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nwire/errors",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Typed domain errors (NotFoundError, ValidationError, ConflictError, ForbiddenError, UnauthorizedError) for uniform error handling. Use `instanceof` checks in route handlers instead of string comparisons.",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"README.md"
|
|
8
|
+
],
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/errors.js",
|
|
11
|
+
"types": "./dist/errors.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/errors.js",
|
|
15
|
+
"types": "./dist/errors.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^22.19.9",
|
|
23
|
+
"typescript": "^5.9.3"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc && node ../../scripts/fix-dist-extensions.mjs dist",
|
|
27
|
+
"dev": "tsc --watch",
|
|
28
|
+
"typecheck": "tsc --noEmit"
|
|
29
|
+
}
|
|
30
|
+
}
|