@nice-code/common-errors 0.2.9 → 0.2.11

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/README.md CHANGED
@@ -1,5 +1,106 @@
1
1
  # @nice-code/common-errors
2
2
 
3
- Shared error domains for Standard Schema validation errors and Hono middleware integration.
3
+ Shared error domains for Standard Schema validation errors, with Hono middleware integration.
4
4
 
5
- See the [main README](../../README.md#nice-codecommon-errors) for full documentation and examples.
5
+ ## Install
6
+
7
+ ```bash
8
+ bun add @nice-code/common-errors
9
+ ```
10
+
11
+ Peer deps: `valibot` (or any Standard Schema library), `hono` (for `/hono` subpath).
12
+
13
+ ---
14
+
15
+ ## Validation error domain
16
+
17
+ `err_validation` is a [`@nice-code/error`](../nice-error) domain for Standard Schema validation failures. Import it to match or inspect validation errors by domain.
18
+
19
+ ```ts
20
+ import { err_validation, EValidator } from "@nice-code/common-errors";
21
+
22
+ // Check if an error is a validation error
23
+ if (err_validation.isExact(caught)) {
24
+ const hydrated = err_validation.hydrate(caught);
25
+ const { issues } = hydrated.getContext(EValidator.standard_schema);
26
+ // issues: readonly StandardSchemaV1.Issue[]
27
+ }
28
+ ```
29
+
30
+ The domain exposes one error id: `EValidator.standard_schema` with context `{ issues }`.
31
+
32
+ ---
33
+
34
+ ## Hono middleware
35
+
36
+ Import from the `/hono` subpath:
37
+
38
+ ```ts
39
+ import { niceSValidator, niceCatchSValidation } from "@nice-code/common-errors/hono";
40
+ ```
41
+
42
+ ### `niceSValidator(target, schema)`
43
+
44
+ Drop-in replacement for `@hono/standard-validator`'s `sValidator` that throws a `NiceError` instead of returning a 400 response when validation fails.
45
+
46
+ ```ts
47
+ import { niceSValidator } from "@nice-code/common-errors/hono";
48
+ import * as v from "valibot";
49
+
50
+ const CreateUserSchema = v.object({
51
+ name: v.string(),
52
+ email: v.pipe(v.string(), v.email()),
53
+ });
54
+
55
+ app.post("/users", niceSValidator("json", CreateUserSchema), async (c) => {
56
+ const body = c.req.valid("json"); // fully typed
57
+ // ...
58
+ });
59
+ ```
60
+
61
+ When validation fails, a `NiceError` from the `err_validation` domain is thrown. Use Hono's `onError` handler to convert it to a JSON response:
62
+
63
+ ```ts
64
+ import { castNiceError } from "@nice-code/error";
65
+
66
+ app.onError((err, c) => {
67
+ const niceError = castNiceError(err);
68
+ return c.json(niceError.toJsonObject(), niceError.httpStatusCode as any);
69
+ });
70
+ ```
71
+
72
+ ### `niceCatchSValidation()`
73
+
74
+ Middleware that intercepts raw `@hono/standard-validator` validation responses (the default `{ success: false, error: [...] }` shape) and converts them into `NiceError` JSON responses. Use this when you can't replace `sValidator` with `niceSValidator` directly.
75
+
76
+ ```ts
77
+ app.use(niceCatchSValidation());
78
+
79
+ // Existing sValidator usage is automatically intercepted
80
+ app.post("/data", sValidator("json", MySchema), handler);
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Full Hono example
86
+
87
+ ```ts
88
+ import { Hono } from "hono";
89
+ import { niceSValidator } from "@nice-code/common-errors/hono";
90
+ import { castNiceError, EErrorPackType } from "@nice-code/error";
91
+ import * as v from "valibot";
92
+
93
+ const app = new Hono();
94
+
95
+ app.onError((err, c) => {
96
+ const niceError = castNiceError(err);
97
+ return c.json(niceError.toJsonObject(), niceError.httpStatusCode as any);
98
+ });
99
+
100
+ const BodySchema = v.object({ message: v.string() });
101
+
102
+ app.post("/echo", niceSValidator("json", BodySchema), async (c) => {
103
+ const { message } = c.req.valid("json");
104
+ return c.json({ echo: message });
105
+ });
106
+ ```
@@ -1,3 +1,99 @@
1
- // src/hono/index.ts
2
- export * from "./niceCatchSValidation";
3
- export * from "./niceSValidator";
1
+ // src/validation/err_validation.ts
2
+ import { err, err_nice } from "@nice-code/error";
3
+ import { StatusCodes } from "http-status-codes";
4
+
5
+ // src/validation/standard_schema/extractMessageFromStandardSchema.ts
6
+ function extractPathFromIssue(issue) {
7
+ let pathString = "";
8
+ for (const segment of issue) {
9
+ if (typeof segment === "object") {
10
+ if (segment.key != null) {
11
+ if (typeof segment.key === "number") {
12
+ pathString += `[${String(segment.key)}]`;
13
+ } else if (typeof segment.key === "symbol") {
14
+ pathString += `[SYMBOL:${String(segment.key)}]`;
15
+ } else {
16
+ pathString += `.${String(segment.key)}`;
17
+ }
18
+ }
19
+ } else {
20
+ pathString += `.${String(segment)}`;
21
+ }
22
+ }
23
+ return pathString.slice(1);
24
+ }
25
+ var extractMessageFromStandardSchema = (failureResult) => {
26
+ let message = `Data validation failed:
27
+ `;
28
+ let issueCount = 0;
29
+ for (const issue of failureResult.issues) {
30
+ issueCount++;
31
+ if (issue.path == null || issue.path.length === 0) {
32
+ message += ` (issue ${issueCount}) ${issue.message}
33
+ `;
34
+ } else {
35
+ message += ` (issue ${issueCount}) [${extractPathFromIssue(issue.path)}]: ${issue.message}
36
+ `;
37
+ }
38
+ }
39
+ return message;
40
+ };
41
+
42
+ // src/validation/err_validation.ts
43
+ var EValidator;
44
+ ((EValidator2) => {
45
+ EValidator2["standard_schema"] = "standard_schema";
46
+ })(EValidator ||= {});
47
+ var err_validation = err_nice.createChildDomain({
48
+ domain: "err_validation",
49
+ defaultHttpStatusCode: StatusCodes.BAD_REQUEST,
50
+ schema: {
51
+ ["standard_schema" /* standard_schema */]: err({
52
+ message: ({ issues }) => extractMessageFromStandardSchema({ issues })
53
+ })
54
+ }
55
+ });
56
+ // src/hono/niceCatchSValidation.ts
57
+ var niceCatchSValidation = () => async (ctx, next) => {
58
+ await next();
59
+ if (!ctx.res.ok) {
60
+ const clonedResponse = ctx.res.clone();
61
+ const contentType = clonedResponse.headers.get("content-type");
62
+ if (contentType?.includes("application/json")) {
63
+ try {
64
+ const responseJson = await clonedResponse.json();
65
+ if (responseJson["success"] != null && responseJson["error"] != null) {
66
+ console.log("Intercepted JSON:", responseJson);
67
+ const result = responseJson;
68
+ const newError = err_validation.fromId("standard_schema" /* standard_schema */, {
69
+ issues: result.error
70
+ });
71
+ ctx.res = undefined;
72
+ ctx.res = new Response(JSON.stringify(newError.toJsonObject()), {
73
+ status: newError.httpStatusCode,
74
+ headers: {
75
+ "Content-Type": "application/json"
76
+ }
77
+ });
78
+ }
79
+ } catch (error) {
80
+ console.error("Failed to parse response JSON:", error);
81
+ }
82
+ }
83
+ }
84
+ };
85
+ // src/hono/niceSValidator.ts
86
+ import { sValidator } from "@hono/standard-validator";
87
+ function niceSValidator(target, schema) {
88
+ return sValidator(target, schema, (result) => {
89
+ if (!result.success) {
90
+ throw err_validation.fromId("standard_schema" /* standard_schema */, {
91
+ issues: result.error
92
+ });
93
+ }
94
+ });
95
+ }
96
+ export {
97
+ niceSValidator,
98
+ niceCatchSValidation
99
+ };
package/build/index.js CHANGED
@@ -1,2 +1,60 @@
1
- // src/index.ts
2
- export * from "./validation";
1
+ // src/validation/err_validation.ts
2
+ import { err, err_nice } from "@nice-code/error";
3
+ import { StatusCodes } from "http-status-codes";
4
+
5
+ // src/validation/standard_schema/extractMessageFromStandardSchema.ts
6
+ function extractPathFromIssue(issue) {
7
+ let pathString = "";
8
+ for (const segment of issue) {
9
+ if (typeof segment === "object") {
10
+ if (segment.key != null) {
11
+ if (typeof segment.key === "number") {
12
+ pathString += `[${String(segment.key)}]`;
13
+ } else if (typeof segment.key === "symbol") {
14
+ pathString += `[SYMBOL:${String(segment.key)}]`;
15
+ } else {
16
+ pathString += `.${String(segment.key)}`;
17
+ }
18
+ }
19
+ } else {
20
+ pathString += `.${String(segment)}`;
21
+ }
22
+ }
23
+ return pathString.slice(1);
24
+ }
25
+ var extractMessageFromStandardSchema = (failureResult) => {
26
+ let message = `Data validation failed:
27
+ `;
28
+ let issueCount = 0;
29
+ for (const issue of failureResult.issues) {
30
+ issueCount++;
31
+ if (issue.path == null || issue.path.length === 0) {
32
+ message += ` (issue ${issueCount}) ${issue.message}
33
+ `;
34
+ } else {
35
+ message += ` (issue ${issueCount}) [${extractPathFromIssue(issue.path)}]: ${issue.message}
36
+ `;
37
+ }
38
+ }
39
+ return message;
40
+ };
41
+
42
+ // src/validation/err_validation.ts
43
+ var EValidator;
44
+ ((EValidator2) => {
45
+ EValidator2["standard_schema"] = "standard_schema";
46
+ })(EValidator ||= {});
47
+ var err_validation = err_nice.createChildDomain({
48
+ domain: "err_validation",
49
+ defaultHttpStatusCode: StatusCodes.BAD_REQUEST,
50
+ schema: {
51
+ ["standard_schema" /* standard_schema */]: err({
52
+ message: ({ issues }) => extractMessageFromStandardSchema({ issues })
53
+ })
54
+ }
55
+ });
56
+ export {
57
+ extractMessageFromStandardSchema,
58
+ err_validation,
59
+ EValidator
60
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nice-code/common-errors",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -29,7 +29,7 @@
29
29
  "build-types": "tsc --project tsconfig.build.json"
30
30
  },
31
31
  "dependencies": {
32
- "@nice-code/error": "0.2.9",
32
+ "@nice-code/error": "0.2.11",
33
33
  "@standard-schema/spec": "^1.1.0",
34
34
  "@hono/standard-validator": "^0.2.2",
35
35
  "http-status-codes": "^2.3.0"