Skip to content

Commit 825da92

Browse files
committed
improve assertions debugging
1 parent 2810fff commit 825da92

File tree

15 files changed

+133
-97
lines changed

15 files changed

+133
-97
lines changed

.changeset/soft-zebras-peel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@squarecloud/api": patch
3+
---
4+
5+
improve new assertions debugging

package-lock.json

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/assertions/application.ts

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ApplicationLanguage } from "@squarecloud/api-types/v2";
22
import * as z from "zod";
3-
import { SquareCloudAPIError } from "..";
3+
import { handleAPIObjectAssertion } from "./common";
44

55
const applicationSchema = z
66
.object({
@@ -25,27 +25,21 @@ const websiteApplicationSchema = applicationSchema
2525
export function assertApplication(
2626
value: unknown,
2727
): asserts value is z.infer<typeof applicationSchema> {
28-
try {
29-
applicationSchema.parse(value);
30-
} catch (err) {
31-
throw new SquareCloudAPIError(
32-
"INVALID_API_APPLICATION",
33-
"Invalid application object received from API /apps/{app_id}",
34-
{ cause: err.errors },
35-
);
36-
}
28+
handleAPIObjectAssertion({
29+
schema: applicationSchema,
30+
value,
31+
code: "APPLICATION",
32+
route: "/apps/{app_id}",
33+
});
3734
}
3835

3936
export function assertWebsiteApplication(
4037
value: unknown,
4138
): asserts value is z.infer<typeof websiteApplicationSchema> {
42-
try {
43-
websiteApplicationSchema.parse(value);
44-
} catch (err) {
45-
throw new SquareCloudAPIError(
46-
"INVALID_API_WEBSITE_APPLICATION",
47-
"Invalid website application object received from API /apps/{app_id}",
48-
{ cause: err.errors },
49-
);
50-
}
39+
handleAPIObjectAssertion({
40+
schema: websiteApplicationSchema,
41+
value,
42+
code: "WEBSITE_APPLICATION",
43+
route: "/apps/{app_id}",
44+
});
5145
}

src/assertions/common.ts

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,16 @@
1+
import {
2+
APIObjectAssertionProps,
3+
LiteralAssertionProps,
4+
} from "@/types/assertions";
15
import * as z from "zod";
26
import { SquareCloudAPIError } from "../structures";
37

4-
const stringSchema = z.coerce.string();
5-
const booleanSchema = z.coerce.boolean();
6-
const pathLikeSchema = z.string().or(z.instanceof(Buffer));
7-
8-
export function assertString(
9-
value: unknown,
10-
code?: string,
11-
): asserts value is string {
12-
handleAssertion({ schema: stringSchema, expect: "string", value, code });
13-
}
14-
15-
export function assertBoolean(
16-
value: unknown,
17-
code?: string,
18-
): asserts value is boolean {
19-
handleAssertion({ schema: booleanSchema, expect: "boolean", value, code });
20-
}
21-
22-
export function assertPathLike(
23-
value: unknown,
24-
code?: string,
25-
): asserts value is string | Buffer {
26-
handleAssertion({
27-
schema: pathLikeSchema,
28-
expect: "string or Buffer",
29-
value,
30-
code,
31-
});
32-
}
33-
34-
export function handleAssertion({
8+
export function handleLiteralAssertion({
359
schema,
3610
value,
3711
expect,
3812
code,
39-
}: {
40-
schema: z.Schema;
41-
value: unknown;
42-
expect: string;
43-
code?: string;
44-
}) {
13+
}: LiteralAssertionProps) {
4514
try {
4615
schema.parse(value);
4716
} catch {
@@ -51,3 +20,27 @@ export function handleAssertion({
5120
);
5221
}
5322
}
23+
24+
export function handleAPIObjectAssertion({
25+
schema,
26+
value,
27+
code,
28+
route,
29+
}: APIObjectAssertionProps) {
30+
const name = code.toLowerCase().replaceAll("_", " ");
31+
32+
try {
33+
schema.parse(value);
34+
} catch (err) {
35+
const cause = err.errors?.map((err: z.ZodIssue) => ({
36+
...err,
37+
path: err.path.join(" > "),
38+
}));
39+
40+
throw new SquareCloudAPIError(
41+
`INVALID_API_${code}`,
42+
`Invalid ${name} object received from API ${route}`,
43+
{ cause },
44+
);
45+
}
46+
}

src/assertions/literal.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import * as z from "zod";
2+
import { handleLiteralAssertion } from "./common";
3+
4+
const stringSchema = z.coerce.string();
5+
const booleanSchema = z.coerce.boolean();
6+
const pathLikeSchema = z.string().or(z.instanceof(Buffer));
7+
8+
export function assertString(
9+
value: unknown,
10+
code?: string,
11+
): asserts value is string {
12+
handleLiteralAssertion({
13+
schema: stringSchema,
14+
expect: "string",
15+
value,
16+
code,
17+
});
18+
}
19+
20+
export function assertBoolean(
21+
value: unknown,
22+
code?: string,
23+
): asserts value is boolean {
24+
handleLiteralAssertion({
25+
schema: booleanSchema,
26+
expect: "boolean",
27+
value,
28+
code,
29+
});
30+
}
31+
32+
export function assertPathLike(
33+
value: unknown,
34+
code?: string,
35+
): asserts value is string | Buffer {
36+
handleLiteralAssertion({
37+
schema: pathLikeSchema,
38+
expect: "string or Buffer",
39+
value,
40+
code,
41+
});
42+
}

src/assertions/status.ts

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ApplicationStatus } from "@squarecloud/api-types/v2";
22
import * as z from "zod";
3-
import { SquareCloudAPIError } from "..";
3+
import { handleAPIObjectAssertion } from "./common";
44

55
const simpleStatusSchema = z
66
.object({
@@ -38,27 +38,21 @@ const statusSchema = z
3838
export function assertSimpleStatus(
3939
value: unknown,
4040
): asserts value is z.infer<typeof simpleStatusSchema> {
41-
try {
42-
simpleStatusSchema.parse(value);
43-
} catch (err) {
44-
throw new SquareCloudAPIError(
45-
"INVALID_API_STATUS_ALL",
46-
"Invalid simple status object received from API /apps/all/status",
47-
{ cause: err.errors },
48-
);
49-
}
41+
handleAPIObjectAssertion({
42+
schema: simpleStatusSchema,
43+
value,
44+
code: "STATUS_ALL",
45+
route: "/apps/all/status",
46+
});
5047
}
5148

5249
export function assertStatus(
5350
value: unknown,
5451
): asserts value is z.infer<typeof statusSchema> {
55-
try {
56-
statusSchema.parse(value);
57-
} catch (err) {
58-
throw new SquareCloudAPIError(
59-
"INVALID_API_STATUS",
60-
"Invalid status object received from API /apps/{app_id}/status",
61-
{ cause: err.errors },
62-
);
63-
}
52+
handleAPIObjectAssertion({
53+
schema: statusSchema,
54+
value,
55+
code: "STATUS",
56+
route: "/apps/{app_id}/status",
57+
});
6458
}

src/assertions/user.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { ApplicationLanguage, UserPlanName } from "@squarecloud/api-types/v2";
22
import * as z from "zod";
3-
import { SquareCloudAPIError } from "..";
3+
import { handleAPIObjectAssertion } from "./common";
44

55
const userSchema = z
66
.object({
77
id: z.string(),
88
tag: z.string(),
9-
locale: z.string(),
109
email: z.string(),
1110
plan: z.object({
1211
name: z.nativeEnum(UserPlanName),
@@ -40,13 +39,10 @@ const userInfoSchema = z.object({
4039
export function assertUserInfo(
4140
value: unknown,
4241
): asserts value is z.infer<typeof userInfoSchema> {
43-
try {
44-
userInfoSchema.parse(value);
45-
} catch (err) {
46-
throw new SquareCloudAPIError(
47-
"INVALID_API_USER_INFO",
48-
"Invalid user info object received from API /user",
49-
{ cause: err.errors },
50-
);
51-
}
42+
handleAPIObjectAssertion({
43+
schema: userInfoSchema,
44+
value,
45+
code: "USER_INFO",
46+
route: "/user",
47+
});
5248
}

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { assertString } from "./assertions/common";
1+
import { assertString } from "./assertions/literal";
22
import {
33
APIManager,
44
ApplicationManager,

src/managers/application/deploys.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { assertString } from "@/assertions/common";
1+
import { assertString } from "@/assertions/literal";
22
import { Application } from "@/index";
33

44
export class ApplicationDeploysManager {

src/managers/application/files.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { join } from "path";
2-
import { assertPathLike, assertString } from "@/assertions/common";
2+
import { assertPathLike, assertString } from "@/assertions/literal";
33
import { Application } from "@/index";
44
import { readFile } from "fs/promises";
55

0 commit comments

Comments
 (0)