@arkyn/server 2.0.1-beta.0 → 2.0.1-beta.10

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.
Files changed (106) hide show
  1. package/dist/http/badResponses/badGateway.d.ts +11 -0
  2. package/dist/http/badResponses/badGateway.d.ts.map +1 -0
  3. package/dist/http/badResponses/badGateway.js +29 -0
  4. package/dist/http/badResponses/badRequest.d.ts +11 -0
  5. package/dist/http/badResponses/badRequest.d.ts.map +1 -0
  6. package/dist/http/badResponses/badRequest.js +29 -0
  7. package/dist/http/badResponses/conflict.d.ts +11 -0
  8. package/dist/http/badResponses/conflict.d.ts.map +1 -0
  9. package/dist/http/badResponses/conflict.js +29 -0
  10. package/dist/http/badResponses/forbidden.d.ts +11 -0
  11. package/dist/http/badResponses/forbidden.d.ts.map +1 -0
  12. package/dist/http/badResponses/forbidden.js +29 -0
  13. package/dist/http/badResponses/notFound.d.ts +11 -0
  14. package/dist/http/badResponses/notFound.d.ts.map +1 -0
  15. package/dist/http/badResponses/notFound.js +29 -0
  16. package/dist/http/badResponses/notImplemented.d.ts +11 -0
  17. package/dist/http/badResponses/notImplemented.d.ts.map +1 -0
  18. package/dist/http/badResponses/notImplemented.js +29 -0
  19. package/dist/http/badResponses/serverError.d.ts +11 -0
  20. package/dist/http/badResponses/serverError.d.ts.map +1 -0
  21. package/dist/http/badResponses/serverError.js +29 -0
  22. package/dist/http/badResponses/unauthorized.d.ts +11 -0
  23. package/dist/http/badResponses/unauthorized.d.ts.map +1 -0
  24. package/dist/http/badResponses/unauthorized.js +29 -0
  25. package/dist/http/badResponses/unprocessableEntity.d.ts +16 -0
  26. package/dist/http/badResponses/unprocessableEntity.d.ts.map +1 -0
  27. package/dist/http/badResponses/unprocessableEntity.js +33 -0
  28. package/dist/http/successResponses/created.d.ts +11 -0
  29. package/dist/http/successResponses/created.d.ts.map +1 -0
  30. package/dist/http/successResponses/created.js +29 -0
  31. package/dist/http/successResponses/found.d.ts +11 -0
  32. package/dist/http/successResponses/found.d.ts.map +1 -0
  33. package/dist/http/successResponses/found.js +29 -0
  34. package/dist/http/successResponses/noContent.d.ts +10 -0
  35. package/dist/http/successResponses/noContent.d.ts.map +1 -0
  36. package/dist/http/successResponses/noContent.js +27 -0
  37. package/dist/http/successResponses/success.d.ts +11 -0
  38. package/dist/http/successResponses/success.d.ts.map +1 -0
  39. package/dist/http/successResponses/success.js +29 -0
  40. package/dist/http/successResponses/updated.d.ts +11 -0
  41. package/dist/http/successResponses/updated.d.ts.map +1 -0
  42. package/dist/http/successResponses/updated.js +29 -0
  43. package/dist/index.d.ts +23 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +22 -0
  46. package/dist/services/decodeRequestBody.d.ts +17 -0
  47. package/dist/services/decodeRequestBody.d.ts.map +1 -0
  48. package/dist/services/decodeRequestBody.js +42 -0
  49. package/dist/services/errorHandler.d.ts +3 -0
  50. package/dist/services/errorHandler.d.ts.map +1 -0
  51. package/dist/services/errorHandler.js +51 -0
  52. package/dist/services/formParse.d.ts +42 -0
  53. package/dist/services/formParse.d.ts.map +1 -0
  54. package/dist/services/formParse.js +54 -0
  55. package/dist/services/getCaller.d.ts +6 -0
  56. package/dist/services/getCaller.d.ts.map +1 -0
  57. package/dist/services/getCaller.js +29 -0
  58. package/dist/services/getScopedParams.d.ts +28 -0
  59. package/dist/services/getScopedParams.d.ts.map +1 -0
  60. package/dist/services/getScopedParams.js +34 -0
  61. package/dist/services/httpDebug.d.ts +3 -0
  62. package/dist/services/httpDebug.d.ts.map +1 -0
  63. package/dist/services/httpDebug.js +18 -0
  64. package/dist/services/schemaValidator.d.ts +13 -0
  65. package/dist/services/schemaValidator.d.ts.map +1 -0
  66. package/dist/services/schemaValidator.js +51 -0
  67. package/dist/services/sendFileToS3.d.ts +52 -0
  68. package/dist/services/sendFileToS3.d.ts.map +1 -0
  69. package/dist/services/sendFileToS3.js +143 -0
  70. package/package.json +4 -2
  71. package/src/http/badResponses/badGateway.ts +36 -0
  72. package/src/http/badResponses/badRequest.ts +36 -0
  73. package/src/http/badResponses/conflict.ts +36 -0
  74. package/src/http/badResponses/forbidden.ts +36 -0
  75. package/src/http/badResponses/notFound.ts +36 -0
  76. package/src/http/badResponses/notImplemented.ts +36 -0
  77. package/src/http/badResponses/serverError.ts +36 -0
  78. package/src/http/badResponses/unauthorized.ts +36 -0
  79. package/src/http/badResponses/unprocessableEntity.ts +48 -0
  80. package/src/http/successResponses/created.ts +35 -0
  81. package/src/http/successResponses/found.ts +35 -0
  82. package/src/http/successResponses/noContent.ts +33 -0
  83. package/src/http/successResponses/success.ts +35 -0
  84. package/src/http/successResponses/updated.ts +35 -0
  85. package/src/index.ts +19 -18
  86. package/src/services/decodeRequestBody.ts +46 -0
  87. package/src/services/errorHandler.ts +55 -0
  88. package/src/services/formParse.ts +42 -1
  89. package/src/services/getCaller.ts +37 -0
  90. package/src/services/getScopedParams.ts +29 -2
  91. package/src/services/httpDebug.ts +23 -0
  92. package/src/services/schemaValidator.ts +66 -0
  93. package/src/services/sendFileToS3.ts +81 -56
  94. package/src/helpers/globalErrorHandler.ts +0 -64
  95. package/src/httpBadResponses/badRequest.ts +0 -29
  96. package/src/httpBadResponses/conflict.ts +0 -29
  97. package/src/httpBadResponses/forbidden.ts +0 -29
  98. package/src/httpBadResponses/notFound.ts +0 -29
  99. package/src/httpBadResponses/serverError.ts +0 -29
  100. package/src/httpBadResponses/unauthorized.ts +0 -29
  101. package/src/httpBadResponses/unprocessableEntity.ts +0 -43
  102. package/src/httpResponses/created.ts +0 -35
  103. package/src/httpResponses/noContent.ts +0 -33
  104. package/src/httpResponses/success.ts +0 -35
  105. package/src/httpResponses/updated.ts +0 -35
  106. package/src/services/extractJsonFromRequest.ts +0 -30
@@ -0,0 +1,143 @@
1
+ import { generateId } from "@arkyn/shared";
2
+ import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
3
+ import { unstable_composeUploadHandlers as composeUploadHandlers, unstable_createFileUploadHandler as createFileUploadHandler, unstable_parseMultipartFormData as parseMultipartFormData, } from "@remix-run/node";
4
+ import fs from "fs";
5
+ import sharp from "sharp";
6
+ import { BadRequest } from "../http/badResponses/badRequest";
7
+ import { getScopedParams } from "./getScopedParams";
8
+ async function s3Upload(fileStream, contentType, awsConfig) {
9
+ const uploadParams = {
10
+ Bucket: awsConfig.AWS_S3_BUCKET,
11
+ Key: `uploads/${generateId("text", "v4")}`,
12
+ Body: fileStream,
13
+ ContentType: contentType,
14
+ };
15
+ const s3Client = new S3Client({
16
+ region: awsConfig.AWS_REGION,
17
+ credentials: {
18
+ accessKeyId: awsConfig.AWS_ACCESS_KEY_ID,
19
+ secretAccessKey: awsConfig.AWS_SECRET_ACCESS_KEY,
20
+ },
21
+ });
22
+ const command = new PutObjectCommand(uploadParams);
23
+ try {
24
+ await s3Client.send(command);
25
+ }
26
+ catch (error) {
27
+ console.error(error);
28
+ }
29
+ return {
30
+ location: `https://${awsConfig.AWS_S3_BUCKET}.s3.amazonaws.com/${uploadParams.Key}`,
31
+ };
32
+ }
33
+ /**
34
+ * Handles file uploads to an AWS S3 bucket. This function processes a file
35
+ * from a multipart form request, validates and optionally compresses the file,
36
+ * and uploads it to S3. It supports image-specific operations such as resizing
37
+ * validation and quality reduction.
38
+ *
39
+ * @param request - The HTTP request containing the multipart form data.
40
+ * @param awsS3Config - Configuration object for AWS S3, including bucket name,
41
+ * region, and credentials.
42
+ * @param config - Optional configuration object for file handling.
43
+ *
44
+ * @param config.fileName - The name of the form field containing the file. Defaults to `"file"`.
45
+ * @param config.maxPartSize - The maximum size (in bytes) for each part of the file. Defaults to `5_000_000`.
46
+ * @param config.reduceImageQuality - The quality percentage for image compression. Defaults to `100`.
47
+ * @param config.validateImageSize - Whether to validate the image dimensions. Defaults to `false`.
48
+ * @param config.validateImageMessage - The error message template for invalid image dimensions.
49
+ * Defaults to `"Invalid dimensions {{width}}px x {{height}}px"`.
50
+ *
51
+ * @returns A promise that resolves to an object containing the uploaded file's URL
52
+ * or an error message if validation fails.
53
+ *
54
+ * @throws {BadRequest} If no file is uploaded.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const awsS3Config = {
59
+ * AWS_S3_BUCKET: "my-bucket",
60
+ * AWS_REGION: "us-east-1",
61
+ * AWS_ACCESS_KEY_ID: "my-access-key",
62
+ * AWS_SECRET_ACCESS_KEY: "my-secret-key",
63
+ * };
64
+ *
65
+ * const config = {
66
+ * fileName: "upload",
67
+ * maxPartSize: 10_000_000,
68
+ * reduceImageQuality: 80,
69
+ * validateImageSize: true,
70
+ * validateImageMessage: "Invalid dimensions {{width}}px x {{height}}px",
71
+ * };
72
+ *
73
+ * const response = await sendFileToS3(request, awsS3Config, config);
74
+ * if (response.error) {
75
+ * console.error(response.error);
76
+ * } else {
77
+ * console.log("File uploaded to:", response.url);
78
+ * }
79
+ * ```
80
+ */
81
+ const sendFileToS3 = async (request, awsS3Config, config) => {
82
+ const fileName = config?.fileName || "file";
83
+ const maxPartSize = config?.maxPartSize || 5_000_000;
84
+ const reduceImageQuality = config?.reduceImageQuality || 100;
85
+ const validateImageSize = config?.validateImageSize || false;
86
+ const validateImageMessage = config?.validateImageMessage ||
87
+ "Invalid dimensions {{width}}px x {{height}}px";
88
+ const uploadHandler = composeUploadHandlers(createFileUploadHandler({
89
+ maxPartSize,
90
+ file: ({ filename }) => filename,
91
+ }));
92
+ const formData = await parseMultipartFormData(request, uploadHandler);
93
+ const file = formData.get(fileName);
94
+ if (!file)
95
+ throw new BadRequest("No file uploaded");
96
+ const filterParams = getScopedParams(request);
97
+ const width = filterParams.get("w");
98
+ const height = filterParams.get("h");
99
+ const reduceQuality = filterParams.get("reduceQuality");
100
+ const quality = reduceQuality ? +reduceQuality : reduceImageQuality;
101
+ const isImage = file.type.startsWith("image");
102
+ if (isImage && width && height && validateImageSize) {
103
+ const image = sharp(file.getFilePath());
104
+ const metadata = await image.metadata();
105
+ if (metadata.width && metadata.height) {
106
+ const widthDiff = Math.abs(metadata.width - +width);
107
+ const heightDiff = Math.abs(metadata.height - +height);
108
+ if (widthDiff > 10 || heightDiff > 10) {
109
+ return {
110
+ error: validateImageMessage
111
+ .replace("{{width}}", width)
112
+ .replace("{{height}}", height),
113
+ };
114
+ }
115
+ }
116
+ }
117
+ if (isImage) {
118
+ let image = sharp(file.getFilePath());
119
+ if (file.type === "image/jpeg") {
120
+ image = image.jpeg({ quality });
121
+ }
122
+ else if (file.type === "image/png") {
123
+ image = image.png({ quality });
124
+ }
125
+ else if (file.type === "image/webp") {
126
+ image = image.webp({ quality });
127
+ }
128
+ const compressedFilePath = file.getFilePath() + "_compressed";
129
+ await image.toFile(compressedFilePath);
130
+ file.getFilePath = () => compressedFilePath;
131
+ const streamFile = fs.createReadStream(file.getFilePath());
132
+ const apiResponse = await s3Upload(streamFile, file.type, awsS3Config);
133
+ fs.unlink(compressedFilePath, (err) => {
134
+ if (err)
135
+ console.error(`Delete image error: ${err}`);
136
+ });
137
+ return { url: apiResponse.location };
138
+ }
139
+ const streamFile = fs.createReadStream(file.getFilePath());
140
+ const apiResponse = await s3Upload(streamFile, file.type, awsS3Config);
141
+ return { url: apiResponse.location };
142
+ };
143
+ export { sendFileToS3 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkyn/server",
3
- "version": "2.0.1-beta.0",
3
+ "version": "2.0.1-beta.10",
4
4
  "main": "./dist/bundle.js",
5
5
  "module": "./src/index.ts",
6
6
  "type": "module",
@@ -12,9 +12,11 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@arkyn/server": "*",
15
+ "@arkyn/shared": "*",
15
16
  "@aws-sdk/client-s3": "^3.775.0",
16
17
  "@remix-run/node": "^2.16.2",
17
- "sharp": "^0.33.5"
18
+ "sharp": "^0.33.5",
19
+ "zod": "^3.24.2"
18
20
  },
19
21
  "devDependencies": {
20
22
  "bun-types": "latest",
@@ -0,0 +1,36 @@
1
+ import { httpDebug } from "../../services/httpDebug";
2
+
3
+ class BadGateway {
4
+ body: any;
5
+ cause?: any;
6
+ status: number = 502;
7
+ statusText: string;
8
+
9
+ constructor(message: string, cause?: any) {
10
+ this.body = { name: "BadGateway", message: message };
11
+ this.statusText = message;
12
+ this.cause = cause ? JSON.stringify(cause) : undefined;
13
+ httpDebug("BadGateway", this.body, this.cause);
14
+ }
15
+
16
+ toResponse() {
17
+ const responseInit: ResponseInit = {
18
+ headers: { "Content-Type": "application/json" },
19
+ status: this.status,
20
+ statusText: this.statusText,
21
+ };
22
+
23
+ return new Response(JSON.stringify(this.body), responseInit);
24
+ }
25
+
26
+ toJson() {
27
+ const responseInit: ResponseInit = {
28
+ status: this.status,
29
+ statusText: this.statusText,
30
+ };
31
+
32
+ return Response.json(this.body, responseInit);
33
+ }
34
+ }
35
+
36
+ export { BadGateway };
@@ -0,0 +1,36 @@
1
+ import { httpDebug } from "../../services/httpDebug";
2
+
3
+ class BadRequest {
4
+ body: any;
5
+ cause?: any;
6
+ status: number = 400;
7
+ statusText: string;
8
+
9
+ constructor(message: string, cause?: any) {
10
+ this.body = { name: "BadRequest", message: message };
11
+ this.statusText = message;
12
+ this.cause = cause ? JSON.stringify(cause) : undefined;
13
+ httpDebug("BadRequest", this.body, this.cause);
14
+ }
15
+
16
+ toResponse() {
17
+ const responseInit: ResponseInit = {
18
+ headers: { "Content-Type": "application/json" },
19
+ status: this.status,
20
+ statusText: this.statusText,
21
+ };
22
+
23
+ return new Response(JSON.stringify(this.body), responseInit);
24
+ }
25
+
26
+ toJson() {
27
+ const responseInit: ResponseInit = {
28
+ status: this.status,
29
+ statusText: this.statusText,
30
+ };
31
+
32
+ return Response.json(this.body, responseInit);
33
+ }
34
+ }
35
+
36
+ export { BadRequest };
@@ -0,0 +1,36 @@
1
+ import { httpDebug } from "../../services/httpDebug";
2
+
3
+ class Conflict {
4
+ body: any;
5
+ cause?: any;
6
+ status: number = 409;
7
+ statusText: string;
8
+
9
+ constructor(message: string, cause?: any) {
10
+ this.body = { name: "Conflict", message: message };
11
+ this.statusText = message;
12
+ this.cause = cause ? JSON.stringify(cause) : undefined;
13
+ httpDebug("Conflict", this.body, this.cause);
14
+ }
15
+
16
+ toResponse() {
17
+ const responseInit: ResponseInit = {
18
+ headers: { "Content-Type": "application/json" },
19
+ status: this.status,
20
+ statusText: this.statusText,
21
+ };
22
+
23
+ return new Response(JSON.stringify(this.body), responseInit);
24
+ }
25
+
26
+ toJson() {
27
+ const responseInit: ResponseInit = {
28
+ status: this.status,
29
+ statusText: this.statusText,
30
+ };
31
+
32
+ return Response.json(this.body, responseInit);
33
+ }
34
+ }
35
+
36
+ export { Conflict };
@@ -0,0 +1,36 @@
1
+ import { httpDebug } from "../../services/httpDebug";
2
+
3
+ class Forbidden {
4
+ body: any;
5
+ cause?: any;
6
+ status: number = 402;
7
+ statusText: string;
8
+
9
+ constructor(message: string, cause?: any) {
10
+ this.body = { name: "Forbidden", message: message };
11
+ this.statusText = message;
12
+ this.cause = cause ? JSON.stringify(cause) : undefined;
13
+ httpDebug("Forbidden", this.body, this.cause);
14
+ }
15
+
16
+ toResponse() {
17
+ const responseInit: ResponseInit = {
18
+ headers: { "Content-Type": "application/json" },
19
+ status: this.status,
20
+ statusText: this.statusText,
21
+ };
22
+
23
+ return new Response(JSON.stringify(this.body), responseInit);
24
+ }
25
+
26
+ toJson() {
27
+ const responseInit: ResponseInit = {
28
+ status: this.status,
29
+ statusText: this.statusText,
30
+ };
31
+
32
+ return Response.json(this.body, responseInit);
33
+ }
34
+ }
35
+
36
+ export { Forbidden };
@@ -0,0 +1,36 @@
1
+ import { httpDebug } from "../../services/httpDebug";
2
+
3
+ class NotFound {
4
+ body: any;
5
+ cause?: any;
6
+ status: number = 404;
7
+ statusText: string;
8
+
9
+ constructor(message: string, cause?: any) {
10
+ this.body = { name: "NotFound", message: message };
11
+ this.statusText = message;
12
+ this.cause = cause ? JSON.stringify(cause) : undefined;
13
+ httpDebug("NotFound", this.body, this.cause);
14
+ }
15
+
16
+ toResponse() {
17
+ const responseInit: ResponseInit = {
18
+ headers: { "Content-Type": "application/json" },
19
+ status: this.status,
20
+ statusText: this.statusText,
21
+ };
22
+
23
+ return new Response(JSON.stringify(this.body), responseInit);
24
+ }
25
+
26
+ toJson() {
27
+ const responseInit: ResponseInit = {
28
+ status: this.status,
29
+ statusText: this.statusText,
30
+ };
31
+
32
+ return Response.json(this.body, responseInit);
33
+ }
34
+ }
35
+
36
+ export { NotFound };
@@ -0,0 +1,36 @@
1
+ import { httpDebug } from "../../services/httpDebug";
2
+
3
+ class NotImplemented {
4
+ body: any;
5
+ cause?: any;
6
+ status: number = 501;
7
+ statusText: string;
8
+
9
+ constructor(message: string, cause?: any) {
10
+ this.body = { name: "NotImplemented", message: message };
11
+ this.statusText = message;
12
+ this.cause = cause ? JSON.stringify(cause) : undefined;
13
+ httpDebug("NotImplemented", this.body, this.cause);
14
+ }
15
+
16
+ toResponse() {
17
+ const responseInit: ResponseInit = {
18
+ headers: { "Content-Type": "application/json" },
19
+ status: this.status,
20
+ statusText: this.statusText,
21
+ };
22
+
23
+ return new Response(JSON.stringify(this.body), responseInit);
24
+ }
25
+
26
+ toJson() {
27
+ const responseInit: ResponseInit = {
28
+ status: this.status,
29
+ statusText: this.statusText,
30
+ };
31
+
32
+ return Response.json(this.body, responseInit);
33
+ }
34
+ }
35
+
36
+ export { NotImplemented };
@@ -0,0 +1,36 @@
1
+ import { httpDebug } from "../../services/httpDebug";
2
+
3
+ class ServerError {
4
+ body: any;
5
+ cause?: any;
6
+ status: number = 500;
7
+ statusText: string;
8
+
9
+ constructor(message: string, cause?: any) {
10
+ this.body = { name: "ServerError", message: message };
11
+ this.statusText = message;
12
+ this.cause = cause ? JSON.stringify(cause) : undefined;
13
+ httpDebug("ServerError", this.body, this.cause);
14
+ }
15
+
16
+ toResponse() {
17
+ const responseInit: ResponseInit = {
18
+ headers: { "Content-Type": "application/json" },
19
+ status: this.status,
20
+ statusText: this.statusText,
21
+ };
22
+
23
+ return new Response(JSON.stringify(this.body), responseInit);
24
+ }
25
+
26
+ toJson() {
27
+ const responseInit: ResponseInit = {
28
+ status: this.status,
29
+ statusText: this.statusText,
30
+ };
31
+
32
+ return Response.json(this.body, responseInit);
33
+ }
34
+ }
35
+
36
+ export { ServerError };
@@ -0,0 +1,36 @@
1
+ import { httpDebug } from "../../services/httpDebug";
2
+
3
+ class Unauthorized {
4
+ body: any;
5
+ cause?: any;
6
+ status: number = 401;
7
+ statusText: string;
8
+
9
+ constructor(message: string, cause?: any) {
10
+ this.body = { name: "Unauthorized", message: message };
11
+ this.statusText = message;
12
+ this.cause = cause ? JSON.stringify(cause) : undefined;
13
+ httpDebug("Unauthorized", this.body, this.cause);
14
+ }
15
+
16
+ toResponse() {
17
+ const responseInit: ResponseInit = {
18
+ headers: { "Content-Type": "application/json" },
19
+ status: this.status,
20
+ statusText: this.statusText,
21
+ };
22
+
23
+ return new Response(JSON.stringify(this.body), responseInit);
24
+ }
25
+
26
+ toJson() {
27
+ const responseInit: ResponseInit = {
28
+ status: this.status,
29
+ statusText: this.statusText,
30
+ };
31
+
32
+ return Response.json(this.body, responseInit);
33
+ }
34
+ }
35
+
36
+ export { Unauthorized };
@@ -0,0 +1,48 @@
1
+ import { httpDebug } from "../../services/httpDebug";
2
+
3
+ type UnprocessableEntityProps = {
4
+ data?: any;
5
+ fieldErrors?: Record<string, string>;
6
+ fields?: Record<string, string>;
7
+ message?: string;
8
+ };
9
+
10
+ class UnprocessableEntity {
11
+ body: any;
12
+ status: number = 422;
13
+ statusText: string;
14
+
15
+ constructor(props: UnprocessableEntityProps, enableDebug = false) {
16
+ this.statusText = props.message || "Unprocessable Entity";
17
+ this.body = {
18
+ name: "UnprocessableEntity",
19
+ message: props.message || null,
20
+ data: props.data,
21
+ fieldErrors: props.fieldErrors,
22
+ fields: props.fields,
23
+ };
24
+
25
+ enableDebug && httpDebug("UnprocessableEntity", this.body);
26
+ }
27
+
28
+ toResponse() {
29
+ const responseInit: ResponseInit = {
30
+ headers: { "Content-Type": "application/json" },
31
+ status: this.status,
32
+ statusText: this.statusText,
33
+ };
34
+
35
+ return new Response(JSON.stringify(this.body), responseInit);
36
+ }
37
+
38
+ toJson() {
39
+ const responseInit: ResponseInit = {
40
+ status: this.status,
41
+ statusText: this.statusText,
42
+ };
43
+
44
+ return Response.json(this.body, responseInit);
45
+ }
46
+ }
47
+
48
+ export { UnprocessableEntity };
@@ -0,0 +1,35 @@
1
+ class Created<T> {
2
+ body: T;
3
+ headers: ResponseInit["headers"];
4
+ status: number;
5
+ statusText: string;
6
+
7
+ constructor(body: T, init?: ResponseInit) {
8
+ this.body = body;
9
+ this.headers = init?.headers || {};
10
+ this.status = init?.status || 201;
11
+ this.statusText = init?.statusText || "Resource created successfully";
12
+ }
13
+
14
+ toResponse() {
15
+ const responseInit: ResponseInit = {
16
+ headers: { "Content-Type": "application/json", ...this.headers },
17
+ status: this.status,
18
+ statusText: this.statusText,
19
+ };
20
+
21
+ return new Response(JSON.stringify(this.body), responseInit);
22
+ }
23
+
24
+ toJson() {
25
+ const responseInit: ResponseInit = {
26
+ headers: this.headers,
27
+ status: this.status,
28
+ statusText: this.statusText,
29
+ };
30
+
31
+ return Response.json(this.body, responseInit);
32
+ }
33
+ }
34
+
35
+ export { Created };
@@ -0,0 +1,35 @@
1
+ class Found<T> {
2
+ body: T;
3
+ headers: ResponseInit["headers"];
4
+ status: number;
5
+ statusText: string;
6
+
7
+ constructor(body: T, init?: ResponseInit) {
8
+ this.body = body;
9
+ this.headers = init?.headers || {};
10
+ this.status = init?.status || 302;
11
+ this.statusText = init?.statusText || "Found";
12
+ }
13
+
14
+ toResponse() {
15
+ const responseInit: ResponseInit = {
16
+ headers: { "Content-Type": "application/json", ...this.headers },
17
+ status: this.status,
18
+ statusText: this.statusText,
19
+ };
20
+
21
+ return new Response(JSON.stringify(this.body), responseInit);
22
+ }
23
+
24
+ toJson() {
25
+ const responseInit: ResponseInit = {
26
+ headers: this.headers,
27
+ status: this.status,
28
+ statusText: this.statusText,
29
+ };
30
+
31
+ return Response.json(this.body, responseInit);
32
+ }
33
+ }
34
+
35
+ export { Found };
@@ -0,0 +1,33 @@
1
+ class NoContent {
2
+ headers: ResponseInit["headers"];
3
+ status: number;
4
+ statusText: string;
5
+
6
+ constructor(init?: ResponseInit) {
7
+ this.headers = init?.headers || {};
8
+ this.status = init?.status || 204;
9
+ this.statusText = init?.statusText ?? "No content";
10
+ }
11
+
12
+ toResponse() {
13
+ const responseInit: ResponseInit = {
14
+ headers: this.headers,
15
+ status: this.status,
16
+ statusText: this.statusText,
17
+ };
18
+
19
+ return new Response(null, responseInit);
20
+ }
21
+
22
+ toJson() {
23
+ const responseInit: ResponseInit = {
24
+ headers: this.headers,
25
+ status: this.status,
26
+ statusText: this.statusText,
27
+ };
28
+
29
+ return Response.json(null, responseInit);
30
+ }
31
+ }
32
+
33
+ export { NoContent };
@@ -0,0 +1,35 @@
1
+ class Success<T> {
2
+ body: T;
3
+ headers: ResponseInit["headers"];
4
+ status: number;
5
+ statusText: string;
6
+
7
+ constructor(body: T, init?: ResponseInit) {
8
+ this.body = body;
9
+ this.headers = init?.headers || {};
10
+ this.status = init?.status || 200;
11
+ this.statusText = init?.statusText ?? "OK";
12
+ }
13
+
14
+ toResponse() {
15
+ const responseInit: ResponseInit = {
16
+ headers: { "Content-Type": "application/json", ...this.headers },
17
+ status: this.status,
18
+ statusText: this.statusText,
19
+ };
20
+
21
+ return new Response(JSON.stringify(this.body), responseInit);
22
+ }
23
+
24
+ toJson() {
25
+ const responseInit: ResponseInit = {
26
+ headers: this.headers,
27
+ status: this.status,
28
+ statusText: this.statusText,
29
+ };
30
+
31
+ return Response.json(this.body, responseInit);
32
+ }
33
+ }
34
+
35
+ export { Success };
@@ -0,0 +1,35 @@
1
+ class Updated<T> {
2
+ body: T;
3
+ headers: ResponseInit["headers"];
4
+ status: number;
5
+ statusText: string;
6
+
7
+ constructor(body: T, init?: ResponseInit) {
8
+ this.body = body;
9
+ this.headers = init?.headers || {};
10
+ this.status = init?.status || 200;
11
+ this.statusText = init?.statusText || "Resource updated successfully";
12
+ }
13
+
14
+ toResponse() {
15
+ const responseInit: ResponseInit = {
16
+ headers: { "Content-Type": "application/json", ...this.headers },
17
+ status: this.status,
18
+ statusText: this.statusText,
19
+ };
20
+
21
+ return new Response(JSON.stringify(this.body), responseInit);
22
+ }
23
+
24
+ toJson() {
25
+ const responseInit: ResponseInit = {
26
+ headers: this.headers,
27
+ status: this.status,
28
+ statusText: this.statusText,
29
+ };
30
+
31
+ return Response.json(this.body, responseInit);
32
+ }
33
+ }
34
+
35
+ export { Updated };