qualityapi 1.0.0-alpha.1 → 1.0.0-alpha.2

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.
@@ -1,9 +1,9 @@
1
1
  import Store from "./_internal/Store";
2
- import { QualityApiResponse as Response } from "./QualityApiResponse";
3
2
  import { QualityApiEndpointBuilder as EndpointBuilder } from "./QualityApiEndpointBuilder";
4
3
  import {} from "./QualityApiBody";
5
4
  import {} from "./QualityApiConfig";
6
5
  import {} from "./QualityApiContentType";
6
+ import { getBodyContentType } from "./_internal/util-functions";
7
7
  var QualityApi;
8
8
  (function (QualityApi) {
9
9
  /** Starts the building process of an endpoint. Use `QualityApiEndpointBuilder`'s built-in methods (ex. `authenticate`, `body`) to build the endpoint. */
@@ -19,58 +19,46 @@ var QualityApi;
19
19
  /** Contains the most commonly used HTTP response codes. Use `_` function to define your own. */
20
20
  let Respond;
21
21
  (function (Respond) {
22
- // 2xx (Success)
23
- /** 200 - OK */
24
- function ok(json) {
25
- return _(200, json);
22
+ function generate(statusCode) {
23
+ return (body, contentType = getBodyContentType(body)) => _(statusCode, body, contentType);
26
24
  }
27
- Respond.ok = ok;
28
- /** 201 - Created */
29
- function created(json) {
30
- return _(201, json);
25
+ function generateNoBody(statusCode) {
26
+ return () => _(statusCode);
31
27
  }
32
- Respond.created = created;
33
- /** 204 - No content */
34
- function noContent() {
35
- return _(204);
36
- }
37
- Respond.noContent = noContent;
38
- // 4xx (Client error)
39
- /** 400 - Bad request */
40
- function badRequest(json) {
41
- return _(400, json);
42
- }
43
- Respond.badRequest = badRequest;
44
- /** 401 - Unauthorized */
45
- function unauthorized(json) {
46
- return _(401, json);
47
- }
48
- Respond.unauthorized = unauthorized;
49
- /** 403 - Forbidden */
50
- function forbidden(json) {
51
- return _(403, json);
52
- }
53
- Respond.forbidden = forbidden;
54
- /** 404 - Not found */
55
- function notFound(json) {
56
- return _(404, json);
57
- }
58
- Respond.notFound = notFound;
59
- /** 409 - Conflict */
60
- function conflict(json) {
61
- return _(409, json);
62
- }
63
- Respond.conflict = conflict;
64
- // 5xx (Server error)
65
- /** 500 - Internal server error */
66
- function internalServerError(json) {
67
- return _(500, json);
68
- }
69
- Respond.internalServerError = internalServerError;
28
+ // 2xx - Success
29
+ /** 200 OK */
30
+ Respond.ok = generate(200);
31
+ /** 201 Created */
32
+ Respond.created = generate(201);
33
+ /** 202 Accepted */
34
+ Respond.accepted = generate(202);
35
+ /** 204 No content */
36
+ Respond.noContent = generateNoBody(204);
37
+ // 4xx - Client error
38
+ /** 400 Bad request */
39
+ Respond.badRequest = generate(400);
40
+ /** 401 Unauthorized */
41
+ Respond.unauthorized = generate(401);
42
+ /** 403 Forbidden */
43
+ Respond.forbidden = generate(403);
44
+ /** 409 Conflict */
45
+ Respond.conflict = generate(400);
46
+ // 5xx - Client error
47
+ /** 500 Internal server error */
48
+ Respond.internalServerError = generate(500);
70
49
  // Other
71
50
  /** Creates a response outside of the predefined HTTP codes. */
72
- function _(status, json) {
73
- return new Response(status, json);
51
+ function _(status, body, contentType = getBodyContentType(body)) {
52
+ const isBlob = body instanceof Blob;
53
+ const isString = typeof body === "string";
54
+ const isJson = !isBlob &&
55
+ !isString;
56
+ return new Response(isJson ? JSON.stringify(body) : body, {
57
+ status,
58
+ headers: {
59
+ ...(contentType && { "Content-Type": contentType })
60
+ }
61
+ });
74
62
  }
75
63
  Respond._ = _;
76
64
  })(Respond = QualityApi.Respond || (QualityApi.Respond = {}));
@@ -1,9 +1,9 @@
1
- export var QualityApiContentType;
2
- (function (QualityApiContentType) {
3
- QualityApiContentType[QualityApiContentType["JSON"] = 0] = "JSON";
4
- QualityApiContentType[QualityApiContentType["Blob"] = 1] = "Blob";
5
- QualityApiContentType[QualityApiContentType["Bytes"] = 2] = "Bytes";
6
- QualityApiContentType[QualityApiContentType["Text"] = 3] = "Text";
7
- QualityApiContentType[QualityApiContentType["ArrayBuffer"] = 4] = "ArrayBuffer";
8
- QualityApiContentType[QualityApiContentType["FormData"] = 5] = "FormData";
9
- })(QualityApiContentType || (QualityApiContentType = {}));
1
+ export var QualityApiRequestContentType;
2
+ (function (QualityApiRequestContentType) {
3
+ QualityApiRequestContentType[QualityApiRequestContentType["JSON"] = 0] = "JSON";
4
+ QualityApiRequestContentType[QualityApiRequestContentType["Blob"] = 1] = "Blob";
5
+ QualityApiRequestContentType[QualityApiRequestContentType["Bytes"] = 2] = "Bytes";
6
+ QualityApiRequestContentType[QualityApiRequestContentType["Text"] = 3] = "Text";
7
+ QualityApiRequestContentType[QualityApiRequestContentType["ArrayBuffer"] = 4] = "ArrayBuffer";
8
+ QualityApiRequestContentType[QualityApiRequestContentType["FormData"] = 5] = "FormData";
9
+ })(QualityApiRequestContentType || (QualityApiRequestContentType = {}));
@@ -1,13 +1,12 @@
1
1
  import QualityApi from "./QualityApi";
2
2
  import Store from "./_internal/./Store";
3
- import { QualityApiResponse } from "./QualityApiResponse";
4
3
  import { Continue } from "./Continue";
5
4
  import {} from "./QualityApiMiddleware";
6
5
  import {} from "./QualityApiBody";
7
6
  import {} from "./QualityApiRequest";
8
7
  import {} from "next-auth";
9
- import { formatZodError, urlSearchParamsToObj } from "./_internal/util-functions";
10
- import { QualityApiContentType as ContentType } from "./QualityApiContentType";
8
+ import { formatZodError, testContentHeader, urlSearchParamsToObj } from "./_internal/util-functions";
9
+ import { QualityApiRequestContentType as ContentType } from "./QualityApiContentType";
11
10
  import z, { ZodObject } from "zod";
12
11
  export class QualityApiEndpointBuilder {
13
12
  constructor(contentType) {
@@ -137,18 +136,21 @@ export class QualityApiEndpointBuilder {
137
136
  this._body = await this.parseRequestBody(nextRequest);
138
137
  }
139
138
  catch {
140
- return QualityApi.Respond._(415).toNextResponse();
139
+ return QualityApi.Respond._(415);
141
140
  }
142
141
  }
143
142
  this._params = await context.params;
144
143
  this._searchParams = urlSearchParamsToObj(new URL(nextRequest.url).searchParams);
145
144
  for (const mw of this.middlewares) {
146
145
  const execution = await mw(this.getRequestData(nextRequest));
147
- if (!(execution instanceof Continue))
148
- return execution.toNextResponse();
146
+ if (execution instanceof Continue)
147
+ continue;
148
+ testContentHeader(execution.headers);
149
+ return execution;
149
150
  }
150
- const execFn = await fn(this.getRequestData(nextRequest));
151
- return execFn.toNextResponse();
151
+ const fnExec = await fn(this.getRequestData(nextRequest));
152
+ testContentHeader(fnExec.headers);
153
+ return fnExec;
152
154
  };
153
155
  }
154
156
  }
@@ -1,3 +1,2 @@
1
- import { QualityApiResponse } from "./QualityApiResponse";
2
1
  import { Continue } from "./Continue";
3
2
  import {} from "./QualityApiRequest";
@@ -0,0 +1,15 @@
1
+ export var Logger;
2
+ (function (Logger) {
3
+ function success(msg) {
4
+ console.log(`✅ Quality API: ${msg}`);
5
+ }
6
+ Logger.success = success;
7
+ function error(msg) {
8
+ console.error(`❌ Quality API: ${msg}`);
9
+ }
10
+ Logger.error = error;
11
+ function warn(msg) {
12
+ console.warn(`⚠️ Quality API: ${msg}`);
13
+ }
14
+ Logger.warn = warn;
15
+ })(Logger || (Logger = {}));
@@ -1,21 +1,21 @@
1
- const KEY = "__QUALITYAPI__";
1
+ import { GLOBAL_THIS_NAMESPACE } from "./globals";
2
2
  var Store;
3
3
  (function (Store) {
4
4
  function init() {
5
- if (!(KEY in globalThis))
5
+ if (!(GLOBAL_THIS_NAMESPACE in globalThis))
6
6
  // @ts-ignore
7
- globalThis[KEY] = new Map();
7
+ globalThis[GLOBAL_THIS_NAMESPACE] = new Map();
8
8
  }
9
9
  function get(key) {
10
10
  init();
11
11
  // @ts-ignore
12
- return globalThis[KEY].get(key);
12
+ return globalThis[GLOBAL_THIS_NAMESPACE].get(key);
13
13
  }
14
14
  Store.get = get;
15
15
  function set(key, value) {
16
16
  init();
17
17
  // @ts-ignore
18
- return globalThis[KEY].set(key, value);
18
+ return globalThis[GLOBAL_THIS_NAMESPACE].set(key, value);
19
19
  }
20
20
  Store.set = set;
21
21
  })(Store || (Store = {}));
@@ -0,0 +1,2 @@
1
+ export const BLOB_CONTENT_TYPE = "application/octet-stream";
2
+ export const GLOBAL_THIS_NAMESPACE = "__QUALITYAPI__";
@@ -1,3 +1,5 @@
1
+ import { BLOB_CONTENT_TYPE } from "./globals";
2
+ import { Logger } from "./Logger";
1
3
  export function urlSearchParamsToObj(urlSearchParams) {
2
4
  let result = {};
3
5
  for (const key of urlSearchParams.keys()) {
@@ -26,3 +28,19 @@ export function formatZodError(step, error) {
26
28
  return error;
27
29
  }
28
30
  }
31
+ export function getBodyContentType(body) {
32
+ if (body instanceof Blob)
33
+ return BLOB_CONTENT_TYPE;
34
+ else if (typeof body === "string")
35
+ return "text/plain";
36
+ else
37
+ return "application/json";
38
+ }
39
+ export function testContentHeader(headers) {
40
+ const header = headers.get("Content-Type");
41
+ if (!header)
42
+ return;
43
+ if (header?.split(";")[0] !== BLOB_CONTENT_TYPE)
44
+ return;
45
+ Logger.warn("Specify a \"Content-Type\" header for responses of type blob");
46
+ }
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import QualityApi from "./QualityApi";
2
- export { QualityApiContentType } from "./QualityApiContentType";
2
+ export { QualityApiRequestContentType } from "./QualityApiContentType";
3
3
  export default QualityApi;
@@ -1,8 +1,7 @@
1
- import { QualityApiResponse as Response } from "./QualityApiResponse";
2
1
  import { QualityApiEndpointBuilder as EndpointBuilder } from "./QualityApiEndpointBuilder";
3
- import { type QualityApiBody as Body } from "./QualityApiBody";
2
+ import { type QualityApiBody } from "./QualityApiBody";
4
3
  import { type QualityApiConfig as Config } from "./QualityApiConfig";
5
- import { type QualityApiContentType as ContentType } from "./QualityApiContentType";
4
+ import { type QualityApiRequestContentType as ContentType } from "./QualityApiContentType";
6
5
  type ContentTypeMap = {
7
6
  [ContentType.JSON]: Awaited<ReturnType<Request["json"]>>;
8
7
  [ContentType.Blob]: Awaited<ReturnType<Request["blob"]>>;
@@ -18,26 +17,26 @@ declare namespace QualityApi {
18
17
  function config(options: Config): void;
19
18
  /** Contains the most commonly used HTTP response codes. Use `_` function to define your own. */
20
19
  namespace Respond {
21
- /** 200 - OK */
22
- function ok<Json extends Body = any>(json?: Json): Response<Json>;
23
- /** 201 - Created */
24
- function created<Json extends Body = any>(json?: Json): Response<Json>;
25
- /** 204 - No content */
26
- function noContent(): Response<Body>;
27
- /** 400 - Bad request */
28
- function badRequest<Json extends Body = any>(json?: Json): Response<Json>;
29
- /** 401 - Unauthorized */
30
- function unauthorized<Json extends Body = any>(json?: Json): Response<Json>;
31
- /** 403 - Forbidden */
32
- function forbidden<Json extends Body = any>(json?: Json): Response<Json>;
33
- /** 404 - Not found */
34
- function notFound<Json extends Body = any>(json?: Json): Response<Json>;
35
- /** 409 - Conflict */
36
- function conflict<Json extends Body = any>(json?: Json): Response<Json>;
37
- /** 500 - Internal server error */
38
- function internalServerError<Json extends Body = any>(json: Json): Response<Json>;
20
+ /** 200 OK */
21
+ const ok: <Body extends QualityApiBody>(body?: Body, contentType?: string | undefined) => Response;
22
+ /** 201 Created */
23
+ const created: <Body extends QualityApiBody>(body?: Body, contentType?: string | undefined) => Response;
24
+ /** 202 Accepted */
25
+ const accepted: <Body extends QualityApiBody>(body?: Body, contentType?: string | undefined) => Response;
26
+ /** 204 No content */
27
+ const noContent: () => Response;
28
+ /** 400 Bad request */
29
+ const badRequest: <Body extends QualityApiBody>(body?: Body, contentType?: string | undefined) => Response;
30
+ /** 401 Unauthorized */
31
+ const unauthorized: <Body extends QualityApiBody>(body?: Body, contentType?: string | undefined) => Response;
32
+ /** 403 Forbidden */
33
+ const forbidden: <Body extends QualityApiBody>(body?: Body, contentType?: string | undefined) => Response;
34
+ /** 409 Conflict */
35
+ const conflict: <Body extends QualityApiBody>(body?: Body, contentType?: string | undefined) => Response;
36
+ /** 500 Internal server error */
37
+ const internalServerError: <Body extends QualityApiBody>(body?: Body, contentType?: string | undefined) => Response;
39
38
  /** Creates a response outside of the predefined HTTP codes. */
40
- function _<Json extends Body>(status: number, json?: Json): Response<Json>;
39
+ function _<Body extends QualityApiBody>(status: number, body?: Body, contentType?: string | undefined): Response;
41
40
  }
42
41
  }
43
42
  export default QualityApi;
@@ -1,2 +1,2 @@
1
1
  export type QualityApiBody = {} | [
2
- ];
2
+ ] | Blob | string | number;
@@ -1,4 +1,4 @@
1
- export declare enum QualityApiContentType {
1
+ export declare enum QualityApiRequestContentType {
2
2
  JSON = 0,
3
3
  Blob = 1,
4
4
  Bytes = 2,
@@ -1,9 +1,8 @@
1
- import { QualityApiResponse } from "./QualityApiResponse";
2
1
  import { type QualityApiMiddleware as Middleware } from "./QualityApiMiddleware";
3
2
  import { type QualityApiBody } from "./QualityApiBody";
4
3
  import { type QualityApiRequest } from "./QualityApiRequest";
5
- import { QualityApiContentType as ContentType } from "./QualityApiContentType";
6
- import z, { ZodObject, type ZodRawShape } from "zod";
4
+ import { QualityApiRequestContentType as ContentType } from "./QualityApiContentType";
5
+ import z, { ZodObject, type ZodRawShape, type ZodType } from "zod";
7
6
  export declare class QualityApiEndpointBuilder<Authenticated extends boolean, Body, Params, SearchParams> {
8
7
  private middlewares;
9
8
  private session;
@@ -19,7 +18,7 @@ export declare class QualityApiEndpointBuilder<Authenticated extends boolean, Bo
19
18
  /** Adds internal middleware that verifies end user's authentication. */
20
19
  authenticate(): QualityApiEndpointBuilder<true, Body, Params, SearchParams>;
21
20
  /** Adds internal middleware that validates the request body. */
22
- body<T extends ZodRawShape>(schema: ZodObject<T>): QualityApiEndpointBuilder<Authenticated, z.infer<ZodObject<T>>, Params, SearchParams>;
21
+ body<T extends ZodType>(schema: T): QualityApiEndpointBuilder<Authenticated, z.infer<T>, Params, SearchParams>;
23
22
  /**
24
23
  * Adds internal middleware that validates the request's parameters (slugs).
25
24
  *
@@ -36,7 +35,7 @@ export declare class QualityApiEndpointBuilder<Authenticated extends boolean, Bo
36
35
  * Defines the final function of the endpoint.
37
36
  * This returns a Next.js-endpoint-compatible function with all middleware compiled.
38
37
  */
39
- endpoint<T extends QualityApiBody>(fn: (data: QualityApiRequest<Authenticated, Body, Params, SearchParams>) => QualityApiResponse<T> | Promise<QualityApiResponse<T>>): (nextRequest: Request, context: {
38
+ endpoint<T extends QualityApiBody>(fn: (data: QualityApiRequest<Authenticated, Body, Params, SearchParams>) => (Response | Promise<Response>)): (nextRequest: Request, context: {
40
39
  params: Promise<{}>;
41
40
  }) => Promise<Response>;
42
41
  }
@@ -1,4 +1,3 @@
1
- import { QualityApiResponse } from "./QualityApiResponse";
2
1
  import { Continue } from "./Continue";
3
2
  import { type QualityApiRequest } from "./QualityApiRequest";
4
- export type QualityApiMiddleware<Authenticated extends boolean> = (data: QualityApiRequest<Authenticated>) => QualityApiResponse<any> | Promise<QualityApiResponse<any>> | Continue;
3
+ export type QualityApiMiddleware<Authenticated extends boolean> = (data: QualityApiRequest<Authenticated>) => Response | Promise<Response> | Continue;
@@ -6,11 +6,11 @@ export type QualityApiRequest<Authenticated extends boolean, Body = unknown, Par
6
6
  * This can be mutated through module augmentation. See [NextAuth module augmentation](https://next-auth.js.org/getting-started/typescript#module-augmentation).
7
7
  */
8
8
  session: Authenticated extends true ? Session : (Session | null);
9
- /** The request body. */
9
+ /** The request body. Use the `.body` middleware to validate this through your Zod schema. */
10
10
  body: Body;
11
- /** The request parameters (slugs). */
11
+ /** The request parameters (slugs). Use the `.params` middleware to validate this through your Zod schema. */
12
12
  params: Params;
13
- /** The request search parameters (query parameters). */
13
+ /** The request search parameters (query parameters). Use the `.searchParams` middleware to validate this through your Zod schema. */
14
14
  searchParams: SearchParams;
15
15
  /** The raw Next.js request. */
16
16
  _request: Request;
@@ -0,0 +1,5 @@
1
+ export declare namespace Logger {
2
+ function success(msg: string): void;
3
+ function error(msg: string): void;
4
+ function warn(msg: string): void;
5
+ }
@@ -0,0 +1,2 @@
1
+ export declare const BLOB_CONTENT_TYPE = "application/octet-stream";
2
+ export declare const GLOBAL_THIS_NAMESPACE = "__QUALITYAPI__";
@@ -1,3 +1,4 @@
1
+ import type { QualityApiBody } from "../QualityApiBody";
1
2
  export declare function urlSearchParamsToObj(urlSearchParams: URLSearchParams): {
2
3
  [_: string]: any;
3
4
  };
@@ -11,3 +12,5 @@ export declare function formatZodError(step: string, error: {
11
12
  step: string;
12
13
  properties: {};
13
14
  };
15
+ export declare function getBodyContentType(body?: QualityApiBody): "application/octet-stream" | "text/plain" | "application/json";
16
+ export declare function testContentHeader(headers: Headers): void;
@@ -5,6 +5,5 @@ export type { QualityApiConfig } from "./QualityApiConfig.ts";
5
5
  export type { QualityApiEndpointBuilder } from "./QualityApiEndpointBuilder.ts";
6
6
  export type { QualityApiMiddleware } from "./QualityApiMiddleware.ts";
7
7
  export type { QualityApiRequest } from "./QualityApiRequest.ts";
8
- export type { QualityApiResponse } from "./QualityApiResponse.ts";
9
- export { QualityApiContentType } from "./QualityApiContentType";
8
+ export { QualityApiRequestContentType } from "./QualityApiContentType";
10
9
  export default QualityApi;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qualityapi",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0-alpha.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -1,12 +0,0 @@
1
- import {} from "./QualityApiBody";
2
- export class QualityApiResponse {
3
- constructor(_status, _body) {
4
- this.status = _status;
5
- this.body = _body;
6
- }
7
- toNextResponse() {
8
- return (this.status === 204
9
- ? new Response(undefined, { status: this.status })
10
- : Response.json(this.body ?? {}, { status: this.status }));
11
- }
12
- }
@@ -1,7 +0,0 @@
1
- import { type QualityApiBody } from "./QualityApiBody";
2
- export declare class QualityApiResponse<Body extends QualityApiBody> {
3
- readonly status: number;
4
- readonly body: Body | undefined;
5
- constructor(_status: number, _body?: Body);
6
- toNextResponse(): Response;
7
- }