diff --git a/.gitignore b/.gitignore index c0feab5..0ec7d59 100644 --- a/.gitignore +++ b/.gitignore @@ -133,4 +133,5 @@ dist/ .yarn/install-state.gz .pnp.* -.DS_Store \ No newline at end of file +.DS_Store +/generated/prisma diff --git a/Aragon-Kanban-API.postman_collection.json b/Aragon-Kanban-API.postman_collection.json new file mode 100644 index 0000000..4dbd899 --- /dev/null +++ b/Aragon-Kanban-API.postman_collection.json @@ -0,0 +1,142 @@ +{ + "info": { + "name": "Aragon Kanban API", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": "Postman collection for Users, Boards, and Tasks API" + }, + "item": [ + { + "name": "Users", + "item": [ + { + "name": "Get All Users", + "request": { + "method": "GET", + "header": [{"key": "Authorization", "value": "Bearer testtoken"}], + "url": { "raw": "{{baseUrl}}/users", "host": ["{{baseUrl}}"], "path": ["users"] } + } + }, + { + "name": "Add User", + "request": { + "method": "POST", + "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}], + "body": { "mode": "raw", "raw": "{\n \"user\": {\n \"id\": 1,\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n }\n}" }, + "url": { "raw": "{{baseUrl}}/users", "host": ["{{baseUrl}}"], "path": ["users"] } + } + }, + { + "name": "Update User", + "request": { + "method": "PUT", + "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}], + "body": { "mode": "raw", "raw": "{\n \"user\": {\n \"id\": 1,\n \"name\": \"Jane Doe\",\n \"email\": \"jane@example.com\"\n }\n}" }, + "url": { "raw": "{{baseUrl}}/users", "host": ["{{baseUrl}}"], "path": ["users"] } + } + }, + { + "name": "Delete User", + "request": { + "method": "DELETE", + "header": [{"key": "Authorization", "value": "Bearer testtoken"}], + "url": { "raw": "{{baseUrl}}/users/1", "host": ["{{baseUrl}}"], "path": ["users", "1"] } + } + } + ] + }, + { + "name": "Boards", + "item": [ + { + "name": "Get All Boards for User", + "request": { + "method": "GET", + "header": [{"key": "Authorization", "value": "Bearer testtoken"}], + "url": { "raw": "{{baseUrl}}/boards/user/1", "host": ["{{baseUrl}}"], "path": ["boards", "user", "1"] } + } + }, + { + "name": "Get Board by ID", + "request": { + "method": "GET", + "header": [{"key": "Authorization", "value": "Bearer testtoken"}], + "url": { "raw": "{{baseUrl}}/boards/user/1/123", "host": ["{{baseUrl}}"], "path": ["boards", "user", "1", "123"] } + } + }, + { + "name": "Add Board", + "request": { + "method": "POST", + "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}], + "body": { "mode": "raw", "raw": "{\n \"name\": \"Project Board\"\n}" }, + "url": { "raw": "{{baseUrl}}/boards/user/1", "host": ["{{baseUrl}}"], "path": ["boards", "user", "1"] } + } + }, + { + "name": "Update Board", + "request": { + "method": "PUT", + "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}], + "body": { "mode": "raw", "raw": "{\n \"name\": \"Updated Board Name\"\n}" }, + "url": { "raw": "{{baseUrl}}/boards/user/1/123", "host": ["{{baseUrl}}"], "path": ["boards", "user", "1", "123"] } + } + }, + { + "name": "Delete Board", + "request": { + "method": "DELETE", + "header": [{"key": "Authorization", "value": "Bearer testtoken"}], + "url": { "raw": "{{baseUrl}}/boards/user/1/123", "host": ["{{baseUrl}}"], "path": ["boards", "user", "1", "123"] } + } + } + ] + }, + { + "name": "Tasks", + "item": [ + { + "name": "Get All Tasks for Board", + "request": { + "method": "GET", + "header": [{"key": "Authorization", "value": "Bearer testtoken"}], + "url": { "raw": "{{baseUrl}}/tasks/board/123", "host": ["{{baseUrl}}"], "path": ["tasks", "board", "123"] } + } + }, + { + "name": "Get Task by ID", + "request": { + "method": "GET", + "header": [{"key": "Authorization", "value": "Bearer testtoken"}], + "url": { "raw": "{{baseUrl}}/tasks/board/123/456", "host": ["{{baseUrl}}"], "path": ["tasks", "board", "123", "456"] } + } + }, + { + "name": "Add Task", + "request": { + "method": "POST", + "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}], + "body": { "mode": "raw", "raw": "{\n \"title\": \"New Task\",\n \"description\": \"Task details\",\n \"status\": \"todo\"\n}" }, + "url": { "raw": "{{baseUrl}}/tasks/board/123", "host": ["{{baseUrl}}"], "path": ["tasks", "board", "123"] } + } + }, + { + "name": "Update Task", + "request": { + "method": "PUT", + "header": [{"key": "Content-Type", "value": "application/json"}, {"key": "Authorization", "value": "Bearer testtoken"}], + "body": { "mode": "raw", "raw": "{\n \"title\": \"Updated Task\",\n \"description\": \"Updated details\",\n \"status\": \"done\"\n}" }, + "url": { "raw": "{{baseUrl}}/tasks/board/123/456", "host": ["{{baseUrl}}"], "path": ["tasks", "board", "123", "456"] } + } + }, + { + "name": "Delete Task", + "request": { + "method": "DELETE", + "header": [{"key": "Authorization", "value": "Bearer testtoken"}], + "url": { "raw": "{{baseUrl}}/tasks/board/123/456", "host": ["{{baseUrl}}"], "path": ["tasks", "board", "123", "456"] } + } + } + ] + } + ] +} diff --git a/lib/constants/EnvVars.js b/lib/constants/EnvVars.js new file mode 100644 index 0000000..cbaa257 --- /dev/null +++ b/lib/constants/EnvVars.js @@ -0,0 +1,29 @@ +"use strict"; +/** + * Environments variables declared here. + */ +var _a, _b, _c, _d, _e, _f, _g; +Object.defineProperty(exports, "__esModule", { value: true }); +/* eslint-disable node/no-process-env */ +exports.default = { + NodeEnv: ((_a = process.env.NODE_ENV) !== null && _a !== void 0 ? _a : ''), + Port: ((_b = process.env.PORT) !== null && _b !== void 0 ? _b : 0), + CookieProps: { + Key: 'ExpressGeneratorTs', + Secret: ((_c = process.env.COOKIE_SECRET) !== null && _c !== void 0 ? _c : ''), + // Casing to match express cookie options + Options: { + httpOnly: true, + signed: true, + path: ((_d = process.env.COOKIE_PATH) !== null && _d !== void 0 ? _d : ''), + maxAge: Number((_e = process.env.COOKIE_EXP) !== null && _e !== void 0 ? _e : 0), + domain: ((_f = process.env.COOKIE_DOMAIN) !== null && _f !== void 0 ? _f : ''), + secure: (process.env.SECURE_COOKIE === 'true'), + }, + }, + Jwt: { + Secret: ((_g = process.env.JWT_SECRET) !== null && _g !== void 0 ? _g : ''), + Exp: (process.env.COOKIE_EXP && process.env.COOKIE_EXP !== '' ? process.env.COOKIE_EXP : '1h'), // exp at the same time as the cookie + }, +}; +//# sourceMappingURL=EnvVars.js.map \ No newline at end of file diff --git a/lib/constants/EnvVars.js.map b/lib/constants/EnvVars.js.map new file mode 100644 index 0000000..1a2395d --- /dev/null +++ b/lib/constants/EnvVars.js.map @@ -0,0 +1 @@ +{"version":3,"file":"EnvVars.js","sourceRoot":"","sources":["../../src/constants/EnvVars.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,wCAAwC;AAGxC,kBAAe;IACb,OAAO,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,QAAQ,mCAAI,EAAE,CAAC;IACrC,IAAI,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,IAAI,mCAAI,CAAC,CAAC;IAC7B,WAAW,EAAE;QACX,GAAG,EAAE,oBAAoB;QACzB,MAAM,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,aAAa,mCAAI,EAAE,CAAC;QACzC,yCAAyC;QACzC,OAAO,EAAE;YACP,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,WAAW,mCAAI,EAAE,CAAC;YACrC,MAAM,EAAE,MAAM,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,UAAU,mCAAI,CAAC,CAAC;YAC3C,MAAM,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,aAAa,mCAAI,EAAE,CAAC;YACzC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,MAAM,CAAC;SAC/C;KACF;IACD,GAAG,EAAE;QACH,MAAM,EAAE,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,UAAU,mCAAK,EAAE,CAAC;QACvC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,qCAAqC;KACtI;CACO,CAAC"} \ No newline at end of file diff --git a/lib/constants/HttpStatusCodes.js b/lib/constants/HttpStatusCodes.js new file mode 100644 index 0000000..96b253b --- /dev/null +++ b/lib/constants/HttpStatusCodes.js @@ -0,0 +1,327 @@ +"use strict"; +/* eslint-disable max-len */ +/** + * This file was copied from here: https://gist.github.com/scokmen/f813c904ef79022e84ab2409574d1b45 + */ +Object.defineProperty(exports, "__esModule", { value: true }); +/** + * Hypertext Transfer Protocol (HTTP) response status codes. + * @see {@link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes} + */ +var HttpStatusCodes; +(function (HttpStatusCodes) { + /** + * The server has received the request headers and the client should proceed to send the request body + * (in the case of a request for which a body needs to be sent; for example, a POST request). + * Sending a large request body to a server after a request has been rejected for inappropriate headers would be inefficient. + * To have a server check the request's headers, a client must send Expect: 100-continue as a header in its initial request + * and receive a 100 Continue status code in response before sending the body. The response 417 Expectation Failed indicates the request should not be continued. + */ + HttpStatusCodes[HttpStatusCodes["CONTINUE"] = 100] = "CONTINUE"; + /** + * The requester has asked the server to switch protocols and the server has agreed to do so. + */ + HttpStatusCodes[HttpStatusCodes["SWITCHING_PROTOCOLS"] = 101] = "SWITCHING_PROTOCOLS"; + /** + * A WebDAV request may contain many sub-requests involving file operations, requiring a long time to complete the request. + * This code indicates that the server has received and is processing the request, but no response is available yet. + * This prevents the client from timing out and assuming the request was lost. + */ + HttpStatusCodes[HttpStatusCodes["PROCESSING"] = 102] = "PROCESSING"; + /** + * Standard response for successful HTTP requests. + * The actual response will depend on the request method used. + * In a GET request, the response will contain an entity corresponding to the requested resource. + * In a POST request, the response will contain an entity describing or containing the result of the action. + */ + HttpStatusCodes[HttpStatusCodes["OK"] = 200] = "OK"; + /** + * The request has been fulfilled, resulting in the creation of a new resource. + */ + HttpStatusCodes[HttpStatusCodes["CREATED"] = 201] = "CREATED"; + /** + * The request has been accepted for processing, but the processing has not been completed. + * The request might or might not be eventually acted upon, and may be disallowed when processing occurs. + */ + HttpStatusCodes[HttpStatusCodes["ACCEPTED"] = 202] = "ACCEPTED"; + /** + * SINCE HTTP/1.1 + * The server is a transforming proxy that received a 200 OK from its origin, + * but is returning a modified version of the origin's response. + */ + HttpStatusCodes[HttpStatusCodes["NON_AUTHORITATIVE_INFORMATION"] = 203] = "NON_AUTHORITATIVE_INFORMATION"; + /** + * The server successfully processed the request and is not returning any content. + */ + HttpStatusCodes[HttpStatusCodes["NO_CONTENT"] = 204] = "NO_CONTENT"; + /** + * The server successfully processed the request, but is not returning any content. + * Unlike a 204 response, this response requires that the requester reset the document view. + */ + HttpStatusCodes[HttpStatusCodes["RESET_CONTENT"] = 205] = "RESET_CONTENT"; + /** + * The server is delivering only part of the resource (byte serving) due to a range header sent by the client. + * The range header is used by HTTP clients to enable resuming of interrupted downloads, + * or split a download into multiple simultaneous streams. + */ + HttpStatusCodes[HttpStatusCodes["PARTIAL_CONTENT"] = 206] = "PARTIAL_CONTENT"; + /** + * The message body that follows is an XML message and can contain a number of separate response codes, + * depending on how many sub-requests were made. + */ + HttpStatusCodes[HttpStatusCodes["MULTI_STATUS"] = 207] = "MULTI_STATUS"; + /** + * The members of a DAV binding have already been enumerated in a preceding part of the (multistatus) response, + * and are not being included again. + */ + HttpStatusCodes[HttpStatusCodes["ALREADY_REPORTED"] = 208] = "ALREADY_REPORTED"; + /** + * The server has fulfilled a request for the resource, + * and the response is a representation of the result of one or more instance-manipulations applied to the current instance. + */ + HttpStatusCodes[HttpStatusCodes["IM_USED"] = 226] = "IM_USED"; + /** + * Indicates multiple options for the resource from which the client may choose (via agent-driven content negotiation). + * For example, this code could be used to present multiple video format options, + * to list files with different filename extensions, or to suggest word-sense disambiguation. + */ + HttpStatusCodes[HttpStatusCodes["MULTIPLE_CHOICES"] = 300] = "MULTIPLE_CHOICES"; + /** + * This and all future requests should be directed to the given URI. + */ + HttpStatusCodes[HttpStatusCodes["MOVED_PERMANENTLY"] = 301] = "MOVED_PERMANENTLY"; + /** + * This is an example of industry practice contradicting the standard. + * The HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect + * (the original describing phrase was "Moved Temporarily"), but popular browsers implemented 302 + * with the functionality of a 303 See Other. Therefore, HTTP/1.1 added status codes 303 and 307 + * to distinguish between the two behaviours. However, some Web applications and frameworks + * use the 302 status code as if it were the 303. + */ + HttpStatusCodes[HttpStatusCodes["FOUND"] = 302] = "FOUND"; + /** + * SINCE HTTP/1.1 + * The response to the request can be found under another URI using a GET method. + * When received in response to a POST (or PUT/DELETE), the client should presume that + * the server has received the data and should issue a redirect with a separate GET message. + */ + HttpStatusCodes[HttpStatusCodes["SEE_OTHER"] = 303] = "SEE_OTHER"; + /** + * Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-None-Match. + * In such case, there is no need to retransmit the resource since the client still has a previously-downloaded copy. + */ + HttpStatusCodes[HttpStatusCodes["NOT_MODIFIED"] = 304] = "NOT_MODIFIED"; + /** + * SINCE HTTP/1.1 + * The requested resource is available only through a proxy, the address for which is provided in the response. + * Many HTTP clients (such as Mozilla and Internet Explorer) do not correctly handle responses with this status code, primarily for security reasons. + */ + HttpStatusCodes[HttpStatusCodes["USE_PROXY"] = 305] = "USE_PROXY"; + /** + * No longer used. Originally meant "Subsequent requests should use the specified proxy." + */ + HttpStatusCodes[HttpStatusCodes["SWITCH_PROXY"] = 306] = "SWITCH_PROXY"; + /** + * SINCE HTTP/1.1 + * In this case, the request should be repeated with another URI; however, future requests should still use the original URI. + * In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request. + * For example, a POST request should be repeated using another POST request. + */ + HttpStatusCodes[HttpStatusCodes["TEMPORARY_REDIRECT"] = 307] = "TEMPORARY_REDIRECT"; + /** + * The request and all future requests should be repeated using another URI. + * 307 and 308 parallel the behaviors of 302 and 301, but do not allow the HTTP method to change. + * So, for example, submitting a form to a permanently redirected resource may continue smoothly. + */ + HttpStatusCodes[HttpStatusCodes["PERMANENT_REDIRECT"] = 308] = "PERMANENT_REDIRECT"; + /** + * The server cannot or will not process the request due to an apparent client error + * (e.g., malformed request syntax, too large size, invalid request message framing, or deceptive request routing). + */ + HttpStatusCodes[HttpStatusCodes["BAD_REQUEST"] = 400] = "BAD_REQUEST"; + /** + * Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet + * been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the + * requested resource. See Basic access authentication and Digest access authentication. 401 semantically means + * "unauthenticated",i.e. the user does not have the necessary credentials. + */ + HttpStatusCodes[HttpStatusCodes["UNAUTHORIZED"] = 401] = "UNAUTHORIZED"; + /** + * Reserved for future use. The original intention was that this code might be used as part of some form of digital + * cash or micro payment scheme, but that has not happened, and this code is not usually used. + * Google Developers API uses this status if a particular developer has exceeded the daily limit on requests. + */ + HttpStatusCodes[HttpStatusCodes["PAYMENT_REQUIRED"] = 402] = "PAYMENT_REQUIRED"; + /** + * The request was valid, but the server is refusing action. + * The user might not have the necessary permissions for a resource. + */ + HttpStatusCodes[HttpStatusCodes["FORBIDDEN"] = 403] = "FORBIDDEN"; + /** + * The requested resource could not be found but may be available in the future. + * Subsequent requests by the client are permissible. + */ + HttpStatusCodes[HttpStatusCodes["NOT_FOUND"] = 404] = "NOT_FOUND"; + /** + * A request method is not supported for the requested resource; + * for example, a GET request on a form that requires data to be presented via POST, or a PUT request on a read-only resource. + */ + HttpStatusCodes[HttpStatusCodes["METHOD_NOT_ALLOWED"] = 405] = "METHOD_NOT_ALLOWED"; + /** + * The requested resource is capable of generating only content not acceptable according to the Accept headers sent in the request. + */ + HttpStatusCodes[HttpStatusCodes["NOT_ACCEPTABLE"] = 406] = "NOT_ACCEPTABLE"; + /** + * The client must first authenticate itself with the proxy. + */ + HttpStatusCodes[HttpStatusCodes["PROXY_AUTHENTICATION_REQUIRED"] = 407] = "PROXY_AUTHENTICATION_REQUIRED"; + /** + * The server timed out waiting for the request. + * According to HTTP specifications: + * "The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time." + */ + HttpStatusCodes[HttpStatusCodes["REQUEST_TIMEOUT"] = 408] = "REQUEST_TIMEOUT"; + /** + * Indicates that the request could not be processed because of conflict in the request, + * such as an edit conflict between multiple simultaneous updates. + */ + HttpStatusCodes[HttpStatusCodes["CONFLICT"] = 409] = "CONFLICT"; + /** + * Indicates that the resource requested is no longer available and will not be available again. + * This should be used when a resource has been intentionally removed and the resource should be purged. + * Upon receiving a 410 status code, the client should not request the resource in the future. + * Clients such as search engines should remove the resource from their indices. + * Most use cases do not require clients and search engines to purge the resource, and a "404 Not Found" may be used instead. + */ + HttpStatusCodes[HttpStatusCodes["GONE"] = 410] = "GONE"; + /** + * The request did not specify the length of its content, which is required by the requested resource. + */ + HttpStatusCodes[HttpStatusCodes["LENGTH_REQUIRED"] = 411] = "LENGTH_REQUIRED"; + /** + * The server does not meet one of the preconditions that the requester put on the request. + */ + HttpStatusCodes[HttpStatusCodes["PRECONDITION_FAILED"] = 412] = "PRECONDITION_FAILED"; + /** + * The request is larger than the server is willing or able to process. Previously called "Request Entity Too Large". + */ + HttpStatusCodes[HttpStatusCodes["PAYLOAD_TOO_LARGE"] = 413] = "PAYLOAD_TOO_LARGE"; + /** + * The URI provided was too long for the server to process. Often the result of too much data being encoded as a query-string of a GET request, + * in which case it should be converted to a POST request. + * Called "Request-URI Too Long" previously. + */ + HttpStatusCodes[HttpStatusCodes["URI_TOO_LONG"] = 414] = "URI_TOO_LONG"; + /** + * The request entity has a media type which the server or resource does not support. + * For example, the client uploads an image as image/svg+xml, but the server requires that images use a different format. + */ + HttpStatusCodes[HttpStatusCodes["UNSUPPORTED_MEDIA_TYPE"] = 415] = "UNSUPPORTED_MEDIA_TYPE"; + /** + * The client has asked for a portion of the file (byte serving), but the server cannot supply that portion. + * For example, if the client asked for a part of the file that lies beyond the end of the file. + * Called "Requested Range Not Satisfiable" previously. + */ + HttpStatusCodes[HttpStatusCodes["RANGE_NOT_SATISFIABLE"] = 416] = "RANGE_NOT_SATISFIABLE"; + /** + * The server cannot meet the requirements of the Expect request-header field. + */ + HttpStatusCodes[HttpStatusCodes["EXPECTATION_FAILED"] = 417] = "EXPECTATION_FAILED"; + /** + * This code was defined in 1998 as one of the traditional IETF April Fools' jokes, in RFC 2324, Hyper Text Coffee Pot Control Protocol, + * and is not expected to be implemented by actual HTTP servers. The RFC specifies this code should be returned by + * teapots requested to brew coffee. This HTTP status is used as an Easter egg in some websites, including Google.com. + */ + HttpStatusCodes[HttpStatusCodes["I_AM_A_TEAPOT"] = 418] = "I_AM_A_TEAPOT"; + /** + * The request was directed at a server that is not able to produce a response (for example because a connection reuse). + */ + HttpStatusCodes[HttpStatusCodes["MISDIRECTED_REQUEST"] = 421] = "MISDIRECTED_REQUEST"; + /** + * The request was well-formed but was unable to be followed due to semantic errors. + */ + HttpStatusCodes[HttpStatusCodes["UNPROCESSABLE_ENTITY"] = 422] = "UNPROCESSABLE_ENTITY"; + /** + * The resource that is being accessed is locked. + */ + HttpStatusCodes[HttpStatusCodes["LOCKED"] = 423] = "LOCKED"; + /** + * The request failed due to failure of a previous request (e.g., a PROPPATCH). + */ + HttpStatusCodes[HttpStatusCodes["FAILED_DEPENDENCY"] = 424] = "FAILED_DEPENDENCY"; + /** + * The client should switch to a different protocol such as TLS/1.0, given in the Upgrade header field. + */ + HttpStatusCodes[HttpStatusCodes["UPGRADE_REQUIRED"] = 426] = "UPGRADE_REQUIRED"; + /** + * The origin server requires the request to be conditional. + * Intended to prevent "the 'lost update' problem, where a client + * GETs a resource's state, modifies it, and PUTs it back to the server, + * when meanwhile a third party has modified the state on the server, leading to a conflict." + */ + HttpStatusCodes[HttpStatusCodes["PRECONDITION_REQUIRED"] = 428] = "PRECONDITION_REQUIRED"; + /** + * The user has sent too many requests in a given amount of time. Intended for use with rate-limiting schemes. + */ + HttpStatusCodes[HttpStatusCodes["TOO_MANY_REQUESTS"] = 429] = "TOO_MANY_REQUESTS"; + /** + * The server is unwilling to process the request because either an individual header field, + * or all the header fields collectively, are too large. + */ + HttpStatusCodes[HttpStatusCodes["REQUEST_HEADER_FIELDS_TOO_LARGE"] = 431] = "REQUEST_HEADER_FIELDS_TOO_LARGE"; + /** + * A server operator has received a legal demand to deny access to a resource or to a set of resources + * that includes the requested resource. The code 451 was chosen as a reference to the novel Fahrenheit 451. + */ + HttpStatusCodes[HttpStatusCodes["UNAVAILABLE_FOR_LEGAL_REASONS"] = 451] = "UNAVAILABLE_FOR_LEGAL_REASONS"; + /** + * A generic error message, given when an unexpected condition was encountered and no more specific message is suitable. + */ + HttpStatusCodes[HttpStatusCodes["INTERNAL_SERVER_ERROR"] = 500] = "INTERNAL_SERVER_ERROR"; + /** + * The server either does not recognize the request method, or it lacks the ability to fulfill the request. + * Usually this implies future availability (e.g., a new feature of a web-service API). + */ + HttpStatusCodes[HttpStatusCodes["NOT_IMPLEMENTED"] = 501] = "NOT_IMPLEMENTED"; + /** + * The server was acting as a gateway or proxy and received an invalid response from the upstream server. + */ + HttpStatusCodes[HttpStatusCodes["BAD_GATEWAY"] = 502] = "BAD_GATEWAY"; + /** + * The server is currently unavailable (because it is overloaded or down for maintenance). + * Generally, this is a temporary state. + */ + HttpStatusCodes[HttpStatusCodes["SERVICE_UNAVAILABLE"] = 503] = "SERVICE_UNAVAILABLE"; + /** + * The server was acting as a gateway or proxy and did not receive a timely response from the upstream server. + */ + HttpStatusCodes[HttpStatusCodes["GATEWAY_TIMEOUT"] = 504] = "GATEWAY_TIMEOUT"; + /** + * The server does not support the HTTP protocol version used in the request + */ + HttpStatusCodes[HttpStatusCodes["HTTP_VERSION_NOT_SUPPORTED"] = 505] = "HTTP_VERSION_NOT_SUPPORTED"; + /** + * Transparent content negotiation for the request results in a circular reference. + */ + HttpStatusCodes[HttpStatusCodes["VARIANT_ALSO_NEGOTIATES"] = 506] = "VARIANT_ALSO_NEGOTIATES"; + /** + * The server is unable to store the representation needed to complete the request. + */ + HttpStatusCodes[HttpStatusCodes["INSUFFICIENT_STORAGE"] = 507] = "INSUFFICIENT_STORAGE"; + /** + * The server detected an infinite loop while processing the request. + */ + HttpStatusCodes[HttpStatusCodes["LOOP_DETECTED"] = 508] = "LOOP_DETECTED"; + /** + * Further extensions to the request are required for the server to fulfill it. + */ + HttpStatusCodes[HttpStatusCodes["NOT_EXTENDED"] = 510] = "NOT_EXTENDED"; + /** + * The client needs to authenticate to gain network access. + * Intended for use by intercepting proxies used to control access to the network (e.g., "captive portals" used + * to require agreement to Terms of Service before granting full Internet access via a Wi-Fi hotspot). + */ + HttpStatusCodes[HttpStatusCodes["NETWORK_AUTHENTICATION_REQUIRED"] = 511] = "NETWORK_AUTHENTICATION_REQUIRED"; +})(HttpStatusCodes || (HttpStatusCodes = {})); +exports.default = HttpStatusCodes; +//# sourceMappingURL=HttpStatusCodes.js.map \ No newline at end of file diff --git a/lib/constants/HttpStatusCodes.js.map b/lib/constants/HttpStatusCodes.js.map new file mode 100644 index 0000000..9901b6f --- /dev/null +++ b/lib/constants/HttpStatusCodes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"HttpStatusCodes.js","sourceRoot":"","sources":["../../src/constants/HttpStatusCodes.ts"],"names":[],"mappings":";AAAA,4BAA4B;AAC5B;;GAEG;;AAEH;;;GAGG;AACH,IAAK,eAsXJ;AAtXD,WAAK,eAAe;IAEhB;;;;;;OAMG;IACH,+DAAc,CAAA;IAEd;;OAEG;IACH,qFAAyB,CAAA;IAEzB;;;;OAIG;IACH,mEAAgB,CAAA;IAEhB;;;;;OAKG;IACH,mDAAQ,CAAA;IAER;;OAEG;IACH,6DAAa,CAAA;IAEb;;;OAGG;IACH,+DAAc,CAAA;IAEd;;;;OAIG;IACH,yGAAmC,CAAA;IAEnC;;OAEG;IACH,mEAAgB,CAAA;IAEhB;;;OAGG;IACH,yEAAmB,CAAA;IAEnB;;;;OAIG;IACH,6EAAqB,CAAA;IAErB;;;OAGG;IACH,uEAAkB,CAAA;IAElB;;;OAGG;IACH,+EAAsB,CAAA;IAEtB;;;OAGG;IACH,6DAAa,CAAA;IAEb;;;;OAIG;IACH,+EAAsB,CAAA;IAEtB;;OAEG;IACH,iFAAuB,CAAA;IAEvB;;;;;;;OAOG;IACH,yDAAW,CAAA;IAEX;;;;;OAKG;IACH,iEAAe,CAAA;IAEf;;;OAGG;IACH,uEAAkB,CAAA;IAElB;;;;OAIG;IACH,iEAAe,CAAA;IAEf;;OAEG;IACH,uEAAkB,CAAA;IAElB;;;;;OAKG;IACH,mFAAwB,CAAA;IAExB;;;;OAIG;IACH,mFAAwB,CAAA;IAExB;;;OAGG;IACH,qEAAiB,CAAA;IAEjB;;;;;OAKG;IACH,uEAAkB,CAAA;IAElB;;;;OAIG;IACH,+EAAsB,CAAA;IAEtB;;;OAGG;IACH,iEAAe,CAAA;IAEf;;;OAGG;IACH,iEAAe,CAAA;IAEf;;;OAGG;IACH,mFAAwB,CAAA;IAExB;;OAEG;IACH,2EAAoB,CAAA;IAEpB;;OAEG;IACH,yGAAmC,CAAA;IAEnC;;;;OAIG;IACH,6EAAqB,CAAA;IAErB;;;OAGG;IACH,+DAAc,CAAA;IAEd;;;;;;OAMG;IACH,uDAAU,CAAA;IAEV;;OAEG;IACH,6EAAqB,CAAA;IAErB;;OAEG;IACH,qFAAyB,CAAA;IAEzB;;OAEG;IACH,iFAAuB,CAAA;IAEvB;;;;OAIG;IACH,uEAAkB,CAAA;IAElB;;;OAGG;IACH,2FAA4B,CAAA;IAE5B;;;;OAIG;IACH,yFAA2B,CAAA;IAE3B;;OAEG;IACH,mFAAwB,CAAA;IAExB;;;;OAIG;IACH,yEAAmB,CAAA;IAEnB;;OAEG;IACH,qFAAyB,CAAA;IAEzB;;OAEG;IACH,uFAA0B,CAAA;IAE1B;;OAEG;IACH,2DAAY,CAAA;IAEZ;;OAEG;IACH,iFAAuB,CAAA;IAEvB;;OAEG;IACH,+EAAsB,CAAA;IAEtB;;;;;OAKG;IACH,yFAA2B,CAAA;IAE3B;;OAEG;IACH,iFAAuB,CAAA;IAEvB;;;OAGG;IACH,6GAAqC,CAAA;IAErC;;;OAGG;IACH,yGAAmC,CAAA;IAEnC;;OAEG;IACH,yFAA2B,CAAA;IAE3B;;;OAGG;IACH,6EAAqB,CAAA;IAErB;;OAEG;IACH,qEAAiB,CAAA;IAEjB;;;OAGG;IACH,qFAAyB,CAAA;IAEzB;;OAEG;IACH,6EAAqB,CAAA;IAErB;;OAEG;IACH,mGAAgC,CAAA;IAEhC;;OAEG;IACH,6FAA6B,CAAA;IAE7B;;OAEG;IACH,uFAA0B,CAAA;IAE1B;;OAEG;IACH,yEAAmB,CAAA;IAEnB;;OAEG;IACH,uEAAkB,CAAA;IAElB;;;;OAIG;IACH,6GAAqC,CAAA;AACzC,CAAC,EAtXI,eAAe,KAAf,eAAe,QAsXnB;AAED,kBAAe,eAAe,CAAC"} \ No newline at end of file diff --git a/lib/constants/misc.js b/lib/constants/misc.js new file mode 100644 index 0000000..6f6641d --- /dev/null +++ b/lib/constants/misc.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.NodeEnvs = void 0; +var NodeEnvs; +(function (NodeEnvs) { + NodeEnvs["Dev"] = "development"; + NodeEnvs["Test"] = "test"; + NodeEnvs["Production"] = "production"; +})(NodeEnvs || (exports.NodeEnvs = NodeEnvs = {})); +//# sourceMappingURL=misc.js.map \ No newline at end of file diff --git a/lib/constants/misc.js.map b/lib/constants/misc.js.map new file mode 100644 index 0000000..5e06715 --- /dev/null +++ b/lib/constants/misc.js.map @@ -0,0 +1 @@ +{"version":3,"file":"misc.js","sourceRoot":"","sources":["../../src/constants/misc.ts"],"names":[],"mappings":";;;AAAA,IAAY,QAIX;AAJD,WAAY,QAAQ;IAClB,+BAAmB,CAAA;IACnB,yBAAa,CAAA;IACb,qCAAyB,CAAA;AAC3B,CAAC,EAJW,QAAQ,wBAAR,QAAQ,QAInB"} \ No newline at end of file diff --git a/lib/controllers/board.controller.js b/lib/controllers/board.controller.js new file mode 100644 index 0000000..1919d4c --- /dev/null +++ b/lib/controllers/board.controller.js @@ -0,0 +1,62 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const board_repo_1 = __importDefault(require("@src/repos/board.repo")); +class BoardController { + constructor() { + // Get all boards for a user + this.getBoardsByUserId = async (req, res) => { + if (!req.headers.authorization) { + return res.status(401).json({ error: 'Unauthorized' }); + } + const userId = +req.params.userId; + const boards = await board_repo_1.default.getBoardsByUserId(userId); + return res.json({ boards }); + }; + // Get single board by userId and boardId + this.getBoardByUserId = async (req, res) => { + if (!req.headers.authorization) { + return res.status(401).json({ error: 'Unauthorized' }); + } + const userId = +req.params.userId; + const boardId = +req.params.boardId; + const board = await board_repo_1.default.getBoardByUserId(userId, boardId); + return res.json({ board }); + }; + // Create board for a user + this.createBoard = async (req, res) => { + if (!req.body.name) { + return res.status(400).json({ error: 'Board name required' }); + } + const userId = +req.params.userId; + const boardData = req.body; + const board = await board_repo_1.default.createBoard(userId, boardData); + return res.status(201).json({ board }); + }; + // Update board for a user + this.updateBoard = async (req, res) => { + if (!req.body.name) { + return res.status(400).json({ error: 'Board name required' }); + } + const userId = +req.params.userId; + const boardId = +req.params.boardId; + const boardData = req.body; + const board = await board_repo_1.default.updateBoard(userId, boardId, boardData); + return res.json({ board }); + }; + // Delete board for a user + this.deleteBoard = async (req, res) => { + if (!req.headers.authorization) { + return res.status(401).json({ error: 'Unauthorized' }); + } + const userId = +req.params.userId; + const boardId = +req.params.boardId; + await board_repo_1.default.deleteBoard(userId, boardId); + return res.status(204).end(); + }; + } +} +exports.default = new BoardController(); +//# sourceMappingURL=board.controller.js.map \ No newline at end of file diff --git a/lib/controllers/board.controller.js.map b/lib/controllers/board.controller.js.map new file mode 100644 index 0000000..7a6c90f --- /dev/null +++ b/lib/controllers/board.controller.js.map @@ -0,0 +1 @@ +{"version":3,"file":"board.controller.js","sourceRoot":"","sources":["../../src/controllers/board.controller.ts"],"names":[],"mappings":";;;;;AACA,uEAA8C;AAI9C,MAAM,eAAe;IAArB;QACE,4BAA4B;QAC5B,sBAAiB,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACxD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;gBAC/B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YACzD,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YAClC,MAAM,MAAM,GAAG,MAAM,oBAAS,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;YACzD,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9B,CAAC,CAAC;QAEF,yCAAyC;QACzC,qBAAgB,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACvD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;gBAC/B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YACzD,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YAClC,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;YACpC,MAAM,KAAK,GAAG,MAAM,oBAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAChE,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7B,CAAC,CAAC;QAEF,0BAA0B;QAC1B,gBAAW,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YAClD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACnB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;YAChE,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YAClC,MAAM,SAAS,GAAW,GAAG,CAAC,IAAI,CAAC;YACnC,MAAM,KAAK,GAAG,MAAM,oBAAS,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YAC7D,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACzC,CAAC,CAAC;QAEF,0BAA0B;QAC1B,gBAAW,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YAClD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACnB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;YAChE,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YAClC,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;YACpC,MAAM,SAAS,GAAW,GAAG,CAAC,IAAI,CAAC;YACnC,MAAM,KAAK,GAAG,MAAM,oBAAS,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;YACtE,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7B,CAAC,CAAC;QAEF,0BAA0B;QAC1B,gBAAW,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YAClD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;gBAC/B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YACzD,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YAClC,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;YACpC,MAAM,oBAAS,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC,CAAC;IACJ,CAAC;CAAA;AAED,kBAAe,IAAI,eAAe,EAAE,CAAC"} \ No newline at end of file diff --git a/lib/controllers/task.controller.js b/lib/controllers/task.controller.js new file mode 100644 index 0000000..6370561 --- /dev/null +++ b/lib/controllers/task.controller.js @@ -0,0 +1,64 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const task_repo_1 = __importDefault(require("@src/repos/task.repo")); +class TaskController { + constructor() { + // Get all tasks for a board + this.getTasksByBoardId = async (req, res) => { + if (!req.headers.authorization) { + return res.status(401).json({ error: 'Unauthorized' }); + } + const boardId = +req.params.boardId; + const tasks = await task_repo_1.default.getTasksByBoardId(boardId); + return res.json({ tasks }); + }; + // Get single task by boardId and taskId + this.getTaskByBoardId = async (req, res) => { + if (!req.headers.authorization) { + return res.status(401).json({ error: 'Unauthorized' }); + } + const boardId = +req.params.boardId; + const taskId = +req.params.taskId; + const task = await task_repo_1.default.getTaskByBoardId(boardId, taskId); + return res.json({ task }); + }; + // Create task for a board + this.createTask = async (req, res) => { + // Dummy form validation + if (!req.body.title) { + return res.status(400).json({ error: 'Task title required' }); + } + const boardId = +req.params.boardId; + const taskData = req.body; + const task = await task_repo_1.default.createTask(boardId, taskData); + return res.status(201).json({ task }); + }; + // Update task for a board + this.updateTask = async (req, res) => { + // Dummy form validation + if (!req.body.title) { + return res.status(400).json({ error: 'Task title required' }); + } + const boardId = +req.params.boardId; + const taskId = +req.params.taskId; + const taskData = req.body; + const task = await task_repo_1.default.updateTask(boardId, taskId, taskData); + return res.json({ task }); + }; + // Delete task for a board + this.deleteTask = async (req, res) => { + if (!req.headers.authorization) { + return res.status(401).json({ error: 'Unauthorized' }); + } + const boardId = +req.params.boardId; + const taskId = +req.params.taskId; + await task_repo_1.default.deleteTask(boardId, taskId); + return res.status(204).end(); + }; + } +} +exports.default = new TaskController(); +//# sourceMappingURL=task.controller.js.map \ No newline at end of file diff --git a/lib/controllers/task.controller.js.map b/lib/controllers/task.controller.js.map new file mode 100644 index 0000000..d5097fb --- /dev/null +++ b/lib/controllers/task.controller.js.map @@ -0,0 +1 @@ +{"version":3,"file":"task.controller.js","sourceRoot":"","sources":["../../src/controllers/task.controller.ts"],"names":[],"mappings":";;;;;AACA,qEAA4C;AAG5C,MAAM,cAAc;IAApB;QACE,4BAA4B;QAC5B,sBAAiB,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACxD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;gBAC/B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YACzD,CAAC;YACD,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;YACpC,MAAM,KAAK,GAAG,MAAM,mBAAQ,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YACxD,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7B,CAAC,CAAC;QAEF,wCAAwC;QACxC,qBAAgB,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACvD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;gBAC/B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YACzD,CAAC;YACD,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;YACpC,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YAClC,MAAM,IAAI,GAAG,MAAM,mBAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC9D,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC;QAEF,0BAA0B;QAC1B,eAAU,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACjD,wBAAwB;YACxB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACpB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;YAChE,CAAC;YACD,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;YACpC,MAAM,QAAQ,GAAU,GAAG,CAAC,IAAI,CAAC;YACjC,MAAM,IAAI,GAAG,MAAM,mBAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAC1D,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,CAAC,CAAC;QAEF,0BAA0B;QAC1B,eAAU,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACjD,wBAAwB;YACxB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACpB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;YAChE,CAAC;YACD,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;YACpC,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YAClC,MAAM,QAAQ,GAAU,GAAG,CAAC,IAAI,CAAC;YACjC,MAAM,IAAI,GAAG,MAAM,mBAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;YAClE,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC;QAEF,0BAA0B;QAC1B,eAAU,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACjD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;gBAC/B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YACzD,CAAC;YACD,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;YACpC,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YAClC,MAAM,mBAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC3C,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC,CAAC;IACJ,CAAC;CAAA;AAED,kBAAe,IAAI,cAAc,EAAE,CAAC"} \ No newline at end of file diff --git a/lib/controllers/user.controller.js b/lib/controllers/user.controller.js new file mode 100644 index 0000000..751ac1d --- /dev/null +++ b/lib/controllers/user.controller.js @@ -0,0 +1,31 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const user_repo_1 = __importDefault(require("@src/repos/user.repo")); +class UserController { + constructor() { + this.getAll = async (_, res) => { + const users = await user_repo_1.default.getAll(); + return res.status(200).json({ users }); + }; + this.add = async (req, res) => { + const user = req.body.user; + await user_repo_1.default.add(user); + return res.status(201).end(); + }; + this.update = async (req, res) => { + const user = req.body.user; + await user_repo_1.default.update(user); + return res.status(200).end(); + }; + this.delete = async (req, res) => { + const id = +req.params.id; + await user_repo_1.default.delete(id); + return res.status(200).end(); + }; + } +} +exports.default = new UserController(); +//# sourceMappingURL=user.controller.js.map \ No newline at end of file diff --git a/lib/controllers/user.controller.js.map b/lib/controllers/user.controller.js.map new file mode 100644 index 0000000..d2585d7 --- /dev/null +++ b/lib/controllers/user.controller.js.map @@ -0,0 +1 @@ +{"version":3,"file":"user.controller.js","sourceRoot":"","sources":["../../src/controllers/user.controller.ts"],"names":[],"mappings":";;;;;AACA,qEAA4C;AAG5C,MAAM,cAAc;IAApB;QACS,WAAM,GAAG,KAAK,EAAE,CAAU,EAAE,GAAa,EAAE,EAAE;YAClD,MAAM,KAAK,GAAG,MAAM,mBAAQ,CAAC,MAAM,EAAE,CAAC;YACtC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACzC,CAAC,CAAC;QAEK,QAAG,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACjD,MAAM,IAAI,GAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAClC,MAAM,mBAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACzB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC,CAAC;QAEK,WAAM,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACpD,MAAM,IAAI,GAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAClC,MAAM,mBAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC,CAAC;QAEK,WAAM,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;YACpD,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,MAAM,mBAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC1B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC,CAAC;IACJ,CAAC;CAAA;AAED,kBAAe,IAAI,cAAc,EAAE,CAAC"} \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..f399426 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,14 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +require("./pre-start"); // Must be the first import +const jet_logger_1 = __importDefault(require("jet-logger")); +const EnvVars_1 = __importDefault(require("@src/constants/EnvVars")); +const server_1 = __importDefault(require("./server")); +// **** Run **** // +const SERVER_START_MSG = ('Express server started on port: ' + + EnvVars_1.default.Port.toString()); +server_1.default.listen(EnvVars_1.default.Port, () => jet_logger_1.default.info(SERVER_START_MSG)); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/index.js.map b/lib/index.js.map new file mode 100644 index 0000000..9562a51 --- /dev/null +++ b/lib/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,uBAAqB,CAAC,2BAA2B;AACjD,4DAAgC;AAEhC,qEAA6C;AAC7C,sDAA8B;AAG9B,mBAAmB;AAEnB,MAAM,gBAAgB,GAAG,CAAC,kCAAkC;IAC1D,iBAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;AAE3B,gBAAM,CAAC,MAAM,CAAC,iBAAO,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,oBAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/lib/models/board.model.js b/lib/models/board.model.js new file mode 100644 index 0000000..12e0238 --- /dev/null +++ b/lib/models/board.model.js @@ -0,0 +1,48 @@ +"use strict"; +// **** Variables **** // +Object.defineProperty(exports, "__esModule", { value: true }); +const INVALID_CONSTRUCTOR_PARAM = 'nameOrObj arg must be a string or an object with the appropriate board keys.'; +// **** Functions **** // +/** + * Create new Board. + */ +function new_(userId, name, description, createdAt, updatedAt, id) { + const now = new Date().toISOString(); + return { + id: (id !== null && id !== void 0 ? id : -1), + userId: (userId !== null && userId !== void 0 ? userId : -1), + name: (name !== null && name !== void 0 ? name : ''), + description, + createdAt: (createdAt !== null && createdAt !== void 0 ? createdAt : now), + updatedAt: (updatedAt !== null && updatedAt !== void 0 ? updatedAt : now), + }; +} +/** + * Get board instance from object. + */ +function from(param) { + if (!isBoard(param)) { + throw new Error(INVALID_CONSTRUCTOR_PARAM); + } + const p = param; + return new_(p.userId, p.name, p.description, p.createdAt, p.updatedAt, p.id); +} +/** + * See if the param meets criteria to be a board. + */ +function isBoard(arg) { + return (!!arg && + typeof arg === 'object' && + 'id' in arg && + 'userId' in arg && + 'name' in arg && + 'createdAt' in arg && + 'updatedAt' in arg); +} +// **** Export default **** // +exports.default = { + new: new_, + from, + isBoard, +}; +//# sourceMappingURL=board.model.js.map \ No newline at end of file diff --git a/lib/models/board.model.js.map b/lib/models/board.model.js.map new file mode 100644 index 0000000..057e59f --- /dev/null +++ b/lib/models/board.model.js.map @@ -0,0 +1 @@ +{"version":3,"file":"board.model.js","sourceRoot":"","sources":["../../src/models/board.model.ts"],"names":[],"mappings":";AAAA,yBAAyB;;AAEzB,MAAM,yBAAyB,GAAG,8EAA8E,CAAC;AAajH,yBAAyB;AAEzB;;GAEG;AACH,SAAS,IAAI,CACZ,MAAe,EACf,IAAa,EACb,WAAoB,EACpB,SAAkB,EAClB,SAAkB,EAClB,EAAW;IAEX,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO;QACN,EAAE,EAAE,CAAC,EAAE,aAAF,EAAE,cAAF,EAAE,GAAI,CAAC,CAAC,CAAC;QACd,MAAM,EAAE,CAAC,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,CAAC,CAAC,CAAC;QACtB,IAAI,EAAE,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,EAAE,CAAC;QAClB,WAAW;QACX,SAAS,EAAE,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,GAAG,CAAC;QAC7B,SAAS,EAAE,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,GAAG,CAAC;KAC7B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,IAAI,CAAC,KAAa;IAC1B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,CAAC,GAAG,KAAe,CAAC;IAC1B,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED;;GAEG;AACH,SAAS,OAAO,CAAC,GAAY;IAC5B,OAAO,CACN,CAAC,CAAC,GAAG;QACL,OAAO,GAAG,KAAK,QAAQ;QACvB,IAAI,IAAI,GAAG;QACX,QAAQ,IAAI,GAAG;QACf,MAAM,IAAI,GAAG;QACb,WAAW,IAAI,GAAG;QAClB,WAAW,IAAI,GAAG,CAClB,CAAC;AACH,CAAC;AAED,8BAA8B;AAE9B,kBAAe;IACd,GAAG,EAAE,IAAI;IACT,IAAI;IACJ,OAAO;CACE,CAAC"} \ No newline at end of file diff --git a/lib/models/task.model.js b/lib/models/task.model.js new file mode 100644 index 0000000..a2d31bd --- /dev/null +++ b/lib/models/task.model.js @@ -0,0 +1,50 @@ +"use strict"; +// **** Variables **** // +Object.defineProperty(exports, "__esModule", { value: true }); +const INVALID_CONSTRUCTOR_PARAM = 'titleOrObj arg must be a string or an object with the appropriate task keys.'; +// **** Functions **** // +/** + * Create new Task. + */ +function new_(boardId, title, status, description, createdAt, updatedAt, id) { + const now = new Date().toISOString(); + return { + id: (id !== null && id !== void 0 ? id : -1), + boardId: (boardId !== null && boardId !== void 0 ? boardId : -1), + title: (title !== null && title !== void 0 ? title : ''), + status: (status !== null && status !== void 0 ? status : 'todo'), + description, + createdAt: (createdAt !== null && createdAt !== void 0 ? createdAt : now), + updatedAt: (updatedAt !== null && updatedAt !== void 0 ? updatedAt : now), + }; +} +/** + * Get task instance from object. + */ +function from(param) { + if (!isTask(param)) { + throw new Error(INVALID_CONSTRUCTOR_PARAM); + } + const p = param; + return new_(p.boardId, p.title, p.status, p.description, p.createdAt, p.updatedAt, p.id); +} +/** + * See if the param meets criteria to be a task. + */ +function isTask(arg) { + return (!!arg && + typeof arg === 'object' && + 'id' in arg && + 'boardId' in arg && + 'title' in arg && + 'status' in arg && + 'createdAt' in arg && + 'updatedAt' in arg); +} +// **** Export default **** // +exports.default = { + new: new_, + from, + isTask, +}; +//# sourceMappingURL=task.model.js.map \ No newline at end of file diff --git a/lib/models/task.model.js.map b/lib/models/task.model.js.map new file mode 100644 index 0000000..6bb99d4 --- /dev/null +++ b/lib/models/task.model.js.map @@ -0,0 +1 @@ +{"version":3,"file":"task.model.js","sourceRoot":"","sources":["../../src/models/task.model.ts"],"names":[],"mappings":";AAAA,yBAAyB;;AAEzB,MAAM,yBAAyB,GAAG,8EAA8E,CAAC;AAcjH,yBAAyB;AAEzB;;GAEG;AACH,SAAS,IAAI,CACZ,OAAgB,EAChB,KAAc,EACd,MAAwC,EACxC,WAAoB,EACpB,SAAkB,EAClB,SAAkB,EAClB,EAAW;IAEX,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO;QACN,EAAE,EAAE,CAAC,EAAE,aAAF,EAAE,cAAF,EAAE,GAAI,CAAC,CAAC,CAAC;QACd,OAAO,EAAE,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,CAAC,CAAC,CAAC;QACxB,KAAK,EAAE,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,EAAE,CAAC;QACpB,MAAM,EAAE,CAAC,MAAM,aAAN,MAAM,cAAN,MAAM,GAAI,MAAM,CAAC;QAC1B,WAAW;QACX,SAAS,EAAE,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,GAAG,CAAC;QAC7B,SAAS,EAAE,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,GAAG,CAAC;KAC7B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,IAAI,CAAC,KAAa;IAC1B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,CAAC,GAAG,KAAc,CAAC;IACzB,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED;;GAEG;AACH,SAAS,MAAM,CAAC,GAAY;IAC3B,OAAO,CACN,CAAC,CAAC,GAAG;QACL,OAAO,GAAG,KAAK,QAAQ;QACvB,IAAI,IAAI,GAAG;QACX,SAAS,IAAI,GAAG;QAChB,OAAO,IAAI,GAAG;QACd,QAAQ,IAAI,GAAG;QACf,WAAW,IAAI,GAAG;QAClB,WAAW,IAAI,GAAG,CAClB,CAAC;AACH,CAAC;AAED,8BAA8B;AAE9B,kBAAe;IACd,GAAG,EAAE,IAAI;IACT,IAAI;IACJ,MAAM;CACG,CAAC"} \ No newline at end of file diff --git a/lib/models/user.model.js b/lib/models/user.model.js new file mode 100644 index 0000000..c4b977d --- /dev/null +++ b/lib/models/user.model.js @@ -0,0 +1,54 @@ +"use strict"; +// **** Variables **** // +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UserRoles = void 0; +const INVALID_CONSTRUCTOR_PARAM = 'nameOrObj arg must a string or an ' + + 'object with the appropriate user keys.'; +var UserRoles; +(function (UserRoles) { + UserRoles[UserRoles["Standard"] = 0] = "Standard"; + UserRoles[UserRoles["Admin"] = 1] = "Admin"; +})(UserRoles || (exports.UserRoles = UserRoles = {})); +// **** Functions **** // +/** + * Create new User. + */ +function new_(name, email, role, pwdHash, id) { + return { + id: (id !== null && id !== void 0 ? id : -1), + name: (name !== null && name !== void 0 ? name : ''), + email: (email !== null && email !== void 0 ? email : ''), + role: (role !== null && role !== void 0 ? role : UserRoles.Standard), + pwdHash: (pwdHash !== null && pwdHash !== void 0 ? pwdHash : ''), + }; +} +/** + * Get user instance from object. + */ +function from(param) { + // Check is user + if (!isUser(param)) { + throw new Error(INVALID_CONSTRUCTOR_PARAM); + } + // Get user instance + const p = param; + return new_(p.name, p.email, p.role, p.pwdHash, p.id); +} +/** + * See if the param meets criteria to be a user. + */ +function isUser(arg) { + return (!!arg && + typeof arg === 'object' && + 'id' in arg && + 'email' in arg && + 'name' in arg && + 'role' in arg); +} +// **** Export default **** // +exports.default = { + new: new_, + from, + isUser, +}; +//# sourceMappingURL=user.model.js.map \ No newline at end of file diff --git a/lib/models/user.model.js.map b/lib/models/user.model.js.map new file mode 100644 index 0000000..e57bffe --- /dev/null +++ b/lib/models/user.model.js.map @@ -0,0 +1 @@ +{"version":3,"file":"user.model.js","sourceRoot":"","sources":["../../src/models/user.model.ts"],"names":[],"mappings":";AAAA,yBAAyB;;;AAEzB,MAAM,yBAAyB,GAAG,oCAAoC;IACpE,wCAAwC,CAAC;AAE3C,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,iDAAQ,CAAA;IACR,2CAAK,CAAA;AACP,CAAC,EAHW,SAAS,yBAAT,SAAS,QAGpB;AAqBD,yBAAyB;AAEzB;;GAEG;AACH,SAAS,IAAI,CACX,IAAa,EACb,KAAc,EACd,IAAgB,EAChB,OAAgB,EAChB,EAAW;IAEX,OAAO;QACL,EAAE,EAAE,CAAC,EAAE,aAAF,EAAE,cAAF,EAAE,GAAI,CAAC,CAAC,CAAC;QACd,IAAI,EAAE,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,EAAE,CAAC;QAClB,KAAK,EAAE,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,EAAE,CAAC;QACpB,IAAI,EAAE,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,SAAS,CAAC,QAAQ,CAAC;QAClC,OAAO,EAAE,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,EAAE,CAAC;KACzB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,IAAI,CAAC,KAAa;IACzB,gBAAgB;IAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,oBAAoB;IACpB,MAAM,CAAC,GAAG,KAAc,CAAC;IACzB,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,SAAS,MAAM,CAAC,GAAY;IAC1B,OAAO,CACL,CAAC,CAAC,GAAG;QACL,OAAO,GAAG,KAAK,QAAQ;QACvB,IAAI,IAAI,GAAG;QACX,OAAO,IAAI,GAAG;QACd,MAAM,IAAI,GAAG;QACb,MAAM,IAAI,GAAG,CACd,CAAC;AACJ,CAAC;AAGD,8BAA8B;AAE9B,kBAAe;IACb,GAAG,EAAE,IAAI;IACT,IAAI;IACJ,MAAM;CACE,CAAC"} \ No newline at end of file diff --git a/lib/other/classes.js b/lib/other/classes.js new file mode 100644 index 0000000..adca176 --- /dev/null +++ b/lib/other/classes.js @@ -0,0 +1,17 @@ +"use strict"; +/** + * Miscellaneous shared classes go here. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RouteError = void 0; +/** + * Error with status code and message + */ +class RouteError extends Error { + constructor(status, message) { + super(message); + this.status = status; + } +} +exports.RouteError = RouteError; +//# sourceMappingURL=classes.js.map \ No newline at end of file diff --git a/lib/other/classes.js.map b/lib/other/classes.js.map new file mode 100644 index 0000000..2e5e091 --- /dev/null +++ b/lib/other/classes.js.map @@ -0,0 +1 @@ +{"version":3,"file":"classes.js","sourceRoot":"","sources":["../../src/other/classes.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAKH;;GAEG;AACH,MAAa,UAAW,SAAQ,KAAK;IAEnC,YAAY,MAAuB,EAAE,OAAe;QAClD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAND,gCAMC"} \ No newline at end of file diff --git a/lib/other/types.js b/lib/other/types.js new file mode 100644 index 0000000..11e638d --- /dev/null +++ b/lib/other/types.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/lib/other/types.js.map b/lib/other/types.js.map new file mode 100644 index 0000000..543f832 --- /dev/null +++ b/lib/other/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/other/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/lib/pre-start.js b/lib/pre-start.js new file mode 100644 index 0000000..4dd85b6 --- /dev/null +++ b/lib/pre-start.js @@ -0,0 +1,31 @@ +"use strict"; +/** + * Pre-start is where we want to place things that must run BEFORE the express + * server is started. This is useful for environment variables, command-line + * arguments, and cron-jobs. + */ +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +// NOTE: DO NOT IMPORT ANY SOURCE CODE HERE +const path_1 = __importDefault(require("path")); +const dotenv_1 = __importDefault(require("dotenv")); +const ts_command_line_args_1 = require("ts-command-line-args"); +// **** Setup **** // +// Command line arguments +const args = (0, ts_command_line_args_1.parse)({ + env: { + type: String, + defaultValue: 'development', + alias: 'e', + }, +}); +// Set the env file +const result2 = dotenv_1.default.config({ + path: path_1.default.join(__dirname, `../env/${args.env}.env`), +}); +if (result2.error) { + throw result2.error; +} +//# sourceMappingURL=pre-start.js.map \ No newline at end of file diff --git a/lib/pre-start.js.map b/lib/pre-start.js.map new file mode 100644 index 0000000..8bc6b66 --- /dev/null +++ b/lib/pre-start.js.map @@ -0,0 +1 @@ +{"version":3,"file":"pre-start.js","sourceRoot":"","sources":["../src/pre-start.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;AAEH,2CAA2C;AAC3C,gDAAwB;AACxB,oDAA4B;AAC5B,+DAA6C;AAU7C,qBAAqB;AAErB,yBAAyB;AACzB,MAAM,IAAI,GAAG,IAAA,4BAAK,EAAQ;IACxB,GAAG,EAAE;QACH,IAAI,EAAE,MAAM;QACZ,YAAY,EAAE,aAAa;QAC3B,KAAK,EAAE,GAAG;KACX;CACF,CAAC,CAAC;AAEH,mBAAmB;AACnB,MAAM,OAAO,GAAG,gBAAM,CAAC,MAAM,CAAC;IAC5B,IAAI,EAAE,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,IAAI,CAAC,GAAG,MAAM,CAAC;CACrD,CAAC,CAAC;AACH,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,MAAM,OAAO,CAAC,KAAK,CAAC;AACtB,CAAC"} \ No newline at end of file diff --git a/lib/public/scripts/http.js b/lib/public/scripts/http.js new file mode 100644 index 0000000..799f8aa --- /dev/null +++ b/lib/public/scripts/http.js @@ -0,0 +1,27 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var Http = (() => { + // Setup request for json + var getOptions = (verb, data) => { + var options = { + dataType: 'json', + method: verb, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + }; + if (data) { + options.body = JSON.stringify(data); + } + return options; + }; + // Set Http methods + return { + get: (path) => fetch(path, getOptions('GET')), + post: (path, data) => fetch(path, getOptions('POST', data)), + put: (path, data) => fetch(path, getOptions('PUT', data)), + delete: (path) => fetch(path, getOptions('DELETE')), + }; +})(); +//# sourceMappingURL=http.js.map \ No newline at end of file diff --git a/lib/public/scripts/http.js.map b/lib/public/scripts/http.js.map new file mode 100644 index 0000000..088257d --- /dev/null +++ b/lib/public/scripts/http.js.map @@ -0,0 +1 @@ +{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/public/scripts/http.js"],"names":[],"mappings":";;AAAA,IAAI,IAAI,GAAG,CAAC,GAAG,EAAE;IACf,yBAAyB;IACzB,IAAI,UAAU,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QAC9B,IAAI,OAAO,GAAG;YACZ,QAAQ,EAAE,MAAM;YAChB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE;gBACP,QAAQ,EAAE,kBAAkB;gBAC5B,cAAc,EAAE,kBAAkB;aACnC;SACF,CAAC;QACF,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IACF,mBAAmB;IACnB,OAAO;QACL,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC3D,GAAG,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACzD,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;KACpD,CAAC;AACJ,CAAC,CAAC,EAAE,CAAC"} \ No newline at end of file diff --git a/lib/public/scripts/users.js b/lib/public/scripts/users.js new file mode 100644 index 0000000..790b41c --- /dev/null +++ b/lib/public/scripts/users.js @@ -0,0 +1,154 @@ +"use strict"; +// ***** Start **** // +Object.defineProperty(exports, "__esModule", { value: true }); +displayUsers(); +// ***** Fetch and display users **** // +/** + * Call api + */ +function displayUsers() { + Http + .get('/api/users/all') + .then(resp => resp.json()) + .then((resp) => { + var allUsers = resp.users; + // Empty the anchor + var allUsersAnchor = document.getElementById('all-users-anchor'); + allUsersAnchor.innerHTML = ''; + // Append users to anchor + allUsers.forEach((user) => { + allUsersAnchor.innerHTML += getUserDisplayEle(user); + }); + }); +} +/** + * Get user display element + */ +function getUserDisplayEle(user) { + return (`
+ +
+
Name: ${user.name}
+
Email: ${user.email}
+ + +
+ +
+
+ Name: +
+
+ Email: +
+ + +
+
`); +} +// **** Add, Edit, and Delete Users **** // +// Setup event listener for button click +document.addEventListener('click', function (event) { + event.preventDefault(); + var ele = event.target; + if (ele.matches('#add-user-btn')) { + addUser(); + } + else if (ele.matches('.edit-user-btn')) { + showEditView(ele.parentNode.parentNode); + } + else if (ele.matches('.cancel-edit-btn')) { + cancelEdit(ele.parentNode.parentNode); + } + else if (ele.matches('.submit-edit-btn')) { + submitEdit(ele); + } + else if (ele.matches('.delete-user-btn')) { + deleteUser(ele); + } + else if (ele.matches('#logout-btn')) { + logoutUser(); + } +}, false); +/** + * Add a new user. + */ +function addUser() { + var nameInput = document.getElementById('name-input'); + var emailInput = document.getElementById('email-input'); + var data = { + user: { + id: -1, + name: nameInput.value, + email: emailInput.value, + role: 0, + }, + }; + // Call api + Http + .post('/api/users/add', data) + .then(() => displayUsers()); +} +/** + * Show edit view. + */ +function showEditView(userEle) { + var normalView = userEle.getElementsByClassName('normal-view')[0]; + var editView = userEle.getElementsByClassName('edit-view')[0]; + normalView.style.display = 'none'; + editView.style.display = 'block'; +} +/** + * Cancel edit. + */ +function cancelEdit(userEle) { + var normalView = userEle.getElementsByClassName('normal-view')[0]; + var editView = userEle.getElementsByClassName('edit-view')[0]; + normalView.style.display = 'block'; + editView.style.display = 'none'; +} +/** + * Submit edit. + */ +function submitEdit(ele) { + var userEle = ele.parentNode.parentNode; + var nameInput = userEle.getElementsByClassName('name-edit-input')[0]; + var emailInput = userEle.getElementsByClassName('email-edit-input')[0]; + var id = ele.getAttribute('data-user-id'); + var role = ele.getAttribute('data-user-role'); + var data = { + user: { + id: Number(id), + name: nameInput.value, + email: emailInput.value, + role: Number(role), + }, + }; + Http + .put('/api/users/update', data) + .then(() => displayUsers()); +} +/** + * Delete a user + */ +function deleteUser(ele) { + var id = ele.getAttribute('data-user-id'); + Http + .delete('/api/users/delete/' + id) + .then(() => displayUsers()); +} +// **** Logout **** // +function logoutUser() { + Http + .get('/api/auth/logout') + .then(() => window.location.href = '/'); +} +//# sourceMappingURL=users.js.map \ No newline at end of file diff --git a/lib/public/scripts/users.js.map b/lib/public/scripts/users.js.map new file mode 100644 index 0000000..f1edf65 --- /dev/null +++ b/lib/public/scripts/users.js.map @@ -0,0 +1 @@ +{"version":3,"file":"users.js","sourceRoot":"","sources":["../../../src/public/scripts/users.js"],"names":[],"mappings":";AAAA,sBAAsB;;AAEtB,YAAY,EAAE,CAAC;AAGf,wCAAwC;AAExC;;GAEG;AACH,SAAS,YAAY;IACnB,IAAI;SACD,GAAG,CAAC,gBAAgB,CAAC;SACrB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SACzB,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QACb,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC;QAC1B,mBAAmB;QACnB,IAAI,cAAc,GAAG,QAAQ,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC;QACjE,cAAc,CAAC,SAAS,GAAG,EAAE,CAAC;QAC9B,yBAAyB;QACzB,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACxB,cAAc,CAAC,SAAS,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,IAAI;IAC7B,OAAO,CACL;;;qBAGiB,IAAI,CAAC,IAAI;sBACR,IAAI,CAAC,KAAK;sDACsB,IAAI,CAAC,EAAE,qBAAqB,IAAI,CAAC,IAAI;;;wDAGnC,IAAI,CAAC,EAAE;;;;;;;wDAOP,IAAI,CAAC,IAAI;;;0DAGP,IAAI,CAAC,KAAK;;wDAEZ,IAAI,CAAC,EAAE;;;wDAGP,IAAI,CAAC,EAAE;;;;WAIpD,CACR,CAAC;AACJ,CAAC;AAGD,2CAA2C;AAE3C,wCAAwC;AACxC,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,UAAU,KAAK;IAChD,KAAK,CAAC,cAAc,EAAE,CAAC;IACvB,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,IAAI,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,CAAC;IACZ,CAAC;SAAM,IAAI,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACzC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAC1C,CAAC;SAAM,IAAI,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC3C,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;SAAM,IAAI,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC3C,UAAU,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC;SAAM,IAAI,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC3C,UAAU,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC;SAAM,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QACtC,UAAU,EAAE,CAAC;IACf,CAAC;AACH,CAAC,EAAE,KAAK,CAAC,CAAC;AAEV;;GAEG;AACH,SAAS,OAAO;IACd,IAAI,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;IACtD,IAAI,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;IACxD,IAAI,IAAI,GAAG;QACT,IAAI,EAAE;YACJ,EAAE,EAAE,CAAC,CAAC;YACN,IAAI,EAAE,SAAS,CAAC,KAAK;YACrB,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,IAAI,EAAE,CAAC;SACR;KACF,CAAC;IACF,WAAW;IACX,IAAI;SACD,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC;SAC5B,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,OAAO;IAC3B,IAAI,UAAU,GAAG,OAAO,CAAC,sBAAsB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,IAAI,QAAQ,GAAG,OAAO,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,OAAO;IACzB,IAAI,UAAU,GAAG,OAAO,CAAC,sBAAsB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,IAAI,QAAQ,GAAG,OAAO,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,GAAG;IACrB,IAAI,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC;IACxC,IAAI,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,UAAU,GAAG,OAAO,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,IAAI,EAAE,GAAG,GAAG,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;IAC1C,IAAI,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;IAC9C,IAAI,IAAI,GAAG;QACT,IAAI,EAAE;YACJ,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC;YACd,IAAI,EAAE,SAAS,CAAC,KAAK;YACrB,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;SACnB;KACF,CAAC;IACH,IAAI;SACA,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC;SAC9B,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,GAAG;IACrB,IAAI,EAAE,GAAG,GAAG,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;IAC3C,IAAI;SACA,MAAM,CAAC,oBAAoB,GAAG,EAAE,CAAC;SACjC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;AAChC,CAAC;AAGD,sBAAsB;AAEtB,SAAS,UAAU;IACjB,IAAI;SACD,GAAG,CAAC,kBAAkB,CAAC;SACvB,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;AAC5C,CAAC"} \ No newline at end of file diff --git a/lib/repos/BoardRepo.js b/lib/repos/BoardRepo.js new file mode 100644 index 0000000..47dfab5 --- /dev/null +++ b/lib/repos/BoardRepo.js @@ -0,0 +1,52 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const MockOrm_1 = __importDefault(require("./MockOrm")); +async function getBoardsByUserId(userId) { + const db = await MockOrm_1.default.openDb(); + return db.boards.filter((board) => board.userId === userId); +} +async function getBoardByUserId(userId, boardId) { + const db = await MockOrm_1.default.openDb(); + return db.boards.find((board) => board.userId === userId && board.id === boardId) || null; +} +async function createBoard(userId, board) { + const db = await MockOrm_1.default.openDb(); + board.id = Date.now(); + board.userId = userId; + board.createdAt = new Date().toISOString(); + board.updatedAt = board.createdAt; + db.boards.push(board); + await MockOrm_1.default.saveDb(db); + return board; +} +async function updateBoard(userId, boardId, boardData) { + const db = await MockOrm_1.default.openDb(); + const board = db.boards.find((b) => b.userId === userId && b.id === boardId); + if (board) { + Object.assign(board, boardData, { updatedAt: new Date().toISOString() }); + await MockOrm_1.default.saveDb(db); + return board; + } + return null; +} +async function deleteBoard(userId, boardId) { + const db = await MockOrm_1.default.openDb(); + const idx = db.boards.findIndex((b) => b.userId === userId && b.id === boardId); + if (idx !== -1) { + db.boards.splice(idx, 1); + await MockOrm_1.default.saveDb(db); + return true; + } + return false; +} +exports.default = { + getBoardsByUserId, + getBoardByUserId, + createBoard, + updateBoard, + deleteBoard, +}; +//# sourceMappingURL=BoardRepo.js.map \ No newline at end of file diff --git a/lib/repos/BoardRepo.js.map b/lib/repos/BoardRepo.js.map new file mode 100644 index 0000000..3e73e3b --- /dev/null +++ b/lib/repos/BoardRepo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"BoardRepo.js","sourceRoot":"","sources":["../../src/repos/BoardRepo.ts"],"names":[],"mappings":";;;;;AACA,wDAA4B;AAE5B,KAAK,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;AACrE,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,MAAc,EAAE,OAAe;IAC9D,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,IAAI,CAAC;AACnG,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,MAAc,EAAE,KAAa;IACvD,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,KAAK,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtB,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACrB,OAAO,KAAK,CAAC;AACd,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,MAAc,EAAE,OAAe,EAAE,SAA0B;IACrF,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;IACrF,IAAI,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACzE,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,MAAc,EAAE,OAAe;IACzD,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;IACxF,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QAChB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACzB,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,kBAAe;IACd,iBAAiB;IACjB,gBAAgB;IAChB,WAAW;IACX,WAAW;IACX,WAAW;CACX,CAAC"} \ No newline at end of file diff --git a/lib/repos/MockOrm.js b/lib/repos/MockOrm.js new file mode 100644 index 0000000..988c0ce --- /dev/null +++ b/lib/repos/MockOrm.js @@ -0,0 +1,27 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const jsonfile_1 = __importDefault(require("jsonfile")); +// **** Variables **** // +const DB_FILE_NAME = 'database.json'; +// **** Functions **** // +/** + * Fetch the json from the file. + */ +function openDb() { + return jsonfile_1.default.readFile(__dirname + '/' + DB_FILE_NAME); +} +/** + * Update the file. + */ +function saveDb(db) { + return jsonfile_1.default.writeFile((__dirname + '/' + DB_FILE_NAME), db); +} +// **** Export default **** // +exports.default = { + openDb, + saveDb, +}; +//# sourceMappingURL=MockOrm.js.map \ No newline at end of file diff --git a/lib/repos/MockOrm.js.map b/lib/repos/MockOrm.js.map new file mode 100644 index 0000000..759649a --- /dev/null +++ b/lib/repos/MockOrm.js.map @@ -0,0 +1 @@ +{"version":3,"file":"MockOrm.js","sourceRoot":"","sources":["../../src/repos/MockOrm.ts"],"names":[],"mappings":";;;;;AAEA,wDAAgC;AAOhC,yBAAyB;AAEzB,MAAM,YAAY,GAAG,eAAe,CAAC;AAYrC,yBAAyB;AAEzB;;GAEG;AACH,SAAS,MAAM;IACb,OAAO,kBAAQ,CAAC,QAAQ,CAAC,SAAS,GAAG,GAAG,GAAG,YAAY,CAAiB,CAAC;AAC3E,CAAC;AAED;;GAEG;AACH,SAAS,MAAM,CAAC,EAAO;IACrB,OAAO,kBAAQ,CAAC,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC;AAClE,CAAC;AAGD,8BAA8B;AAE9B,kBAAe;IACb,MAAM;IACN,MAAM;CACE,CAAC"} \ No newline at end of file diff --git a/lib/repos/TaskRepo.js b/lib/repos/TaskRepo.js new file mode 100644 index 0000000..a5bd8a5 --- /dev/null +++ b/lib/repos/TaskRepo.js @@ -0,0 +1,52 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const MockOrm_1 = __importDefault(require("./MockOrm")); +async function getTasksByBoardId(boardId) { + const db = await MockOrm_1.default.openDb(); + return db.tasks.filter((task) => task.boardId === boardId); +} +async function getTaskByBoardId(boardId, taskId) { + const db = await MockOrm_1.default.openDb(); + return db.tasks.find((task) => task.boardId === boardId && task.id === taskId) || null; +} +async function createTask(boardId, task) { + const db = await MockOrm_1.default.openDb(); + task.id = Date.now(); + task.boardId = boardId; + task.createdAt = new Date().toISOString(); + task.updatedAt = task.createdAt; + db.tasks.push(task); + await MockOrm_1.default.saveDb(db); + return task; +} +async function updateTask(boardId, taskId, taskData) { + const db = await MockOrm_1.default.openDb(); + const task = db.tasks.find((t) => t.boardId === boardId && t.id === taskId); + if (task) { + Object.assign(task, taskData, { updatedAt: new Date().toISOString() }); + await MockOrm_1.default.saveDb(db); + return task; + } + return null; +} +async function deleteTask(boardId, taskId) { + const db = await MockOrm_1.default.openDb(); + const idx = db.tasks.findIndex((t) => t.boardId === boardId && t.id === taskId); + if (idx !== -1) { + db.tasks.splice(idx, 1); + await MockOrm_1.default.saveDb(db); + return true; + } + return false; +} +exports.default = { + getTasksByBoardId, + getTaskByBoardId, + createTask, + updateTask, + deleteTask, +}; +//# sourceMappingURL=TaskRepo.js.map \ No newline at end of file diff --git a/lib/repos/TaskRepo.js.map b/lib/repos/TaskRepo.js.map new file mode 100644 index 0000000..2c42ba7 --- /dev/null +++ b/lib/repos/TaskRepo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"TaskRepo.js","sourceRoot":"","sources":["../../src/repos/TaskRepo.ts"],"names":[],"mappings":";;;;;AACA,wDAA4B;AAE5B,KAAK,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAW,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;AACnE,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,OAAe,EAAE,MAAc;IAC9D,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAW,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC;AAC/F,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,IAAW;IACrD,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACvB,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAChC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACrB,OAAO,IAAI,CAAC;AACb,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,MAAc,EAAE,QAAwB;IAClF,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;IACnF,IAAI,IAAI,EAAE,CAAC;QACV,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACvE,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,MAAc;IACxD,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;IACvF,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QAChB,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACxB,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,kBAAe;IACd,iBAAiB;IACjB,gBAAgB;IAChB,UAAU;IACV,UAAU;IACV,UAAU;CACV,CAAC"} \ No newline at end of file diff --git a/lib/repos/board.repo.js b/lib/repos/board.repo.js new file mode 100644 index 0000000..5996ec3 --- /dev/null +++ b/lib/repos/board.repo.js @@ -0,0 +1,52 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const MockOrm_1 = __importDefault(require("./MockOrm")); +async function getBoardsByUserId(userId) { + const db = await MockOrm_1.default.openDb(); + return db.boards.filter((board) => board.userId === userId); +} +async function getBoardByUserId(userId, boardId) { + const db = await MockOrm_1.default.openDb(); + return db.boards.find((board) => board.userId === userId && board.id === boardId) || null; +} +async function createBoard(userId, board) { + const db = await MockOrm_1.default.openDb(); + board.id = Date.now(); + board.userId = userId; + board.createdAt = new Date().toISOString(); + board.updatedAt = board.createdAt; + db.boards.push(board); + await MockOrm_1.default.saveDb(db); + return board; +} +async function updateBoard(userId, boardId, boardData) { + const db = await MockOrm_1.default.openDb(); + const board = db.boards.find((b) => b.userId === userId && b.id === boardId); + if (board) { + Object.assign(board, boardData, { updatedAt: new Date().toISOString() }); + await MockOrm_1.default.saveDb(db); + return board; + } + return null; +} +async function deleteBoard(userId, boardId) { + const db = await MockOrm_1.default.openDb(); + const idx = db.boards.findIndex((b) => b.userId === userId && b.id === boardId); + if (idx !== -1) { + db.boards.splice(idx, 1); + await MockOrm_1.default.saveDb(db); + return true; + } + return false; +} +exports.default = { + getBoardsByUserId, + getBoardByUserId, + createBoard, + updateBoard, + deleteBoard, +}; +//# sourceMappingURL=board.repo.js.map \ No newline at end of file diff --git a/lib/repos/board.repo.js.map b/lib/repos/board.repo.js.map new file mode 100644 index 0000000..7e0c263 --- /dev/null +++ b/lib/repos/board.repo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"board.repo.js","sourceRoot":"","sources":["../../src/repos/board.repo.ts"],"names":[],"mappings":";;;;;AACA,wDAA4B;AAE5B,KAAK,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;AACrE,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,MAAc,EAAE,OAAe;IAC9D,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,IAAI,CAAC;AACnG,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,MAAc,EAAE,KAAa;IACvD,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,KAAK,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtB,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACrB,OAAO,KAAK,CAAC;AACd,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,MAAc,EAAE,OAAe,EAAE,SAA0B;IACrF,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;IACrF,IAAI,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACzE,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,MAAc,EAAE,OAAe;IACzD,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;IACxF,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QAChB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACzB,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,kBAAe;IACd,iBAAiB;IACjB,gBAAgB;IAChB,WAAW;IACX,WAAW;IACX,WAAW;CACX,CAAC"} \ No newline at end of file diff --git a/lib/repos/task.repo.js b/lib/repos/task.repo.js new file mode 100644 index 0000000..a883bf0 --- /dev/null +++ b/lib/repos/task.repo.js @@ -0,0 +1,52 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const MockOrm_1 = __importDefault(require("./MockOrm")); +async function getTasksByBoardId(boardId) { + const db = await MockOrm_1.default.openDb(); + return db.tasks.filter((task) => task.boardId === boardId); +} +async function getTaskByBoardId(boardId, taskId) { + const db = await MockOrm_1.default.openDb(); + return db.tasks.find((task) => task.boardId === boardId && task.id === taskId) || null; +} +async function createTask(boardId, task) { + const db = await MockOrm_1.default.openDb(); + task.id = Date.now(); + task.boardId = boardId; + task.createdAt = new Date().toISOString(); + task.updatedAt = task.createdAt; + db.tasks.push(task); + await MockOrm_1.default.saveDb(db); + return task; +} +async function updateTask(boardId, taskId, taskData) { + const db = await MockOrm_1.default.openDb(); + const task = db.tasks.find((t) => t.boardId === boardId && t.id === taskId); + if (task) { + Object.assign(task, taskData, { updatedAt: new Date().toISOString() }); + await MockOrm_1.default.saveDb(db); + return task; + } + return null; +} +async function deleteTask(boardId, taskId) { + const db = await MockOrm_1.default.openDb(); + const idx = db.tasks.findIndex((t) => t.boardId === boardId && t.id === taskId); + if (idx !== -1) { + db.tasks.splice(idx, 1); + await MockOrm_1.default.saveDb(db); + return true; + } + return false; +} +exports.default = { + getTasksByBoardId, + getTaskByBoardId, + createTask, + updateTask, + deleteTask, +}; +//# sourceMappingURL=task.repo.js.map \ No newline at end of file diff --git a/lib/repos/task.repo.js.map b/lib/repos/task.repo.js.map new file mode 100644 index 0000000..8eb9207 --- /dev/null +++ b/lib/repos/task.repo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"task.repo.js","sourceRoot":"","sources":["../../src/repos/task.repo.ts"],"names":[],"mappings":";;;;;AACA,wDAA4B;AAE5B,KAAK,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAW,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;AACnE,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,OAAe,EAAE,MAAc;IAC9D,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAW,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC;AAC/F,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,IAAW;IACrD,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACvB,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAChC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACrB,OAAO,IAAI,CAAC;AACb,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,MAAc,EAAE,QAAwB;IAClF,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;IACnF,IAAI,IAAI,EAAE,CAAC;QACV,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACvE,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,MAAc;IACxD,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;IACvF,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QAChB,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACxB,MAAM,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,kBAAe;IACd,iBAAiB;IACjB,gBAAgB;IAChB,UAAU;IACV,UAAU;IACV,UAAU;CACV,CAAC"} \ No newline at end of file diff --git a/lib/repos/user.repo.js b/lib/repos/user.repo.js new file mode 100644 index 0000000..b3c84a8 --- /dev/null +++ b/lib/repos/user.repo.js @@ -0,0 +1,82 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const misc_1 = require("@src/util/misc"); +const MockOrm_1 = __importDefault(require("./MockOrm")); +// **** Functions **** // +/** + * Get one user. + */ +async function getOne(email) { + const db = await MockOrm_1.default.openDb(); + for (const user of db.users) { + if (user.email === email) { + return user; + } + } + return null; +} +/** + * See if a user with the given id exists. + */ +async function persists(id) { + const db = await MockOrm_1.default.openDb(); + for (const user of db.users) { + if (user.id === id) { + return true; + } + } + return false; +} +/** + * Get all users. + */ +async function getAll() { + const db = await MockOrm_1.default.openDb(); + return db.users; +} +/** + * Add one user. + */ +async function add(user) { + const db = await MockOrm_1.default.openDb(); + user.id = (0, misc_1.getRandomInt)(); + db.users.push(user); + return MockOrm_1.default.saveDb(db); +} +/** + * Update a user. + */ +async function update(user) { + const db = await MockOrm_1.default.openDb(); + for (let i = 0; i < db.users.length; i++) { + if (db.users[i].id === user.id) { + db.users[i] = user; + return MockOrm_1.default.saveDb(db); + } + } +} +/** + * Delete one user. + */ +async function delete_(id) { + const db = await MockOrm_1.default.openDb(); + for (let i = 0; i < db.users.length; i++) { + if (db.users[i].id === id) { + db.users.splice(i, 1); + return MockOrm_1.default.saveDb(db); + } + } +} +// **** Export default **** // +exports.default = { + getOne, + persists, + getAll, + add, + update, + delete: delete_, +}; +//# sourceMappingURL=user.repo.js.map \ No newline at end of file diff --git a/lib/repos/user.repo.js.map b/lib/repos/user.repo.js.map new file mode 100644 index 0000000..3621f77 --- /dev/null +++ b/lib/repos/user.repo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"user.repo.js","sourceRoot":"","sources":["../../src/repos/user.repo.ts"],"names":[],"mappings":";;;;;AACA,yCAA8C;AAC9C,wDAA4B;AAG5B,yBAAyB;AAEzB;;GAEG;AACH,KAAK,UAAU,MAAM,CAAC,KAAa;IACjC,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,QAAQ,CAAC,EAAU;IAChC,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,MAAM;IACnB,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,CAAC,KAAK,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,GAAG,CAAC,IAAW;IAC5B,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE,GAAG,IAAA,mBAAY,GAAE,CAAC;IACzB,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,OAAO,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,MAAM,CAAC,IAAW;IAC/B,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,EAAE,CAAC;YAC/B,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;YACnB,OAAO,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,OAAO,CAAC,EAAU;IAC/B,MAAM,EAAE,GAAG,MAAM,iBAAG,CAAC,MAAM,EAAE,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;YAC1B,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtB,OAAO,iBAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;AACH,CAAC;AAGD,8BAA8B;AAE9B,kBAAe;IACb,MAAM;IACN,QAAQ;IACR,MAAM;IACN,GAAG;IACH,MAAM;IACN,MAAM,EAAE,OAAO;CACP,CAAC"} \ No newline at end of file diff --git a/lib/routes/api.js b/lib/routes/api.js new file mode 100644 index 0000000..af997c7 --- /dev/null +++ b/lib/routes/api.js @@ -0,0 +1,24 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = require("express"); +const jet_validator_1 = __importDefault(require("jet-validator")); +const Paths_1 = __importDefault(require("./constants/Paths")); +const user_model_1 = __importDefault(require("@src/models/user.model")); +const user_controller_1 = __importDefault(require("@src/controllers/user.controller")); +// **** Variables **** // +const apiRouter = (0, express_1.Router)(), validate = (0, jet_validator_1.default)(); +// ** Add UserRouter ** // +const userRouter = (0, express_1.Router)(); +// Get all users +userRouter.get(Paths_1.default.Users.Get, user_controller_1.default.getAll.bind(user_controller_1.default)); +userRouter.post(Paths_1.default.Users.Add, validate(['user', user_model_1.default.isUser]), user_controller_1.default.add.bind(user_controller_1.default)); +userRouter.put(Paths_1.default.Users.Update, validate(['user', user_model_1.default.isUser]), user_controller_1.default.update.bind(user_controller_1.default)); +userRouter.delete(Paths_1.default.Users.Delete, validate(['id', 'number', 'params']), user_controller_1.default.delete.bind(user_controller_1.default)); +// Add UserRouter +apiRouter.use(Paths_1.default.Users.Base, userRouter); +// **** Export default **** // +exports.default = apiRouter; +//# sourceMappingURL=api.js.map \ No newline at end of file diff --git a/lib/routes/api.js.map b/lib/routes/api.js.map new file mode 100644 index 0000000..85f4d1c --- /dev/null +++ b/lib/routes/api.js.map @@ -0,0 +1 @@ +{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/routes/api.ts"],"names":[],"mappings":";;;;;AAAA,qCAAiC;AACjC,kEAAyC;AAEzC,8DAAsC;AACtC,wEAA0C;AAC1C,uFAA8D;AAG9D,yBAAyB;AAEzB,MAAM,SAAS,GAAG,IAAA,gBAAM,GAAE,EACxB,QAAQ,GAAG,IAAA,uBAAY,GAAE,CAAC;AAG5B,0BAA0B;AAE1B,MAAM,UAAU,GAAG,IAAA,gBAAM,GAAE,CAAC;AAE5B,gBAAgB;AAChB,UAAU,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,GAAG,EAAE,yBAAc,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAc,CAAC,CAAC,CAAC;AAC5E,UAAU,CAAC,IAAI,CACb,eAAK,CAAC,KAAK,CAAC,GAAG,EACf,QAAQ,CAAC,CAAC,MAAM,EAAE,oBAAI,CAAC,MAAM,CAAC,CAAC,EAC/B,yBAAc,CAAC,GAAG,CAAC,IAAI,CAAC,yBAAc,CAAC,CACxC,CAAC;AACF,UAAU,CAAC,GAAG,CACZ,eAAK,CAAC,KAAK,CAAC,MAAM,EAClB,QAAQ,CAAC,CAAC,MAAM,EAAE,oBAAI,CAAC,MAAM,CAAC,CAAC,EAC/B,yBAAc,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAc,CAAC,CAC3C,CAAC;AACF,UAAU,CAAC,MAAM,CACf,eAAK,CAAC,KAAK,CAAC,MAAM,EAClB,QAAQ,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,EACpC,yBAAc,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAc,CAAC,CAC3C,CAAC;AAEF,iBAAiB;AACjB,SAAS,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AAG5C,8BAA8B;AAE9B,kBAAe,SAAS,CAAC"} \ No newline at end of file diff --git a/lib/routes/board.route.js b/lib/routes/board.route.js new file mode 100644 index 0000000..fb27424 --- /dev/null +++ b/lib/routes/board.route.js @@ -0,0 +1,15 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = require("express"); +const board_controller_1 = __importDefault(require("../controllers/board.controller")); +const router = (0, express_1.Router)(); +router.get('/user/:userId', board_controller_1.default.getBoardsByUserId); +router.get('/user/:userId/:boardId', board_controller_1.default.getBoardByUserId); +router.post('/user/:userId', board_controller_1.default.createBoard); +router.put('/user/:userId/:boardId', board_controller_1.default.updateBoard); +router.delete('/user/:userId/:boardId', board_controller_1.default.deleteBoard); +exports.default = router; +//# sourceMappingURL=board.route.js.map \ No newline at end of file diff --git a/lib/routes/board.route.js.map b/lib/routes/board.route.js.map new file mode 100644 index 0000000..cb43a6c --- /dev/null +++ b/lib/routes/board.route.js.map @@ -0,0 +1 @@ +{"version":3,"file":"board.route.js","sourceRoot":"","sources":["../../src/routes/board.route.ts"],"names":[],"mappings":";;;;;AACA,qCAAiC;AACjC,uFAA8D;AAE9D,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,0BAAe,CAAC,iBAAiB,CAAC,CAAC;AAC/D,MAAM,CAAC,GAAG,CAAC,wBAAwB,EAAE,0BAAe,CAAC,gBAAgB,CAAC,CAAC;AACvE,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,0BAAe,CAAC,WAAW,CAAC,CAAC;AAC1D,MAAM,CAAC,GAAG,CAAC,wBAAwB,EAAE,0BAAe,CAAC,WAAW,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,CAAC,wBAAwB,EAAE,0BAAe,CAAC,WAAW,CAAC,CAAC;AAErE,kBAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/routes/constants/FullPaths.js b/lib/routes/constants/FullPaths.js new file mode 100644 index 0000000..3a4d54a --- /dev/null +++ b/lib/routes/constants/FullPaths.js @@ -0,0 +1,30 @@ +"use strict"; +/** + * Convert paths to full paths. + */ +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const Paths_1 = __importDefault(require("./Paths")); +/** + * The recursive function. + */ +function getFullPaths(parent, baseUrl) { + const url = (baseUrl + parent.Base), keys = Object.keys(parent), retVal = { Base: url }; + // Iterate keys + for (const key of keys) { + const pval = parent[key]; + if (key !== 'Base' && typeof pval === 'string') { + retVal[key] = (url + pval); + } + else if (typeof pval === 'object') { + retVal[key] = getFullPaths(pval, url); + } + } + // Return + return retVal; +} +// **** Export default **** // +exports.default = getFullPaths(Paths_1.default, ''); +//# sourceMappingURL=FullPaths.js.map \ No newline at end of file diff --git a/lib/routes/constants/FullPaths.js.map b/lib/routes/constants/FullPaths.js.map new file mode 100644 index 0000000..c56fa5c --- /dev/null +++ b/lib/routes/constants/FullPaths.js.map @@ -0,0 +1 @@ +{"version":3,"file":"FullPaths.js","sourceRoot":"","sources":["../../../src/routes/constants/FullPaths.ts"],"names":[],"mappings":";AACA;;GAEG;;;;;AAEH,oDAAwC;AAQxC;;GAEG;AACH,SAAS,YAAY,CACnB,MAAgB,EAChB,OAAe;IAEf,MAAM,GAAG,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,EACjC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAC1B,MAAM,GAAa,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IACnC,eAAe;IACf,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,GAAG,KAAK,MAAM,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC/C,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;QAC7B,CAAC;aAAM,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IACD,SAAS;IACT,OAAO,MAAM,CAAC;AAChB,CAAC;AAGD,8BAA8B;AAE9B,kBAAe,YAAY,CAAC,eAAK,EAAE,EAAE,CAAW,CAAC"} \ No newline at end of file diff --git a/lib/routes/constants/Paths.js b/lib/routes/constants/Paths.js new file mode 100644 index 0000000..2d3b5d4 --- /dev/null +++ b/lib/routes/constants/Paths.js @@ -0,0 +1,17 @@ +"use strict"; +/** + * Express router paths go here. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const Paths = { + Base: '/api', + Users: { + Base: '/users', + Get: '/all', + Add: '/add', + Update: '/update', + Delete: '/delete/:id', + }, +}; +exports.default = Paths; +//# sourceMappingURL=Paths.js.map \ No newline at end of file diff --git a/lib/routes/constants/Paths.js.map b/lib/routes/constants/Paths.js.map new file mode 100644 index 0000000..e0a24da --- /dev/null +++ b/lib/routes/constants/Paths.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Paths.js","sourceRoot":"","sources":["../../../src/routes/constants/Paths.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAKH,MAAM,KAAK,GAAG;IACZ,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE;QACL,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,MAAM;QACX,GAAG,EAAE,MAAM;QACX,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,aAAa;KACtB;CACF,CAAC;AAMF,kBAAe,KAAe,CAAC"} \ No newline at end of file diff --git a/lib/routes/task.route.js b/lib/routes/task.route.js new file mode 100644 index 0000000..6fbc8be --- /dev/null +++ b/lib/routes/task.route.js @@ -0,0 +1,15 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = require("express"); +const task_controller_1 = __importDefault(require("../controllers/task.controller")); +const router = (0, express_1.Router)(); +router.get('/board/:boardId', task_controller_1.default.getTasksByBoardId); +router.get('/board/:boardId/:taskId', task_controller_1.default.getTaskByBoardId); +router.post('/board/:boardId', task_controller_1.default.createTask); +router.put('/board/:boardId/:taskId', task_controller_1.default.updateTask); +router.delete('/board/:boardId/:taskId', task_controller_1.default.deleteTask); +exports.default = router; +//# sourceMappingURL=task.route.js.map \ No newline at end of file diff --git a/lib/routes/task.route.js.map b/lib/routes/task.route.js.map new file mode 100644 index 0000000..aade63b --- /dev/null +++ b/lib/routes/task.route.js.map @@ -0,0 +1 @@ +{"version":3,"file":"task.route.js","sourceRoot":"","sources":["../../src/routes/task.route.ts"],"names":[],"mappings":";;;;;AACA,qCAAiC;AACjC,qFAA4D;AAE5D,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,iBAAiB,EAAE,yBAAc,CAAC,iBAAiB,CAAC,CAAC;AAChE,MAAM,CAAC,GAAG,CAAC,yBAAyB,EAAE,yBAAc,CAAC,gBAAgB,CAAC,CAAC;AACvE,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,yBAAc,CAAC,UAAU,CAAC,CAAC;AAC1D,MAAM,CAAC,GAAG,CAAC,yBAAyB,EAAE,yBAAc,CAAC,UAAU,CAAC,CAAC;AACjE,MAAM,CAAC,MAAM,CAAC,yBAAyB,EAAE,yBAAc,CAAC,UAAU,CAAC,CAAC;AAEpE,kBAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/routes/types/express/misc.js b/lib/routes/types/express/misc.js new file mode 100644 index 0000000..5387908 --- /dev/null +++ b/lib/routes/types/express/misc.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=misc.js.map \ No newline at end of file diff --git a/lib/routes/types/express/misc.js.map b/lib/routes/types/express/misc.js.map new file mode 100644 index 0000000..e3a9914 --- /dev/null +++ b/lib/routes/types/express/misc.js.map @@ -0,0 +1 @@ +{"version":3,"file":"misc.js","sourceRoot":"","sources":["../../../../src/routes/types/express/misc.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/lib/routes/types/types.js b/lib/routes/types/types.js new file mode 100644 index 0000000..11e638d --- /dev/null +++ b/lib/routes/types/types.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/lib/routes/types/types.js.map b/lib/routes/types/types.js.map new file mode 100644 index 0000000..098515c --- /dev/null +++ b/lib/routes/types/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/routes/types/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/lib/routes/user.route.js b/lib/routes/user.route.js new file mode 100644 index 0000000..5d008d9 --- /dev/null +++ b/lib/routes/user.route.js @@ -0,0 +1,14 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = require("express"); +const user_controller_1 = __importDefault(require("../controllers/user.controller")); +const router = (0, express_1.Router)(); +router.get('/', user_controller_1.default.getAll); +router.post('/', user_controller_1.default.add); +router.put('/', user_controller_1.default.update); +router.delete('/:id', user_controller_1.default.delete); +exports.default = router; +//# sourceMappingURL=user.route.js.map \ No newline at end of file diff --git a/lib/routes/user.route.js.map b/lib/routes/user.route.js.map new file mode 100644 index 0000000..f962444 --- /dev/null +++ b/lib/routes/user.route.js.map @@ -0,0 +1 @@ +{"version":3,"file":"user.route.js","sourceRoot":"","sources":["../../src/routes/user.route.ts"],"names":[],"mappings":";;;;;AAAA,qCAAiC;AACjC,qFAA4D;AAE5D,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,yBAAc,CAAC,MAAM,CAAC,CAAC;AACvC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,yBAAc,CAAC,GAAG,CAAC,CAAC;AACrC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,yBAAc,CAAC,MAAM,CAAC,CAAC;AACvC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAc,CAAC,MAAM,CAAC,CAAC;AAE7C,kBAAe,MAAM,CAAC"} \ No newline at end of file diff --git a/lib/server.js b/lib/server.js new file mode 100644 index 0000000..b33bf63 --- /dev/null +++ b/lib/server.js @@ -0,0 +1,69 @@ +"use strict"; +/** + * Setup express server. + */ +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const cookie_parser_1 = __importDefault(require("cookie-parser")); +const morgan_1 = __importDefault(require("morgan")); +const path_1 = __importDefault(require("path")); +const helmet_1 = __importDefault(require("helmet")); +const express_1 = __importDefault(require("express")); +const jet_logger_1 = __importDefault(require("jet-logger")); +require("express-async-errors"); +const api_1 = __importDefault(require("@src/routes/api")); +const Paths_1 = __importDefault(require("@src/routes/constants/Paths")); +const EnvVars_1 = __importDefault(require("@src/constants/EnvVars")); +const HttpStatusCodes_1 = __importDefault(require("@src/constants/HttpStatusCodes")); +const misc_1 = require("@src/constants/misc"); +const classes_1 = require("@src/other/classes"); +// **** Variables **** // +const app = (0, express_1.default)(); +// **** Setup **** // +// Basic middleware +app.use(express_1.default.json()); +app.use(express_1.default.urlencoded({ extended: true })); +app.use((0, cookie_parser_1.default)(EnvVars_1.default.CookieProps.Secret)); +// Show routes called in console during development +if (EnvVars_1.default.NodeEnv === misc_1.NodeEnvs.Dev) { + app.use((0, morgan_1.default)('dev')); +} +// Security +if (EnvVars_1.default.NodeEnv === misc_1.NodeEnvs.Production) { + app.use((0, helmet_1.default)()); +} +// Add APIs, must be after middleware +app.use(Paths_1.default.Base, api_1.default); +// Add error handler +app.use((err, _, res, +// eslint-disable-next-line @typescript-eslint/no-unused-vars +next) => { + if (EnvVars_1.default.NodeEnv !== misc_1.NodeEnvs.Test) { + jet_logger_1.default.err(err, true); + } + let status = HttpStatusCodes_1.default.BAD_REQUEST; + if (err instanceof classes_1.RouteError) { + status = err.status; + } + return res.status(status).json({ error: err.message }); +}); +// ** Front-End Content ** // +// Set views directory (html) +const viewsDir = path_1.default.join(__dirname, 'views'); +app.set('views', viewsDir); +// Set static directory (js and css). +const staticDir = path_1.default.join(__dirname, 'public'); +app.use(express_1.default.static(staticDir)); +// Nav to users pg by default +app.get('/', (_, res) => { + return res.redirect('/users'); +}); +// Redirect to login if not logged in. +app.get('/users', (_, res) => { + return res.sendFile('users.html', { root: viewsDir }); +}); +// **** Export default **** // +exports.default = app; +//# sourceMappingURL=server.js.map \ No newline at end of file diff --git a/lib/server.js.map b/lib/server.js.map new file mode 100644 index 0000000..acfd2be --- /dev/null +++ b/lib/server.js.map @@ -0,0 +1 @@ +{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;AAEH,kEAAyC;AACzC,oDAA4B;AAC5B,gDAAwB;AACxB,oDAA4B;AAC5B,sDAAmE;AACnE,4DAAgC;AAEhC,gCAA8B;AAE9B,0DAAyC;AACzC,wEAAgD;AAEhD,qEAA6C;AAC7C,qFAA6D;AAE7D,8CAA+C;AAC/C,gDAAgD;AAGhD,yBAAyB;AAEzB,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;AAGtB,qBAAqB;AAErB,mBAAmB;AACnB,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AACxB,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,UAAU,CAAC,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC,CAAC,CAAC;AAC9C,GAAG,CAAC,GAAG,CAAC,IAAA,uBAAY,EAAC,iBAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;AAElD,mDAAmD;AACnD,IAAI,iBAAO,CAAC,OAAO,KAAK,eAAQ,CAAC,GAAG,EAAE,CAAC;IACrC,GAAG,CAAC,GAAG,CAAC,IAAA,gBAAM,EAAC,KAAK,CAAC,CAAC,CAAC;AACzB,CAAC;AAED,WAAW;AACX,IAAI,iBAAO,CAAC,OAAO,KAAK,eAAQ,CAAC,UAAU,EAAE,CAAC;IAC5C,GAAG,CAAC,GAAG,CAAC,IAAA,gBAAM,GAAE,CAAC,CAAC;AACpB,CAAC;AAED,qCAAqC;AACrC,GAAG,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,EAAE,aAAU,CAAC,CAAC;AAEhC,oBAAoB;AACpB,GAAG,CAAC,GAAG,CAAC,CACN,GAAU,EACV,CAAU,EACV,GAAa;AACb,6DAA6D;AAC7D,IAAkB,EAClB,EAAE;IACF,IAAI,iBAAO,CAAC,OAAO,KAAK,eAAQ,CAAC,IAAI,EAAE,CAAC;QACtC,oBAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IACD,IAAI,MAAM,GAAG,yBAAe,CAAC,WAAW,CAAC;IACzC,IAAI,GAAG,YAAY,oBAAU,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACtB,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;AACzD,CAAC,CAAC,CAAC;AAGH,6BAA6B;AAE7B,6BAA6B;AAC7B,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC/C,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAE3B,qCAAqC;AACrC,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AACjD,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;AAEnC,6BAA6B;AAC7B,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAU,EAAE,GAAa,EAAE,EAAE;IACzC,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC;AAEH,sCAAsC;AACtC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAU,EAAE,GAAa,EAAE,EAAE;IAC9C,OAAO,GAAG,CAAC,QAAQ,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC;AAGH,8BAA8B;AAE9B,kBAAe,GAAG,CAAC"} \ No newline at end of file diff --git a/lib/services/AuthService.js b/lib/services/AuthService.js new file mode 100644 index 0000000..033fab6 --- /dev/null +++ b/lib/services/AuthService.js @@ -0,0 +1,45 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Errors = void 0; +const user_repo_1 = __importDefault(require("@src/repos/user.repo")); +const PwdUtil_1 = __importDefault(require("@src/util/PwdUtil")); +const misc_1 = require("@src/util/misc"); +const HttpStatusCodes_1 = __importDefault(require("@src/constants/HttpStatusCodes")); +const classes_1 = require("@src/other/classes"); +// **** Variables **** // +// Errors +exports.Errors = { + Unauth: 'Unauthorized', + EmailNotFound(email) { + return `User with email "${email}" not found`; + }, +}; +// **** Functions **** // +/** + * Login a user. + */ +async function login(email, password) { + var _a; + // Fetch user + const user = await user_repo_1.default.getOne(email); + if (!user) { + throw new classes_1.RouteError(HttpStatusCodes_1.default.UNAUTHORIZED, exports.Errors.EmailNotFound(email)); + } + // Check password + const hash = ((_a = user.pwdHash) !== null && _a !== void 0 ? _a : ''), pwdPassed = await PwdUtil_1.default.compare(password, hash); + if (!pwdPassed) { + // If password failed, wait 500ms this will increase security + await (0, misc_1.tick)(500); + throw new classes_1.RouteError(HttpStatusCodes_1.default.UNAUTHORIZED, exports.Errors.Unauth); + } + // Return + return user; +} +// **** Export default **** // +exports.default = { + login, +}; +//# sourceMappingURL=AuthService.js.map \ No newline at end of file diff --git a/lib/services/AuthService.js.map b/lib/services/AuthService.js.map new file mode 100644 index 0000000..60c1e36 --- /dev/null +++ b/lib/services/AuthService.js.map @@ -0,0 +1 @@ +{"version":3,"file":"AuthService.js","sourceRoot":"","sources":["../../src/services/AuthService.ts"],"names":[],"mappings":";;;;;;AAAA,qEAA4C;AAE5C,gEAAwC;AACxC,yCAAsC;AAEtC,qFAA6D;AAC7D,gDAAgD;AAIhD,yBAAyB;AAEzB,SAAS;AACI,QAAA,MAAM,GAAG;IACpB,MAAM,EAAE,cAAc;IACtB,aAAa,CAAC,KAAa;QACzB,OAAO,oBAAoB,KAAK,aAAa,CAAC;IAChD,CAAC;CACO,CAAC;AAGX,yBAAyB;AAEzB;;GAEG;AACH,KAAK,UAAU,KAAK,CAAC,KAAa,EAAE,QAAgB;;IAClD,aAAa;IACb,MAAM,IAAI,GAAG,MAAM,mBAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,oBAAU,CAClB,yBAAe,CAAC,YAAY,EAC5B,cAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAC5B,CAAC;IACJ,CAAC;IACD,iBAAiB;IACjB,MAAM,IAAI,GAAG,CAAC,MAAA,IAAI,CAAC,OAAO,mCAAI,EAAE,CAAC,EAC/B,SAAS,GAAG,MAAM,iBAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,6DAA6D;QAC7D,MAAM,IAAA,WAAI,EAAC,GAAG,CAAC,CAAC;QAChB,MAAM,IAAI,oBAAU,CAClB,yBAAe,CAAC,YAAY,EAC5B,cAAM,CAAC,MAAM,CACd,CAAC;IACJ,CAAC;IACD,SAAS;IACT,OAAO,IAAI,CAAC;AACd,CAAC;AAGD,8BAA8B;AAE9B,kBAAe;IACb,KAAK;CACG,CAAC"} \ No newline at end of file diff --git a/lib/services/UserService.js b/lib/services/UserService.js new file mode 100644 index 0000000..221771b --- /dev/null +++ b/lib/services/UserService.js @@ -0,0 +1,54 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.USER_NOT_FOUND_ERR = void 0; +const user_repo_1 = __importDefault(require("@src/repos/user.repo")); +const classes_1 = require("@src/other/classes"); +const HttpStatusCodes_1 = __importDefault(require("@src/constants/HttpStatusCodes")); +// **** Variables **** // +exports.USER_NOT_FOUND_ERR = 'User not found'; +// **** Functions **** // +/** + * Get all users. + */ +function getAll() { + return user_repo_1.default.getAll(); +} +/** + * Add one user. + */ +function addOne(user) { + return user_repo_1.default.add(user); +} +/** + * Update one user. + */ +async function updateOne(user) { + const persists = await user_repo_1.default.persists(user.id); + if (!persists) { + throw new classes_1.RouteError(HttpStatusCodes_1.default.NOT_FOUND, exports.USER_NOT_FOUND_ERR); + } + // Return user + return user_repo_1.default.update(user); +} +/** + * Delete a user by their id. + */ +async function _delete(id) { + const persists = await user_repo_1.default.persists(id); + if (!persists) { + throw new classes_1.RouteError(HttpStatusCodes_1.default.NOT_FOUND, exports.USER_NOT_FOUND_ERR); + } + // Delete user + return user_repo_1.default.delete(id); +} +// **** Export default **** // +exports.default = { + getAll, + addOne, + updateOne, + delete: _delete, +}; +//# sourceMappingURL=UserService.js.map \ No newline at end of file diff --git a/lib/services/UserService.js.map b/lib/services/UserService.js.map new file mode 100644 index 0000000..16e4bde --- /dev/null +++ b/lib/services/UserService.js.map @@ -0,0 +1 @@ +{"version":3,"file":"UserService.js","sourceRoot":"","sources":["../../src/services/UserService.ts"],"names":[],"mappings":";;;;;;AAAA,qEAA4C;AAE5C,gDAAgD;AAChD,qFAA6D;AAG7D,yBAAyB;AAEZ,QAAA,kBAAkB,GAAG,gBAAgB,CAAC;AAGnD,yBAAyB;AAEzB;;GAEG;AACH,SAAS,MAAM;IACb,OAAO,mBAAQ,CAAC,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,SAAS,MAAM,CAAC,IAAW;IACzB,OAAO,mBAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,SAAS,CAAC,IAAW;IAClC,MAAM,QAAQ,GAAG,MAAM,mBAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,oBAAU,CAClB,yBAAe,CAAC,SAAS,EACzB,0BAAkB,CACnB,CAAC;IACJ,CAAC;IACD,cAAc;IACd,OAAO,mBAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,OAAO,CAAC,EAAU;IAC/B,MAAM,QAAQ,GAAG,MAAM,mBAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,oBAAU,CAClB,yBAAe,CAAC,SAAS,EACzB,0BAAkB,CACnB,CAAC;IACJ,CAAC;IACD,cAAc;IACd,OAAO,mBAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAC7B,CAAC;AAGD,8BAA8B;AAE9B,kBAAe;IACb,MAAM;IACN,MAAM;IACN,SAAS;IACT,MAAM,EAAE,OAAO;CACP,CAAC"} \ No newline at end of file diff --git a/lib/util/PwdUtil.js b/lib/util/PwdUtil.js new file mode 100644 index 0000000..3fff3be --- /dev/null +++ b/lib/util/PwdUtil.js @@ -0,0 +1,34 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const bcrypt_1 = __importDefault(require("bcrypt")); +// **** Variables **** // +const SALT_ROUNDS = 12; +// **** Functions **** // +/** + * Get a hash from the password. + */ +function getHash(pwd) { + return bcrypt_1.default.hash(pwd, SALT_ROUNDS); +} +/** + * Useful for testing. + */ +function hashSync(pwd) { + return bcrypt_1.default.hashSync(pwd, SALT_ROUNDS); +} +/** + * See if a password passes the hash. + */ +function compare(pwd, hash) { + return bcrypt_1.default.compare(pwd, hash); +} +// **** Export Default **** // +exports.default = { + getHash, + hashSync, + compare, +}; +//# sourceMappingURL=PwdUtil.js.map \ No newline at end of file diff --git a/lib/util/PwdUtil.js.map b/lib/util/PwdUtil.js.map new file mode 100644 index 0000000..6cb93f8 --- /dev/null +++ b/lib/util/PwdUtil.js.map @@ -0,0 +1 @@ +{"version":3,"file":"PwdUtil.js","sourceRoot":"","sources":["../../src/util/PwdUtil.ts"],"names":[],"mappings":";;;;;AAAA,oDAA4B;AAG5B,yBAAyB;AAEzB,MAAM,WAAW,GAAG,EAAE,CAAC;AAGvB,yBAAyB;AAEzB;;GAEG;AACH,SAAS,OAAO,CAAC,GAAW;IAC1B,OAAO,gBAAM,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,SAAS,QAAQ,CAAC,GAAW;IAC3B,OAAO,gBAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,SAAS,OAAO,CAAC,GAAW,EAAE,IAAY;IACxC,OAAO,gBAAM,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACnC,CAAC;AAGD,8BAA8B;AAE9B,kBAAe;IACb,OAAO;IACP,QAAQ;IACR,OAAO;CACC,CAAC"} \ No newline at end of file diff --git a/lib/util/SessionUtil.js b/lib/util/SessionUtil.js new file mode 100644 index 0000000..56ec8c0 --- /dev/null +++ b/lib/util/SessionUtil.js @@ -0,0 +1,74 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const HttpStatusCodes_1 = __importDefault(require("@src/constants/HttpStatusCodes")); +const classes_1 = require("@src/other/classes"); +const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); +const EnvVars_1 = __importDefault(require("../constants/EnvVars")); +// **** Variables **** // +// Errors +const Errors = { + ParamFalsey: 'Param is falsey', + Validation: 'JSON-web-token validation failed.', +}; +// Options +const Options = { + expiresIn: EnvVars_1.default.Jwt.Exp, +}; +// **** Functions **** // +/** + * Get session data from request object (i.e. ISessionUser) + */ +function getSessionData(req) { + const { Key } = EnvVars_1.default.CookieProps, jwt = req.signedCookies[Key]; + return _decode(jwt); +} +/** + * Add a JWT to the response + */ +async function addSessionData(res, data) { + if (!res || !data) { + throw new classes_1.RouteError(HttpStatusCodes_1.default.BAD_REQUEST, Errors.ParamFalsey); + } + // Setup JWT + const jwt = await _sign(data), { Key, Options } = EnvVars_1.default.CookieProps; + // Return + return res.cookie(Key, jwt, Options); +} +/** + * Remove cookie + */ +function clearCookie(res) { + const { Key, Options } = EnvVars_1.default.CookieProps; + return res.clearCookie(Key, Options); +} +// **** Helper Functions **** // +/** + * Encrypt data and return jwt. + */ +function _sign(data) { + return new Promise((res, rej) => { + jsonwebtoken_1.default.sign(data, EnvVars_1.default.Jwt.Secret, { expiresIn: '1h' }, (err, token) => { + return err ? rej(err) : res(token || ''); + }); + }); +} +/** + * Decrypt JWT and extract client data. + */ +function _decode(jwt) { + return new Promise((res, rej) => { + jsonwebtoken_1.default.verify(jwt, EnvVars_1.default.Jwt.Secret, undefined, (err, decoded) => { + return err ? rej(Errors.Validation) : res(decoded); + }); + }); +} +// **** Export default **** // +exports.default = { + addSessionData, + getSessionData, + clearCookie, +}; +//# sourceMappingURL=SessionUtil.js.map \ No newline at end of file diff --git a/lib/util/SessionUtil.js.map b/lib/util/SessionUtil.js.map new file mode 100644 index 0000000..d8551e0 --- /dev/null +++ b/lib/util/SessionUtil.js.map @@ -0,0 +1 @@ +{"version":3,"file":"SessionUtil.js","sourceRoot":"","sources":["../../src/util/SessionUtil.ts"],"names":[],"mappings":";;;;;AAEA,qFAA6D;AAC7D,gDAAgD;AAChD,gEAAwC;AAExC,mEAA2C;AAG3C,yBAAyB;AAEzB,SAAS;AACT,MAAM,MAAM,GAAG;IACb,WAAW,EAAE,iBAAiB;IAC9B,UAAU,EAAE,mCAAmC;CACvC,CAAC;AAEX,UAAU;AACV,MAAM,OAAO,GAAG;IACd,SAAS,EAAE,iBAAO,CAAC,GAAG,CAAC,GAAG;CAC3B,CAAC;AAGF,yBAAyB;AAEzB;;GAEG;AACH,SAAS,cAAc,CAAI,GAAY;IACrC,MAAM,EAAE,GAAG,EAAE,GAAG,iBAAO,CAAC,WAAW,EACjC,GAAG,GAAG,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,cAAc,CAC3B,GAAa,EACb,IAAqB;IAErB,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,oBAAU,CAAC,yBAAe,CAAC,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;IACxE,CAAC;IACD,YAAY;IACZ,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,EAC3B,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,iBAAO,CAAC,WAAW,CAAC;IACzC,SAAS;IACT,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,GAAa;IAChC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,iBAAO,CAAC,WAAW,CAAC;IAC7C,OAAO,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC;AAGD,gCAAgC;AAEhC;;GAEG;AACH,SAAS,KAAK,CAAC,IAA8B;IAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9B,sBAAY,CAAC,IAAI,CACf,IAAI,EACJ,iBAAO,CAAC,GAAG,CAAC,MAAM,EAClB,EAAE,SAAS,EAAE,IAAI,EAAE,EACnB,CAAC,GAAiB,EAAE,KAAc,EAAE,EAAE;YACpC,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,OAAO,CAAI,GAAW;IAC7B,OAAO,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9B,sBAAY,CAAC,MAAM,CACjB,GAAG,EACH,iBAAO,CAAC,GAAG,CAAC,MAAM,EAClB,SAAS,EACT,CAAC,GAAiB,EAAE,OAA0C,EAAE,EAAE;YAChE,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAY,CAAC,CAAC;QAC1D,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAGD,8BAA8B;AAE9B,kBAAe;IACb,cAAc;IACd,cAAc;IACd,WAAW;CACH,CAAC"} \ No newline at end of file diff --git a/lib/util/misc.js b/lib/util/misc.js new file mode 100644 index 0000000..a5b0f49 --- /dev/null +++ b/lib/util/misc.js @@ -0,0 +1,24 @@ +"use strict"; +/** + * Miscellaneous shared functions go here. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getRandomInt = getRandomInt; +exports.tick = tick; +/** + * Get a random number between 1 and 1,000,000,000,000 + */ +function getRandomInt() { + return Math.floor(Math.random() * 1000000000000); +} +/** + * Wait for a certain number of milliseconds. + */ +function tick(milliseconds) { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, milliseconds); + }); +} +//# sourceMappingURL=misc.js.map \ No newline at end of file diff --git a/lib/util/misc.js.map b/lib/util/misc.js.map new file mode 100644 index 0000000..72c52e0 --- /dev/null +++ b/lib/util/misc.js.map @@ -0,0 +1 @@ +{"version":3,"file":"misc.js","sourceRoot":"","sources":["../../src/util/misc.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAMH,oCAEC;AAKD,oBAMC;AAhBD;;GAEG;AACH,SAAgB,YAAY;IAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,aAAiB,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,SAAgB,IAAI,CAAC,YAAoB;IACvC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,UAAU,CAAC,GAAG,EAAE;YACd,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,YAAY,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1629e86..5b44246 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,33 +1,39 @@ { - "name": "Seer", + "name": "ara-kanban-service", "version": "0.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "Seer", + "name": "ara-kanban-service", "version": "0.0.0", "dependencies": { + "@prisma/client": "^6.16.2", + "bcrypt": "^6.0.0", "cookie-parser": "^1.4.6", - "dotenv": "^16.3.1", + "dotenv": "^16.6.1", "express": "^4.18.2", "express-async-errors": "^3.1.1", - "helmet": "^7.0.0", + "helmet": "^7.2.0", "inserturlparams": "^1.0.1", "jet-logger": "^1.3.1", "jet-validator": "^1.1.1", "jsonfile": "^6.1.0", + "jsonwebtoken": "^9.0.2", "module-alias": "^2.2.3", "morgan": "^1.10.0", + "prisma": "^6.16.2", "ts-command-line-args": "^2.5.1" }, "devDependencies": { + "@types/bcrypt": "^6.0.0", "@types/cookie-parser": "^1.4.3", "@types/express": "^4.17.17", "@types/find": "^0.2.1", "@types/fs-extra": "^11.0.1", "@types/jasmine": "^4.3.5", "@types/jsonfile": "^6.1.1", + "@types/jsonwebtoken": "^9.0.10", "@types/morgan": "^1.9.4", "@types/node": "^20.4.2", "@types/supertest": "^2.0.12", @@ -42,7 +48,7 @@ "supertest": "^6.3.3", "ts-node": "^10.9.1", "tsconfig-paths": "^4.2.0", - "typescript": "^5.1.6" + "typescript": "^5.9.2" }, "engines": { "node": ">=8.10.0" @@ -318,6 +324,91 @@ "node": ">=14" } }, + "node_modules/@prisma/client": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.16.2.tgz", + "integrity": "sha512-E00PxBcalMfYO/TWnXobBVUai6eW/g5OsifWQsQDzJYm7yaY+IRLo7ZLsaefi0QkTpxfuhFcQ/w180i6kX3iJw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.16.2.tgz", + "integrity": "sha512-mKXSUrcqXj0LXWPmJsK2s3p9PN+aoAbyMx7m5E1v1FufofR1ZpPoIArjjzOIm+bJRLLvYftoNYLx1tbHgF9/yg==", + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.16.2.tgz", + "integrity": "sha512-bo4/gA/HVV6u8YK2uY6glhNsJ7r+k/i5iQ9ny/3q5bt9ijCj7WMPUwfTKPvtEgLP+/r26Z686ly11hhcLiQ8zA==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.16.2.tgz", + "integrity": "sha512-7yf3AjfPUgsg/l7JSu1iEhsmZZ/YE00yURPjTikqm2z4btM0bCl2coFtTGfeSOWbQMmq45Jab+53yGUIAT1sjA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.16.2", + "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "@prisma/fetch-engine": "6.16.2", + "@prisma/get-platform": "6.16.2" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43.tgz", + "integrity": "sha512-ThvlDaKIVrnrv97ujNFDYiQbeMQpLa0O86HFA2mNoip4mtFqM7U5GSz2ie1i2xByZtvPztJlNRgPsXGeM/kqAA==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.16.2.tgz", + "integrity": "sha512-wPnZ8DMRqpgzye758ZvfAMiNJRuYpz+rhgEBZi60ZqDIgOU2694oJxiuu3GKFeYeR/hXxso4/2oBC243t/whxQ==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.16.2", + "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "@prisma/get-platform": "6.16.2" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.16.2.tgz", + "integrity": "sha512-U/P36Uke5wS7r1+omtAgJpEB94tlT4SdlgaeTc6HVTTT93pXj7zZ+B/cZnmnvjcNPfWddgoDx8RLjmQwqGDYyA==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.16.2" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT" + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -342,6 +433,16 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, + "node_modules/@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -443,6 +544,17 @@ "@types/node": "*" } }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -458,6 +570,13 @@ "@types/node": "*" } }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.4.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz", @@ -974,6 +1093,20 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1028,6 +1161,12 @@ "node": ">=8" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -1036,6 +1175,62 @@ "node": ">= 0.8" } }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/c12/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -1111,6 +1306,15 @@ "node": ">= 6" } }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1259,6 +1463,21 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -1351,6 +1570,21 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1368,6 +1602,12 @@ "node": ">= 0.8" } }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -1421,14 +1661,15 @@ } }, "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" + "url": "https://dotenvx.com" } }, "node_modules/eastasianwidth": { @@ -1437,17 +1678,45 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1824,6 +2093,34 @@ "node": ">= 0.6" } }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2095,6 +2392,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, "node_modules/glob": { "version": "10.3.3", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz", @@ -2248,9 +2562,10 @@ } }, "node_modules/helmet": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.0.0.tgz", - "integrity": "sha512-MsIgYmdBh460ZZ8cJC81q4XJknjG567wzEmv46WOBblDb6TUd3z8/GhgmsM9pn8g2B80tAJ4m5/d3Bi1KrSUBQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz", + "integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==", + "license": "MIT", "engines": { "node": ">=16.0.0" } @@ -2477,6 +2792,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/jet-logger/-/jet-logger-1.3.1.tgz", "integrity": "sha512-BSsTm88Y7a+XtXKpZM71qm0ulH+bNI13rR+BzeQStfjpE/6n3fX3FZpKF/WZh52h1e6gEAOjuFlkmdzGBQnwPg==", + "license": "MIT", "dependencies": { "colors": "1.3.0" } @@ -2485,10 +2801,21 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/jet-validator/-/jet-validator-1.1.1.tgz", "integrity": "sha512-F/L+UtXAkd5Dm+eIRca0BgCb5/sYenHqixHOt2tWYkMFd8AUDqA6U8dD3mQzXL+SVxCVOd5Ftcf9c9HGbUIhlw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", "dependencies": { "express": "^4.18.2" } }, + "node_modules/jiti": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.0.tgz", + "integrity": "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2536,6 +2863,55 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2569,12 +2945,54 @@ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/lru-cache": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.0.tgz", @@ -2749,6 +3167,32 @@ "node": ">= 0.6" } }, + "node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/nodemon": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", @@ -2837,6 +3281,25 @@ "node": ">=0.10.0" } }, + "node_modules/nypm": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -2845,6 +3308,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -3003,6 +3472,18 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -3015,6 +3496,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -3024,6 +3516,31 @@ "node": ">= 0.8.0" } }, + "node_modules/prisma": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.16.2.tgz", + "integrity": "sha512-aRvldGE5UUJTtVmFiH3WfNFNiqFlAtePUxcI0UEGlnXCX7DqhiMT5TRYwncHFeA/Reca5W6ToXXyCMTeFPdSXA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.16.2", + "@prisma/engines": "6.16.2" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -3051,6 +3568,22 @@ "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -3107,6 +3640,16 @@ "node": ">= 0.8" } }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -3261,7 +3804,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -3276,7 +3818,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -3650,6 +4191,12 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3704,6 +4251,7 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", + "license": "ISC", "dependencies": { "chalk": "^4.1.0", "command-line-args": "^5.1.1", @@ -3808,10 +4356,11 @@ } }, "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", - "dev": true, + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "devOptional": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4019,8 +4568,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yn": { "version": "3.1.1", @@ -4241,6 +4789,67 @@ "dev": true, "optional": true }, + "@prisma/client": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.16.2.tgz", + "integrity": "sha512-E00PxBcalMfYO/TWnXobBVUai6eW/g5OsifWQsQDzJYm7yaY+IRLo7ZLsaefi0QkTpxfuhFcQ/w180i6kX3iJw==", + "requires": {} + }, + "@prisma/config": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.16.2.tgz", + "integrity": "sha512-mKXSUrcqXj0LXWPmJsK2s3p9PN+aoAbyMx7m5E1v1FufofR1ZpPoIArjjzOIm+bJRLLvYftoNYLx1tbHgF9/yg==", + "requires": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.16.12", + "empathic": "2.0.0" + } + }, + "@prisma/debug": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.16.2.tgz", + "integrity": "sha512-bo4/gA/HVV6u8YK2uY6glhNsJ7r+k/i5iQ9ny/3q5bt9ijCj7WMPUwfTKPvtEgLP+/r26Z686ly11hhcLiQ8zA==" + }, + "@prisma/engines": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.16.2.tgz", + "integrity": "sha512-7yf3AjfPUgsg/l7JSu1iEhsmZZ/YE00yURPjTikqm2z4btM0bCl2coFtTGfeSOWbQMmq45Jab+53yGUIAT1sjA==", + "requires": { + "@prisma/debug": "6.16.2", + "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "@prisma/fetch-engine": "6.16.2", + "@prisma/get-platform": "6.16.2" + } + }, + "@prisma/engines-version": { + "version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43.tgz", + "integrity": "sha512-ThvlDaKIVrnrv97ujNFDYiQbeMQpLa0O86HFA2mNoip4mtFqM7U5GSz2ie1i2xByZtvPztJlNRgPsXGeM/kqAA==" + }, + "@prisma/fetch-engine": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.16.2.tgz", + "integrity": "sha512-wPnZ8DMRqpgzye758ZvfAMiNJRuYpz+rhgEBZi60ZqDIgOU2694oJxiuu3GKFeYeR/hXxso4/2oBC243t/whxQ==", + "requires": { + "@prisma/debug": "6.16.2", + "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", + "@prisma/get-platform": "6.16.2" + } + }, + "@prisma/get-platform": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.16.2.tgz", + "integrity": "sha512-U/P36Uke5wS7r1+omtAgJpEB94tlT4SdlgaeTc6HVTTT93pXj7zZ+B/cZnmnvjcNPfWddgoDx8RLjmQwqGDYyA==", + "requires": { + "@prisma/debug": "6.16.2" + } + }, + "@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==" + }, "@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -4265,6 +4874,15 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, + "@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -4366,6 +4984,16 @@ "@types/node": "*" } }, + "@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "dev": true, + "requires": { + "@types/ms": "*", + "@types/node": "*" + } + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -4381,6 +5009,12 @@ "@types/node": "*" } }, + "@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true + }, "@types/node": { "version": "20.4.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz", @@ -4747,6 +5381,15 @@ } } }, + "bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "requires": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + } + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -4791,11 +5434,50 @@ "fill-range": "^7.0.1" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, + "c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "requires": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "dependencies": { + "chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "requires": { + "readdirp": "^4.0.1" + } + }, + "readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==" + } + } + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -4847,6 +5529,14 @@ } } }, + "citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "requires": { + "consola": "^3.2.3" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4964,6 +5654,16 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==" + }, + "consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==" + }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -5038,6 +5738,16 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==" + }, + "defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==" + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -5049,6 +5759,11 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, + "destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==" + }, "destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -5089,9 +5804,9 @@ } }, "dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==" }, "eastasianwidth": { "version": "0.2.0", @@ -5099,17 +5814,39 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "effect": { + "version": "3.16.12", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz", + "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==", + "requires": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -5389,6 +6126,19 @@ "integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==", "requires": {} }, + "exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==" + }, + "fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "requires": { + "pure-rand": "^6.1.0" + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5604,6 +6354,19 @@ "has-symbols": "^1.0.3" } }, + "giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "requires": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + } + }, "glob": { "version": "10.3.3", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz", @@ -5711,9 +6474,9 @@ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, "helmet": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.0.0.tgz", - "integrity": "sha512-MsIgYmdBh460ZZ8cJC81q4XJknjG567wzEmv46WOBblDb6TUd3z8/GhgmsM9pn8g2B80tAJ4m5/d3Bi1KrSUBQ==" + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz", + "integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==" }, "hexoid": { "version": "1.0.0", @@ -5893,6 +6656,11 @@ "express": "^4.18.2" } }, + "jiti": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.0.tgz", + "integrity": "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==" + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -5929,6 +6697,49 @@ "universalify": "^2.0.0" } }, + "jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "requires": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5953,12 +6764,47 @@ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "lru-cache": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.0.tgz", @@ -6090,6 +6936,21 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, + "node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==" + }, + "node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==" + }, + "node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==" + }, "nodemon": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", @@ -6155,11 +7016,28 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "nypm": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "requires": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "tinyexec": "^1.0.1" + } + }, "object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" }, + "ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==" + }, "on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -6273,18 +7151,47 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" + }, + "perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==" + }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, + "pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "requires": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prisma": { + "version": "6.16.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.16.2.tgz", + "integrity": "sha512-aRvldGE5UUJTtVmFiH3WfNFNiqFlAtePUxcI0UEGlnXCX7DqhiMT5TRYwncHFeA/Reca5W6ToXXyCMTeFPdSXA==", + "requires": { + "@prisma/config": "6.16.2", + "@prisma/engines": "6.16.2" + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -6306,6 +7213,11 @@ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true }, + "pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==" + }, "qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", @@ -6336,6 +7248,15 @@ "unpipe": "1.0.0" } }, + "rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "requires": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -6427,7 +7348,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "requires": { "lru-cache": "^6.0.0" }, @@ -6436,7 +7356,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -6713,6 +7632,11 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==" + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6817,10 +7741,10 @@ } }, "typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", - "dev": true + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "devOptional": true }, "typical": { "version": "4.0.0", @@ -6966,8 +7890,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yn": { "version": "3.1.1", diff --git a/package.json b/package.json index 7ff1d6c..78bd2c8 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { - "name": "Seer", + "name": "ara-kanban-service", "version": "0.0.0", "scripts": { "build": "npx ts-node build.ts", "lint": "npx eslint --ext .ts src/", "lint:tests": "npx eslint --ext .ts spec/", "start": "node -r module-alias/register ./dist --env=production", - "dev": "nodemon", + "dev": "PORT=5000 nodemon", "test": "nodemon --config ./spec/nodemon.json", "test:no-reloading": "npx ts-node --files -r tsconfig-paths/register ./spec" }, @@ -27,26 +27,32 @@ "node": ">=8.10.0" }, "dependencies": { + "@prisma/client": "^6.16.2", + "bcrypt": "^6.0.0", "cookie-parser": "^1.4.6", - "dotenv": "^16.3.1", + "dotenv": "^16.6.1", "express": "^4.18.2", "express-async-errors": "^3.1.1", - "helmet": "^7.0.0", + "helmet": "^7.2.0", "inserturlparams": "^1.0.1", "jet-logger": "^1.3.1", "jet-validator": "^1.1.1", "jsonfile": "^6.1.0", + "jsonwebtoken": "^9.0.2", "module-alias": "^2.2.3", "morgan": "^1.10.0", + "prisma": "^6.16.2", "ts-command-line-args": "^2.5.1" }, "devDependencies": { + "@types/bcrypt": "^6.0.0", "@types/cookie-parser": "^1.4.3", "@types/express": "^4.17.17", "@types/find": "^0.2.1", "@types/fs-extra": "^11.0.1", "@types/jasmine": "^4.3.5", "@types/jsonfile": "^6.1.1", + "@types/jsonwebtoken": "^9.0.10", "@types/morgan": "^1.9.4", "@types/node": "^20.4.2", "@types/supertest": "^2.0.12", @@ -61,6 +67,6 @@ "supertest": "^6.3.3", "ts-node": "^10.9.1", "tsconfig-paths": "^4.2.0", - "typescript": "^5.1.6" + "typescript": "^5.9.2" } } diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..e8b9fe9 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,15 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" + output = "../generated/prisma" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} diff --git a/spec/tests/users.spec.ts b/spec/tests/users.spec.ts index 3b7669a..f0dc2bf 100644 --- a/spec/tests/users.spec.ts +++ b/spec/tests/users.spec.ts @@ -4,8 +4,8 @@ import insertUrlParams from 'inserturlparams'; import app from '@src/server'; -import UserRepo from '@src/repos/UserRepo'; -import User from '@src/models/User'; +import UserRepo from '@src/repos/user.repo'; +import User from '@src/models/user.model'; import HttpStatusCodes from '@src/constants/HttpStatusCodes'; import { USER_NOT_FOUND_ERR } from '@src/services/UserService'; import FullPaths from '@src/routes/constants/FullPaths'; diff --git a/spec/types/supertest/index.d.ts b/spec/types/supertest/index.d.ts index 9603fcc..18fbc28 100644 --- a/spec/types/supertest/index.d.ts +++ b/spec/types/supertest/index.d.ts @@ -1,4 +1,4 @@ -import { IUser } from '@src/models/User'; +import { IUser } from '@src/models/user.model'; import 'supertest'; diff --git a/src/constants/EnvVars.ts b/src/constants/EnvVars.ts index 6e3740a..9e7a1cb 100644 --- a/src/constants/EnvVars.ts +++ b/src/constants/EnvVars.ts @@ -2,11 +2,13 @@ * Environments variables declared here. */ +import { NodeEnvs } from './misc'; + /* eslint-disable node/no-process-env */ export default { - NodeEnv: (process.env.NODE_ENV ?? ''), + NodeEnv: (process.env.NODE_ENV as NodeEnvs ?? ''), Port: (process.env.PORT ?? 0), CookieProps: { Key: 'ExpressGeneratorTs', @@ -23,6 +25,6 @@ export default { }, Jwt: { Secret: (process.env.JWT_SECRET ?? ''), - Exp: (process.env.COOKIE_EXP ?? ''), // exp at the same time as the cookie + Exp: (process.env.COOKIE_EXP && process.env.COOKIE_EXP !== '' ? process.env.COOKIE_EXP : '1h'), // exp at the same time as the cookie }, } as const; diff --git a/src/controllers/board.controller.ts b/src/controllers/board.controller.ts new file mode 100644 index 0000000..1edb1d3 --- /dev/null +++ b/src/controllers/board.controller.ts @@ -0,0 +1,93 @@ +import { Request, Response } from 'express'; +import BoardRepo from '@src/repos/board.repo'; +import { IBoard } from '@src/models/board.model'; + +class BoardController { + // Get all boards for a user + public getBoardsByUserId = async (req: Request, res: Response) => { + try { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const userId = +req.params.userId; + const boards = await BoardRepo.getBoardsByUserId(userId); + return res.json({ boards }); + } catch (err) { + return res.status(500).json({ error: 'Internal server error', + details: String(err) }); + } + }; + + // Get single board by userId and boardId + public getBoardByUserId = async (req: Request, res: Response) => { + try { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const userId = +req.params.userId; + const boardId = +req.params.boardId; + const board = await BoardRepo.getBoardByUserId(userId, boardId); + return res.json({ board }); + } catch (err) { + return res.status(500).json({ error: 'Internal server error', + details: String(err) }); + } + }; + + // Create board for a user + public createBoard = async (req: Request, res: Response) => { + try { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const boardData = req.body as IBoard; + if (!boardData.name) { + return res.status(400).json({ error: 'Board name required' }); + } + const userId = +req.params.userId; + const board = await BoardRepo.createBoard(userId, boardData); + return res.status(201).json({ board }); + } catch (err) { + return res.status(500).json({ error: 'Internal server error', + details: String(err) }); + } + }; + + // Update board for a user + public updateBoard = async (req: Request, res: Response) => { + try { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const boardData = req.body as IBoard; + if (!boardData.name) { + return res.status(400).json({ error: 'Board name required' }); + } + const userId = +req.params.userId; + const boardId = +req.params.boardId; + const board = await BoardRepo.updateBoard(userId, boardId, boardData); + return res.json({ board }); + } catch (err) { + return res.status(500).json({ error: 'Internal server error', + details: String(err) }); + } + }; + + // Delete board for a user + public deleteBoard = async (req: Request, res: Response) => { + try { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const userId = +req.params.userId; + const boardId = +req.params.boardId; + await BoardRepo.deleteBoard(userId, boardId); + return res.status(204).end(); + } catch (err) { + return res.status(500).json({ error: 'Internal server error', + details: String(err) }); + } + }; +} + +export default new BoardController(); diff --git a/src/controllers/task.controller.ts b/src/controllers/task.controller.ts new file mode 100644 index 0000000..41d25c0 --- /dev/null +++ b/src/controllers/task.controller.ts @@ -0,0 +1,95 @@ +import { Request, Response } from 'express'; +import TaskRepo from '@src/repos/task.repo'; +import { ITask } from '@src/models/task.model'; + +class TaskController { + // Get all tasks for a board + public getTasksByBoardId = async (req: Request, res: Response) => { + try { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const boardId = +req.params.boardId; + const tasks = await TaskRepo.getTasksByBoardId(boardId); + return res.json({ tasks }); + } catch (err) { + return res.status(500).json({ error: 'Internal server error', + details: String(err) }); + } + }; + + // Get single task by boardId and taskId + public getTaskByBoardId = async (req: Request, res: Response) => { + try { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const boardId = +req.params.boardId; + const taskId = +req.params.taskId; + const task = await TaskRepo.getTaskByBoardId(boardId, taskId); + return res.json({ task }); + } catch (err) { + return res.status(500).json({ error: 'Internal server error', + details: String(err) }); + } + }; + + // Create task for a board + public createTask = async (req: Request, res: Response) => { + try { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + // Dummy form validation + const taskData = req.body as ITask; + if (!taskData.title) { + return res.status(400).json({ error: 'Task title required' }); + } + const boardId = +req.params.boardId; + const task = await TaskRepo.createTask(boardId, taskData); + return res.status(201).json({ task }); + } catch (err) { + return res.status(500).json({ error: 'Internal server error', + details: String(err) }); + } + }; + + // Update task for a board + public updateTask = async (req: Request, res: Response) => { + try { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + // Dummy form validation + const taskData = req.body as ITask; + if (!taskData.title) { + return res.status(400).json({ error: 'Task title required' }); + } + const boardId = +req.params.boardId; + const taskId = +req.params.taskId; + const task = await TaskRepo.updateTask(boardId, taskId, taskData); + return res.json({ task }); + } catch (err) { + return res.status(500).json({ error: 'Internal server error', + details: String(err) }); + } + }; + + // Delete task for a board + public deleteTask = async (req: Request, res: Response) => { + try { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const boardId = +req.params.boardId; + const taskId = +req.params.taskId; + await TaskRepo.deleteTask(boardId, taskId); + return res.status(204).end(); + } catch (err) { + return res.status(500).json({ error: 'Internal server error', + details: String(err) }); + } + }; +} + +export default new TaskController(); diff --git a/src/controllers/user.controller.ts b/src/controllers/user.controller.ts new file mode 100644 index 0000000..a595267 --- /dev/null +++ b/src/controllers/user.controller.ts @@ -0,0 +1,42 @@ +import { Request, Response } from 'express'; +import UserRepo from '@src/repos/user.repo'; +import { IUser } from '@src/models/user.model'; + +class UserController { + public getAll = async (req: Request, res: Response) => { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const users = await UserRepo.getAll(); + return res.status(200).json({ users }); + }; + + public add = async (req: Request, res: Response) => { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const user = req.body.user as IUser; + await UserRepo.add(user); + return res.status(201).end(); + }; + + public update = async (req: Request, res: Response) => { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const user = req.body.user as IUser; + await UserRepo.update(user); + return res.status(200).end(); + }; + + public delete = async (req: Request, res: Response) => { + if (req.headers.authorization !== 'Bearer testtoken') { + return res.status(401).json({ error: 'Unauthorized' }); + } + const id = +req.params.id; + await UserRepo.delete(id); + return res.status(200).end(); + }; +} + +export default new UserController(); \ No newline at end of file diff --git a/src/models/board.model.ts b/src/models/board.model.ts new file mode 100644 index 0000000..23b0c27 --- /dev/null +++ b/src/models/board.model.ts @@ -0,0 +1,80 @@ +// **** Variables **** // + +const INVALID_CONSTRUCTOR_PARAM = 'nameOrObj arg must be a string or an object with the appropriate board keys.'; + +// **** Types **** // + +export interface IBoard { + id: number; + userId: number; + name: string; + description?: string; + createdAt: string; + updatedAt: string; +} + +// **** Functions **** // + +/** + * Create new Board. + */ +function new_( + userId?: number, + name?: string, + description?: string, + createdAt?: string, + updatedAt?: string, + id?: number, +): IBoard { + const now = new Date().toISOString(); + return { + id: (id ?? -1), + userId: (userId ?? -1), + name: (name ?? ''), + description, + createdAt: (createdAt ?? now), + updatedAt: (updatedAt ?? now), + }; +} + +/** + * Get board instance from object. + */ +function from(param: object): IBoard { + if (!isBoard(param)) { + throw new Error(INVALID_CONSTRUCTOR_PARAM); + } + const p = param as IBoard; + return new_(p.userId, p.name, p.description, p.createdAt, p.updatedAt, p.id); +} + +/** + * See if the param meets criteria to be a board. + */ +function isBoard(arg: unknown): boolean { + return ( + !!arg && + typeof arg === 'object' && + 'id' in arg && + 'userId' in arg && + 'name' in arg && + 'createdAt' in arg && + 'updatedAt' in arg + ); +} + +// **** Export default **** // + +export default { + new: new_, + from, + isBoard, +} as const; +export interface IBoard { + id: number; + userId: number; + name: string; + description?: string; + createdAt: string; + updatedAt: string; +} diff --git a/src/models/task.model.ts b/src/models/task.model.ts new file mode 100644 index 0000000..ae74fee --- /dev/null +++ b/src/models/task.model.ts @@ -0,0 +1,85 @@ +// **** Variables **** // + +const INVALID_CONSTRUCTOR_PARAM = 'titleOrObj arg must be a string or an object with the appropriate task keys.'; + +// **** Types **** // + +export interface ITask { + id: number; + boardId: number; + title: string; + description?: string; + status: 'todo' | 'in-progress' | 'done'; + createdAt: string; + updatedAt: string; +} + +// **** Functions **** // + +/** + * Create new Task. + */ +function new_( + boardId?: number, + title?: string, + status?: 'todo' | 'in-progress' | 'done', + description?: string, + createdAt?: string, + updatedAt?: string, + id?: number, +): ITask { + const now = new Date().toISOString(); + return { + id: (id ?? -1), + boardId: (boardId ?? -1), + title: (title ?? ''), + status: (status ?? 'todo'), + description, + createdAt: (createdAt ?? now), + updatedAt: (updatedAt ?? now), + }; +} + +/** + * Get task instance from object. + */ +function from(param: object): ITask { + if (!isTask(param)) { + throw new Error(INVALID_CONSTRUCTOR_PARAM); + } + const p = param as ITask; + return new_(p.boardId, p.title, p.status, p.description, p.createdAt, p.updatedAt, p.id); +} + +/** + * See if the param meets criteria to be a task. + */ +function isTask(arg: unknown): boolean { + return ( + !!arg && + typeof arg === 'object' && + 'id' in arg && + 'boardId' in arg && + 'title' in arg && + 'status' in arg && + 'createdAt' in arg && + 'updatedAt' in arg + ); +} + +// **** Export default **** // + +export default { + new: new_, + from, + isTask, +} as const; +export interface ITask { + id: number; + boardId: number; + title: string; + description?: string; + status: 'todo' | 'in-progress' | 'done'; + createdAt: string; + updatedAt: string; +} diff --git a/src/models/User.ts b/src/models/user.model.ts similarity index 100% rename from src/models/User.ts rename to src/models/user.model.ts diff --git a/src/public/stylesheets/users.css b/src/public/stylesheets/users.css deleted file mode 100644 index 41efb7c..0000000 --- a/src/public/stylesheets/users.css +++ /dev/null @@ -1,50 +0,0 @@ -body { - padding: 100px; - font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; -} - -body .users-column { - display: inline-block; - margin-right: 2em; - vertical-align: top; -} - -body .users-column .column-header { - padding-bottom: 5px; - font-weight: 700; - font-size: 1.2em; -} - - -/** Add User Column **/ - -body .add-user-col input { - margin-bottom: 10px; -} - -body .add-user-col #add-user-btn { - margin-top: 2px; - margin-bottom: 10px; -} - -body .add-user-col #logout-btn { - margin-top: 25px; - margin-bottom: 10px; - font-size: 15px; -} - - -/** Users Display Column **/ - -body .users-column .user-display-ele { - padding-bottom: 10px; -} - -body .users-column .user-display-ele button { - margin-top: 2px; - margin-bottom: 10px; -} - -body .users-column .user-display-ele .edit-view { - display: none; -} diff --git a/src/repos/BoardRepo.ts b/src/repos/BoardRepo.ts new file mode 100644 index 0000000..54212db --- /dev/null +++ b/src/repos/BoardRepo.ts @@ -0,0 +1,53 @@ +import { IBoard } from '@src/models/board.model'; +import orm from './MockOrm'; + +async function getBoardsByUserId(userId: number): Promise { + const db = await orm.openDb(); + return db.boards.filter((board: IBoard) => board.userId === userId); +} + +async function getBoardByUserId(userId: number, boardId: number): Promise { + const db = await orm.openDb(); + return db.boards.find((board: IBoard) => board.userId === userId && board.id === boardId) || null; +} + +async function createBoard(userId: number, board: IBoard): Promise { + const db = await orm.openDb(); + board.id = Date.now(); + board.userId = userId; + board.createdAt = new Date().toISOString(); + board.updatedAt = board.createdAt; + db.boards.push(board); + await orm.saveDb(db); + return board; +} + +async function updateBoard(userId: number, boardId: number, boardData: Partial): Promise { + const db = await orm.openDb(); + const board = db.boards.find((b: IBoard) => b.userId === userId && b.id === boardId); + if (board) { + Object.assign(board, boardData, { updatedAt: new Date().toISOString() }); + await orm.saveDb(db); + return board; + } + return null; +} + +async function deleteBoard(userId: number, boardId: number): Promise { + const db = await orm.openDb(); + const idx = db.boards.findIndex((b: IBoard) => b.userId === userId && b.id === boardId); + if (idx !== -1) { + db.boards.splice(idx, 1); + await orm.saveDb(db); + return true; + } + return false; +} + +export default { + getBoardsByUserId, + getBoardByUserId, + createBoard, + updateBoard, + deleteBoard, +}; diff --git a/src/repos/MockOrm.ts b/src/repos/MockOrm.ts index e2093cf..0197884 100644 --- a/src/repos/MockOrm.ts +++ b/src/repos/MockOrm.ts @@ -2,7 +2,9 @@ import jsonfile from 'jsonfile'; -import { IUser } from '@src/models/User'; +import { IUser } from '@src/models/user.model'; +import { IBoard } from '@src/models/board.model'; +import { ITask } from '@src/models/task.model'; // **** Variables **** // @@ -14,6 +16,8 @@ const DB_FILE_NAME = 'database.json'; interface IDb { users: IUser[]; + boards: IBoard[]; + tasks: ITask[]; } diff --git a/src/repos/TaskRepo.ts b/src/repos/TaskRepo.ts new file mode 100644 index 0000000..8371a6d --- /dev/null +++ b/src/repos/TaskRepo.ts @@ -0,0 +1,53 @@ +import { ITask } from '@src/models/task.model'; +import orm from './MockOrm'; + +async function getTasksByBoardId(boardId: number): Promise { + const db = await orm.openDb(); + return db.tasks.filter((task: ITask) => task.boardId === boardId); +} + +async function getTaskByBoardId(boardId: number, taskId: number): Promise { + const db = await orm.openDb(); + return db.tasks.find((task: ITask) => task.boardId === boardId && task.id === taskId) || null; +} + +async function createTask(boardId: number, task: ITask): Promise { + const db = await orm.openDb(); + task.id = Date.now(); + task.boardId = boardId; + task.createdAt = new Date().toISOString(); + task.updatedAt = task.createdAt; + db.tasks.push(task); + await orm.saveDb(db); + return task; +} + +async function updateTask(boardId: number, taskId: number, taskData: Partial): Promise { + const db = await orm.openDb(); + const task = db.tasks.find((t: ITask) => t.boardId === boardId && t.id === taskId); + if (task) { + Object.assign(task, taskData, { updatedAt: new Date().toISOString() }); + await orm.saveDb(db); + return task; + } + return null; +} + +async function deleteTask(boardId: number, taskId: number): Promise { + const db = await orm.openDb(); + const idx = db.tasks.findIndex((t: ITask) => t.boardId === boardId && t.id === taskId); + if (idx !== -1) { + db.tasks.splice(idx, 1); + await orm.saveDb(db); + return true; + } + return false; +} + +export default { + getTasksByBoardId, + getTaskByBoardId, + createTask, + updateTask, + deleteTask, +}; diff --git a/src/repos/board.repo.ts b/src/repos/board.repo.ts new file mode 100644 index 0000000..d4bff20 --- /dev/null +++ b/src/repos/board.repo.ts @@ -0,0 +1,64 @@ +import { IBoard } from '@src/models/board.model'; +import orm from './MockOrm'; + +async function getBoardsByUserId(userId: number): Promise { + const db = await orm.openDb(); + const boards = Array.isArray(db.boards) ? db.boards : []; + return boards.filter((board: IBoard) => board.userId === userId); +} + +async function getBoardByUserId(userId: number, boardId: number): + Promise { + const db = await orm.openDb(); + const boards = Array.isArray(db.boards) ? db.boards : []; + return boards.find( + (board: IBoard) => board.userId === userId && board.id === boardId, + ) || null; +} + +async function createBoard(userId: number, board: IBoard): Promise { + const db = await orm.openDb(); + if (!Array.isArray(db.boards)) db.boards = []; + board.id = Date.now(); + board.userId = userId; + board.createdAt = new Date().toISOString(); + board.updatedAt = board.createdAt; + db.boards.push(board); + await orm.saveDb(db); + return board; +} + +async function updateBoard(userId: number, boardId: number, boardData: + Partial): Promise { + const db = await orm.openDb(); + const boards = Array.isArray(db.boards) ? db.boards : []; + const board = boards.find((b: IBoard) => b.userId === userId && + b.id === boardId); + if (board) { + Object.assign(board, boardData, { updatedAt: new Date().toISOString() }); + await orm.saveDb(db); + return board; + } + return null; +} + +async function deleteBoard(userId: number, boardId: number): Promise { + const db = await orm.openDb(); + const boards = Array.isArray(db.boards) ? db.boards : []; + const idx = boards.findIndex((b: IBoard) => b.userId === userId && + b.id === boardId); + if (idx !== -1) { + boards.splice(idx, 1); + await orm.saveDb(db); + return true; + } + return false; +} + +export default { + getBoardsByUserId, + getBoardByUserId, + createBoard, + updateBoard, + deleteBoard, +}; diff --git a/src/repos/database.json b/src/repos/database.json index 00d993e..2d3d2d1 100644 --- a/src/repos/database.json +++ b/src/repos/database.json @@ -1 +1 @@ -{"users":[{"name":"Sean Maxwell","email":"sean.maxwell@gmail.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":1,"id":159123164363},{"name":"Gordan Freeman","email":"gordan.freeman@halflife.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":0,"id":906524522143},{"name":"John Smith","email":"jsmith@yahoo.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":0,"id":357437875835},{"id":75800032258,"name":"asdf","email":"asdfasdf","role":0}]} +{"users":[{"name":"Sean Maxwell","email":"sean.maxwell@gmail.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":1,"id":159123164363},{"name":"Gordan Freeman","email":"gordan.freeman@halflife.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":0,"id":906524522143},{"name":"John Smith","email":"jsmith@yahoo.com","pwdHash":"$2b$12$1mE2OI9hMS/rgH9Mi0s85OM2V5gzm7aF3gJIWH1y0S1MqVBueyjsy","role":0,"id":357437875835},{"id":75800032258,"name":"asdf","email":"asdfasdf","role":0}],"boards":[{"name":"Project Board","id":1758960982352,"userId":1,"createdAt":"2025-09-27T08:16:22.352Z","updatedAt":"2025-09-27T08:16:22.352Z"}],"tasks":[{"title":"New Task","description":"Task details","status":"todo","id":1758961254717,"boardId":1758960982352,"createdAt":"2025-09-27T08:20:54.717Z","updatedAt":"2025-09-27T08:20:54.717Z"},{"title":"New Task 2","description":"Task details 2","status":"todo","id":1758961267429,"boardId":1758960982352,"createdAt":"2025-09-27T08:21:07.429Z","updatedAt":"2025-09-27T08:21:07.429Z"}]} diff --git a/src/repos/task.repo.ts b/src/repos/task.repo.ts new file mode 100644 index 0000000..51ebe0c --- /dev/null +++ b/src/repos/task.repo.ts @@ -0,0 +1,63 @@ +import { ITask } from '@src/models/task.model'; +import orm from './MockOrm'; + +async function getTasksByBoardId(boardId: number): Promise { + const db = await orm.openDb(); + const tasks = Array.isArray(db.tasks) ? db.tasks : []; + return tasks.filter((task: ITask) => task.boardId === boardId); +} + +async function getTaskByBoardId(boardId: number, taskId: number): + Promise { + const db = await orm.openDb(); + const tasks = Array.isArray(db.tasks) ? db.tasks : []; + return tasks.find((task: ITask) => task.boardId === boardId && + task.id === taskId) || null; +} + +async function createTask(boardId: number, task: ITask): Promise { + const db = await orm.openDb(); + if (!Array.isArray(db.tasks)) db.tasks = []; + task.id = Date.now(); + task.boardId = boardId; + task.createdAt = new Date().toISOString(); + task.updatedAt = task.createdAt; + db.tasks.push(task); + await orm.saveDb(db); + return task; +} + +async function updateTask(boardId: number, taskId: number, taskData: + Partial): Promise { + const db = await orm.openDb(); + const tasks = Array.isArray(db.tasks) ? db.tasks : []; + const task = tasks.find((t: ITask) => t.boardId === boardId && + t.id === taskId); + if (task) { + Object.assign(task, taskData, { updatedAt: new Date().toISOString() }); + await orm.saveDb(db); + return task; + } + return null; +} + +async function deleteTask(boardId: number, taskId: number): Promise { + const db = await orm.openDb(); + const tasks = Array.isArray(db.tasks) ? db.tasks : []; + const idx = tasks.findIndex((t: ITask) => t.boardId === boardId && + t.id === taskId); + if (idx !== -1) { + tasks.splice(idx, 1); + await orm.saveDb(db); + return true; + } + return false; +} + +export default { + getTasksByBoardId, + getTaskByBoardId, + createTask, + updateTask, + deleteTask, +}; diff --git a/src/repos/UserRepo.ts b/src/repos/user.repo.ts similarity index 91% rename from src/repos/UserRepo.ts rename to src/repos/user.repo.ts index 2b525c8..a8760a0 100644 --- a/src/repos/UserRepo.ts +++ b/src/repos/user.repo.ts @@ -1,4 +1,4 @@ -import { IUser } from '@src/models/User'; +import { IUser } from '@src/models/user.model'; import { getRandomInt } from '@src/util/misc'; import orm from './MockOrm'; diff --git a/src/routes/UserRoutes.ts b/src/routes/UserRoutes.ts deleted file mode 100644 index caa2f37..0000000 --- a/src/routes/UserRoutes.ts +++ /dev/null @@ -1,53 +0,0 @@ -import HttpStatusCodes from '@src/constants/HttpStatusCodes'; - -import UserService from '@src/services/UserService'; -import { IUser } from '@src/models/User'; -import { IReq, IRes } from './types/express/misc'; - - -// **** Functions **** // - -/** - * Get all users. - */ -async function getAll(_: IReq, res: IRes) { - const users = await UserService.getAll(); - return res.status(HttpStatusCodes.OK).json({ users }); -} - -/** - * Add one user. - */ -async function add(req: IReq<{user: IUser}>, res: IRes) { - const { user } = req.body; - await UserService.addOne(user); - return res.status(HttpStatusCodes.CREATED).end(); -} - -/** - * Update one user. - */ -async function update(req: IReq<{user: IUser}>, res: IRes) { - const { user } = req.body; - await UserService.updateOne(user); - return res.status(HttpStatusCodes.OK).end(); -} - -/** - * Delete one user. - */ -async function delete_(req: IReq, res: IRes) { - const id = +req.params.id; - await UserService.delete(id); - return res.status(HttpStatusCodes.OK).end(); -} - - -// **** Export default **** // - -export default { - getAll, - add, - update, - delete: delete_, -} as const; diff --git a/src/routes/api.ts b/src/routes/api.ts deleted file mode 100644 index 929aa09..0000000 --- a/src/routes/api.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Router } from 'express'; -import jetValidator from 'jet-validator'; - -import Paths from './constants/Paths'; -import User from '@src/models/User'; -import UserRoutes from './UserRoutes'; - - -// **** Variables **** // - -const apiRouter = Router(), - validate = jetValidator(); - - -// ** Add UserRouter ** // - -const userRouter = Router(); - -// Get all users -userRouter.get( - Paths.Users.Get, - UserRoutes.getAll, -); - -// Add one user -userRouter.post( - Paths.Users.Add, - validate(['user', User.isUser]), - UserRoutes.add, -); - -// Update one user -userRouter.put( - Paths.Users.Update, - validate(['user', User.isUser]), - UserRoutes.update, -); - -// Delete one user -userRouter.delete( - Paths.Users.Delete, - validate(['id', 'number', 'params']), - UserRoutes.delete, -); - -// Add UserRouter -apiRouter.use(Paths.Users.Base, userRouter); - - -// **** Export default **** // - -export default apiRouter; diff --git a/src/routes/board.route.ts b/src/routes/board.route.ts new file mode 100644 index 0000000..bc414d2 --- /dev/null +++ b/src/routes/board.route.ts @@ -0,0 +1,13 @@ + +import { Router } from 'express'; +import BoardController from '../controllers/board.controller'; + +const router = Router(); + +router.get('/user/:userId', BoardController.getBoardsByUserId); +router.get('/user/:userId/:boardId', BoardController.getBoardByUserId); +router.post('/user/:userId', BoardController.createBoard); +router.put('/user/:userId/:boardId', BoardController.updateBoard); +router.delete('/user/:userId/:boardId', BoardController.deleteBoard); + +export default router; diff --git a/src/routes/constants/FullPaths.ts b/src/routes/constants/FullPaths.ts deleted file mode 100644 index 2241c2e..0000000 --- a/src/routes/constants/FullPaths.ts +++ /dev/null @@ -1,40 +0,0 @@ - -/** - * Convert paths to full paths. - */ - -import Paths, { TPaths } from './Paths'; - - -interface IPathObj { - Base: string; - [key: string]: string | IPathObj; -} - -/** - * The recursive function. - */ -function getFullPaths( - parent: IPathObj, - baseUrl: string, -): IPathObj { - const url = (baseUrl + parent.Base), - keys = Object.keys(parent), - retVal: IPathObj = { Base: url }; - // Iterate keys - for (const key of keys) { - const pval = parent[key]; - if (key !== 'Base' && typeof pval === 'string') { - retVal[key] = (url + pval); - } else if (typeof pval === 'object') { - retVal[key] = getFullPaths(pval, url); - } - } - // Return - return retVal; -} - - -// **** Export default **** // - -export default getFullPaths(Paths, '') as TPaths; diff --git a/src/routes/constants/Paths.ts b/src/routes/constants/Paths.ts deleted file mode 100644 index 63397d1..0000000 --- a/src/routes/constants/Paths.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Express router paths go here. - */ - -import { Immutable } from '@src/other/types'; - - -const Paths = { - Base: '/api', - Users: { - Base: '/users', - Get: '/all', - Add: '/add', - Update: '/update', - Delete: '/delete/:id', - }, -}; - - -// **** Export **** // - -export type TPaths = Immutable; -export default Paths as TPaths; diff --git a/src/routes/index.ts b/src/routes/index.ts new file mode 100644 index 0000000..e023f14 --- /dev/null +++ b/src/routes/index.ts @@ -0,0 +1,12 @@ +import { Router } from 'express'; +import boardRouter from './board.route'; +import taskRouter from './task.route'; +import userRouter from './user.route'; + +const router = Router(); + +router.use('/boards', boardRouter); +router.use('/tasks', taskRouter); +router.use('/users', userRouter); + +export default router; diff --git a/src/routes/task.route.ts b/src/routes/task.route.ts new file mode 100644 index 0000000..d37e81c --- /dev/null +++ b/src/routes/task.route.ts @@ -0,0 +1,13 @@ + +import { Router } from 'express'; +import TaskController from '../controllers/task.controller'; + +const router = Router(); + +router.get('/board/:boardId', TaskController.getTasksByBoardId); +router.get('/board/:boardId/:taskId', TaskController.getTaskByBoardId); +router.post('/board/:boardId', TaskController.createTask); +router.put('/board/:boardId/:taskId', TaskController.updateTask); +router.delete('/board/:boardId/:taskId', TaskController.deleteTask); + +export default router; diff --git a/src/routes/types/express/index.d.ts b/src/routes/types/express/index.d.ts deleted file mode 100644 index eb0b809..0000000 --- a/src/routes/types/express/index.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import 'express'; - - -// **** Declaration Merging **** // - -declare module 'express' { - - export interface Request { - signedCookies: Record; - } -} diff --git a/src/routes/types/express/misc.ts b/src/routes/types/express/misc.ts deleted file mode 100644 index b5b3b2c..0000000 --- a/src/routes/types/express/misc.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as e from 'express'; - -import { ISessionUser } from '@src/models/User'; - - -// **** Express **** // - -export interface IReq extends e.Request { - body: T; -} - -export interface IRes extends e.Response { - locals: { - sessionUser?: ISessionUser; - }; -} diff --git a/src/routes/types/types.ts b/src/routes/types/types.ts deleted file mode 100644 index c9c693a..0000000 --- a/src/routes/types/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as e from 'express'; -import { Query } from 'express-serve-static-core'; - -import { ISessionUser } from '@src/models/User'; - - -// **** Express **** // - -export interface IReq extends e.Request { - body: T; -} - -export interface IReqQuery extends e.Request { - query: T; - body: U; -} - -export interface IRes extends e.Response { - locals: { - sessionUser: ISessionUser; - }; -} diff --git a/src/routes/user.route.ts b/src/routes/user.route.ts new file mode 100644 index 0000000..2a2cf01 --- /dev/null +++ b/src/routes/user.route.ts @@ -0,0 +1,11 @@ +import { Router } from 'express'; +import UserController from '../controllers/user.controller'; + +const router = Router(); + +router.get('/', UserController.getAll); +router.post('/', UserController.add); +router.put('/', UserController.update); +router.delete('/:id', UserController.delete); + +export default router; diff --git a/src/server.ts b/src/server.ts index 5f8e6c7..14b4018 100644 --- a/src/server.ts +++ b/src/server.ts @@ -11,8 +11,7 @@ import logger from 'jet-logger'; import 'express-async-errors'; -import BaseRouter from '@src/routes/api'; -import Paths from '@src/routes/constants/Paths'; +import BaseRouter from '@src/routes'; import EnvVars from '@src/constants/EnvVars'; import HttpStatusCodes from '@src/constants/HttpStatusCodes'; @@ -44,7 +43,7 @@ if (EnvVars.NodeEnv === NodeEnvs.Production) { } // Add APIs, must be after middleware -app.use(Paths.Base, BaseRouter); +app.use('/', BaseRouter); // Add error handler app.use(( diff --git a/src/services/AuthService.ts b/src/services/AuthService.ts index 175c701..195e38a 100644 --- a/src/services/AuthService.ts +++ b/src/services/AuthService.ts @@ -1,11 +1,11 @@ -import UserRepo from '@src/repos/UserRepo'; +import UserRepo from '@src/repos/user.repo'; import PwdUtil from '@src/util/PwdUtil'; import { tick } from '@src/util/misc'; import HttpStatusCodes from '@src/constants/HttpStatusCodes'; import { RouteError } from '@src/other/classes'; -import { IUser } from '@src/models/User'; +import { IUser } from '@src/models/user.model'; // **** Variables **** // diff --git a/src/services/UserService.ts b/src/services/UserService.ts index a07c647..32e1499 100644 --- a/src/services/UserService.ts +++ b/src/services/UserService.ts @@ -1,5 +1,5 @@ -import UserRepo from '@src/repos/UserRepo'; -import { IUser } from '@src/models/User'; +import UserRepo from '@src/repos/user.repo'; +import { IUser } from '@src/models/user.model'; import { RouteError } from '@src/other/classes'; import HttpStatusCodes from '@src/constants/HttpStatusCodes'; diff --git a/src/util/SessionUtil.ts b/src/util/SessionUtil.ts index a625401..bcbd43f 100644 --- a/src/util/SessionUtil.ts +++ b/src/util/SessionUtil.ts @@ -65,9 +65,14 @@ function clearCookie(res: Response): Response { */ function _sign(data: string | object | Buffer): Promise { return new Promise((res, rej) => { - jsonwebtoken.sign(data, EnvVars.Jwt.Secret, Options, (err, token) => { - return err ? rej(err) : res(token || ''); - }); + jsonwebtoken.sign( + data, + EnvVars.Jwt.Secret, + { expiresIn: '1h' }, + (err: Error | null, token?: string) => { + return err ? rej(err) : res(token || ''); + }, + ); }); } @@ -76,9 +81,14 @@ function _sign(data: string | object | Buffer): Promise { */ function _decode(jwt: string): Promise { return new Promise((res, rej) => { - jsonwebtoken.verify(jwt, EnvVars.Jwt.Secret, (err, decoded) => { - return err ? rej(Errors.Validation) : res(decoded as T); - }); + jsonwebtoken.verify( + jwt, + EnvVars.Jwt.Secret, + undefined, + (err: Error | null, decoded?: string | jsonwebtoken.JwtPayload) => { + return err ? rej(Errors.Validation) : res(decoded as T); + }, + ); }); } diff --git a/src/views/users.html b/src/views/users.html deleted file mode 100644 index 3d43d8a..0000000 --- a/src/views/users.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Users - - - - - -
-
- Add User: -
-
- -
-
- -
-
- -
-
- - -
-
Users:
-
-
- - - - - diff --git a/tsconfig.json b/tsconfig.json index 2d1c5ee..3a4c337 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,83 +1,24 @@ { "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - // "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "dist", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - - /* Module Resolution Options */ - // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - - /* Advanced Options */ - "skipLibCheck": true, /* Skip type checking of declaration files. */ - "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ + "allowJs": true, + "baseUrl": ".", + "esModuleInterop": true, + "moduleResolution": "nodenext", + "forceConsistentCasingInFileNames": true, + "module": "nodenext", + "target": "es2019", + "noImplicitReturns": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "outDir": "lib", + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "types": ["node", "express"], "paths": { - "@src/*": [ - "src/*" - ], - }, - "useUnknownInCatchVariables": false + "@src/*": ["src/*"] + } }, - "include": [ - "src/**/*.ts", - "spec/**/*.ts", - "build.ts" - ], - "exclude": [ - "src/public/" - ] -} \ No newline at end of file + "compileOnSave": true, + "include": ["src"] +}