@joystick.js/node-canary 0.0.0-canary.8 → 0.0.0-canary.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/_package.json +2 -1
  2. package/dist/app/accounts/createMetadataTableColumns.js +12 -0
  3. package/dist/app/accounts/deleteUser.js +7 -0
  4. package/dist/app/accounts/generateSession.js +2 -4
  5. package/dist/app/accounts/getBrowserSafeUser.js +2 -1
  6. package/dist/app/accounts/hasLoginTokenExpired.js +1 -2
  7. package/dist/app/accounts/index.js +2 -0
  8. package/dist/app/accounts/signup.js +37 -7
  9. package/dist/app/databases/mongodb/createAccountsIndexes.js +18 -0
  10. package/dist/app/databases/mongodb/index.js +1 -1
  11. package/dist/app/databases/mongodb/queries/accounts.js +7 -0
  12. package/dist/app/databases/postgresql/queries/accounts.js +3 -0
  13. package/dist/app/databases/stringToSnakeCase.js +6 -0
  14. package/dist/app/getBrowserSafeRequest.js +3 -2
  15. package/dist/app/index.js +104 -12
  16. package/dist/app/middleware/getTranslations.js +64 -0
  17. package/dist/app/middleware/index.js +4 -5
  18. package/dist/app/middleware/render.js +11 -68
  19. package/dist/app/sanitizeAPIResponse.js +1 -6
  20. package/dist/app/validateSession.js +3 -0
  21. package/dist/email/templates/reset-password.js +0 -1
  22. package/dist/index.js +7 -2
  23. package/dist/lib/escapeHTML.js +9 -0
  24. package/dist/lib/escapeKeyValuePair.js +13 -0
  25. package/dist/lib/getBuildPath.js +1 -1
  26. package/dist/lib/getSSLCertificates.js +1 -1
  27. package/dist/lib/importFile.js +7 -0
  28. package/dist/lib/log.js +0 -3
  29. package/dist/lib/nodeUrlPolyfills.js +7 -14
  30. package/dist/lib/wait.js +8 -0
  31. package/dist/ssr/getAPIForDataFunctions.js +33 -0
  32. package/dist/ssr/getDataFromComponent.js +14 -0
  33. package/dist/ssr/index.js +5 -41
  34. package/package.json +2 -1
  35. package/dist/app/accounts/roles/index.test.js +0 -123
  36. package/dist/app/index.test.js +0 -575
  37. package/dist/app/middleware/sanitizeQueryParameters.js +0 -16
  38. package/dist/email/send.test.js +0 -37
@@ -1,10 +1,5 @@
1
1
  import util from "util";
2
- import { HTML_ENTITY_MAP } from "../lib/constants.js";
3
- const escapeHTML = (string = "") => {
4
- return String(string).replace(/[&<>"'`=\/]/g, function(match) {
5
- return HTML_ENTITY_MAP[match];
6
- });
7
- };
2
+ import escapeHTML from "../lib/escapeHTML.js";
8
3
  const sanitizeAPIResponse = (data = null) => {
9
4
  let sanitizedData = data;
10
5
  if (!util.isString(sanitizedData) && !util.isObject(sanitizedData) && !Array.isArray(sanitizedData)) {
@@ -3,6 +3,9 @@ var validateSession_default = (req = null, res = null, sessions = null) => {
3
3
  const sessionToken = req?.cookies?.joystickSession;
4
4
  const csrfToken = req?.headers["x-joystick-csrf"];
5
5
  const session = sessions?.get(sessionToken);
6
+ if (csrfToken === "joystick_test") {
7
+ return true;
8
+ }
6
9
  if (!session || session && session.csrf !== csrfToken) {
7
10
  res.status(403).send(JSON.stringify({
8
11
  errors: [formatAPIError(new Error("Unauthorized request."))]
@@ -1,6 +1,5 @@
1
1
  import ui from "@joystick.js/ui";
2
2
  const ResetPassword = ui.component({
3
- id: process.env.NODE_ENV === "test" ? "testComponent1234" : null,
4
3
  render: ({ props }) => {
5
4
  return `
6
5
  <p>A password reset was requested for this email address (${props.emailAddress}). If you requested this reset, click the link below to reset your password:</p>
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
- import sanitizeHTML from "sanitize-html";
2
1
  import fs from "fs";
2
+ import { fileURLToPath } from "url";
3
+ import { dirname } from "path";
4
+ import sanitizeHTML from "sanitize-html";
3
5
  import _accounts from "./app/accounts";
4
6
  import _action from "./action/index.js";
5
7
  import _websockets from "./websockets";
@@ -27,16 +29,18 @@ const sanitize = {
27
29
  allowedTags: sanitizeHTML.defaults.allowedTags
28
30
  }
29
31
  };
32
+ const currentFilePath = fileURLToPath(import.meta.url);
33
+ const __package = dirname(currentFilePath);
30
34
  const __filename = nodeUrlPolyfills.__filename;
31
35
  const __dirname = nodeUrlPolyfills.__dirname;
32
36
  const id = generateId;
33
37
  const origin = getOrigin();
34
38
  const settings = loadSettings();
35
- console.log("HERE", fs.readFileSync(__dirname("dist/app/utils/process.js")?.replace("file://", ""), "utf-8"));
36
39
  global.joystick = {
37
40
  id: generateId,
38
41
  emitters: {},
39
42
  settings,
43
+ __package,
40
44
  __dirname,
41
45
  __filename
42
46
  };
@@ -58,6 +62,7 @@ var src_default = {
58
62
  export {
59
63
  __dirname,
60
64
  __filename,
65
+ __package,
61
66
  accounts,
62
67
  action,
63
68
  src_default as default,
@@ -0,0 +1,9 @@
1
+ import { HTML_ENTITY_MAP } from "./constants.js";
2
+ var escapeHTML_default = (string = "") => {
3
+ return String(string).replace(/[&<>"'`=]/g, function(match) {
4
+ return HTML_ENTITY_MAP[match];
5
+ });
6
+ };
7
+ export {
8
+ escapeHTML_default as default
9
+ };
@@ -0,0 +1,13 @@
1
+ import escapeHTML from "./escapeHTML.js";
2
+ var escapeKeyValuePair_default = (target = {}) => {
3
+ const parameters = Object.entries(target || {});
4
+ for (let i = 0; i < parameters?.length; i += 1) {
5
+ const [key, value] = parameters[i];
6
+ delete target[key];
7
+ target[escapeHTML(key)] = escapeHTML(value);
8
+ }
9
+ return target;
10
+ };
11
+ export {
12
+ escapeKeyValuePair_default as default
13
+ };
@@ -1,6 +1,6 @@
1
1
  import fs from "fs";
2
2
  var getBuildPath_default = () => {
3
- if (process.env.NODE_ENV === "development" || fs.existsSync(".joystick/build")) {
3
+ if (["development", "test"].includes(process.env.NODE_ENV) || fs.existsSync(".joystick/build")) {
4
4
  return ".joystick/build/";
5
5
  }
6
6
  return "";
@@ -6,7 +6,7 @@ var getSSLCertificates_default = (ssl = null) => {
6
6
  const keyPath = process.env.IS_PUSH_DEPLOYED ? pushKeyPath : ssl?.key || null;
7
7
  const certExists = fs.existsSync(certPath);
8
8
  const keyExists = fs.existsSync(keyPath);
9
- if (process.env.NODE_ENV === "development" || !certExists || !keyExists) {
9
+ if (["development", "test"].includes(process.env.NODE_ENV) || !certExists || !keyExists) {
10
10
  return null;
11
11
  }
12
12
  return {
@@ -0,0 +1,7 @@
1
+ var importFile_default = async (buildPath = "") => {
2
+ const file = await import(buildPath);
3
+ return file?.default;
4
+ };
5
+ export {
6
+ importFile_default as default
7
+ };
package/dist/lib/log.js CHANGED
@@ -1,9 +1,6 @@
1
1
  import chalk from "chalk";
2
2
  import rainbowRoad from "./rainbowRoad.js";
3
3
  var log_default = (message = "", options = {}) => {
4
- if (process.env.NODE_ENV === "test") {
5
- return;
6
- }
7
4
  const colors = {
8
5
  info: "blue",
9
6
  success: "green",
@@ -1,19 +1,12 @@
1
- import { URL } from "url";
1
+ import { fileURLToPath } from "url";
2
+ import { dirname } from "path";
2
3
  var nodeUrlPolyfills_default = {
3
- __filename: (url = null) => {
4
- if (!url) {
5
- return "";
6
- }
7
- const path = new URL(".", url)?.replace("file://", "");
8
- return path?.pathname;
4
+ __filename: (url = "") => {
5
+ return fileURLToPath(url);
9
6
  },
10
- __dirname: (url = null) => {
11
- if (!url) {
12
- return "";
13
- }
14
- console.log({ url });
15
- const path = new URL("./", url)?.replace("file://", "");
16
- return path?.pathname || "";
7
+ __dirname: (url = "") => {
8
+ const currentFilePath = fileURLToPath(url);
9
+ return dirname(currentFilePath);
17
10
  }
18
11
  };
19
12
  export {
@@ -0,0 +1,8 @@
1
+ var wait_default = (seconds = 0) => {
2
+ return new Promise((resolve) => {
3
+ setTimeout(() => resolve(), seconds * 1e3);
4
+ });
5
+ };
6
+ export {
7
+ wait_default as default
8
+ };
@@ -0,0 +1,33 @@
1
+ import get from "../api/get";
2
+ import set from "../api/set";
3
+ var getAPIForDataFunctions_default = (req = {}, api = {}) => {
4
+ try {
5
+ return {
6
+ get: (getterName = "", getterOptions = {}) => {
7
+ return get({
8
+ getterName,
9
+ getterOptions: api?.getters[getterName] || {},
10
+ input: getterOptions?.input,
11
+ output: getterOptions?.output,
12
+ context: req?.context,
13
+ APIOptions: api?.options
14
+ });
15
+ },
16
+ set: (setterName = "", setterOptions = {}) => {
17
+ return set({
18
+ setterName,
19
+ setterOptions: api?.setters[setterName] || {},
20
+ input: setterOptions?.input,
21
+ output: setterOptions?.output,
22
+ context: req?.context,
23
+ APIOptions: api?.options
24
+ });
25
+ }
26
+ };
27
+ } catch (exception) {
28
+ throw new Error(`[ssr.getAPIForDataFunctions] ${exception.message}`);
29
+ }
30
+ };
31
+ export {
32
+ getAPIForDataFunctions_default as default
33
+ };
@@ -0,0 +1,14 @@
1
+ var getDataFromComponent_default = async (componentInstance = {}, api = {}, browserSafeRequest = {}) => {
2
+ try {
3
+ const data = await componentInstance.handleFetchData(api, browserSafeRequest, {}, componentInstance);
4
+ return {
5
+ componentId: componentInstance?.id,
6
+ data
7
+ };
8
+ } catch (exception) {
9
+ throw new Error(`[ssr.getDataFromComponent] ${exception.message}`);
10
+ }
11
+ };
12
+ export {
13
+ getDataFromComponent_default as default
14
+ };
package/dist/ssr/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import fs from "fs";
2
+ import { __package } from "../index.js";
2
3
  import get from "../api/get";
3
4
  import set from "../api/set";
4
5
  import getBrowserSafeRequest from "../app/getBrowserSafeRequest";
@@ -7,6 +8,8 @@ import getCSSFromTree from "./getCSSFromTree";
7
8
  import replaceWhenTags from "./replaceWhenTags";
8
9
  import setHeadTagsInHTML from "./setHeadTagsInHTML";
9
10
  import { parseHTML } from "linkedom";
11
+ import getDataFromComponent from "./getDataFromComponent.js";
12
+ import getAPIForDataFunctions from "./getAPIForDataFunctions.js";
10
13
  const injectCSSIntoHTML = (html, baseCSS = "", css = "") => {
11
14
  try {
12
15
  return html.replace("${css}", css).replace("${globalCSS}", `<style>${baseCSS || ""}</style>`).replace("${componentCSS}", css);
@@ -184,7 +187,7 @@ const getBaseCSS = (baseHTMLName = "") => {
184
187
  try {
185
188
  const customBaseCSSPathForEmail = baseHTMLName ? `${process.cwd()}/email/base_${baseHTMLName}.css` : null;
186
189
  const customDefaultBaseCSSPathForEmail = `${process.cwd()}/email/base.css`;
187
- const defaultBaseCSSPathForEmail = process.env.NODE_ENV === "test" ? `${process.cwd()}/src/email/templates/base.css` : `${process.cwd()}/node_modules/@joystick.js/node/dist/email/templates/base.css`;
190
+ const defaultBaseCSSPathForEmail = process.env.NODE_ENV === "test" ? `${process.cwd()}/src/email/templates/base.css` : `${__package}/email/templates/base.css`;
188
191
  let baseCSSPathToFetch = defaultBaseCSSPathForEmail;
189
192
  if (fs.existsSync(customDefaultBaseCSSPathForEmail)) {
190
193
  baseCSSPathToFetch = customDefaultBaseCSSPathForEmail;
@@ -242,7 +245,7 @@ const getBaseHTML = (isEmailRender = false, baseEmailHTMLName = "") => {
242
245
  if (isEmailRender) {
243
246
  const customBaseHTMLPathForEmail = baseEmailHTMLName ? `${process.cwd()}/email/base_${baseEmailHTMLName}.html` : null;
244
247
  const customDefaultBaseHTMLPathForEmail = `${process.cwd()}/email/base.html`;
245
- const defaultBaseHTMLPathForEmail = process.env.NODE_ENV === "test" ? `${process.cwd()}/src/email/templates/base.html` : `${process.cwd()}/node_modules/@joystick.js/node/dist/email/templates/base.html`;
248
+ const defaultBaseHTMLPathForEmail = process.env.NODE_ENV === "test" ? `${process.cwd()}/src/email/templates/base.html` : `${__package}/email/templates/base.html`;
246
249
  baseHTMLPathToFetch = defaultBaseHTMLPathForEmail;
247
250
  if (fs.existsSync(customDefaultBaseHTMLPathForEmail)) {
248
251
  baseHTMLPathToFetch = customDefaultBaseHTMLPathForEmail;
@@ -289,17 +292,6 @@ const buildTreeForComponent = (componentInstance = {}, ssrTree = {}, translation
289
292
  throw new Error(`[ssr.buildTreeForComponent] ${exception.message}`);
290
293
  }
291
294
  };
292
- const getDataFromComponent = async (componentInstance = {}, api = {}, browserSafeRequest = {}) => {
293
- try {
294
- const data = await componentInstance.handleFetchData(api, browserSafeRequest, {}, componentInstance);
295
- return {
296
- componentId: componentInstance?.id,
297
- data
298
- };
299
- } catch (exception) {
300
- throw new Error(`[ssr.getDataFromComponent] ${exception.message}`);
301
- }
302
- };
303
295
  const getTreeForSSR = (componentInstance = {}) => {
304
296
  try {
305
297
  return {
@@ -320,34 +312,6 @@ const getComponentInstance = (Component, options = {}) => {
320
312
  throw new Error(`[ssr.getComponentInstance] ${exception.message}`);
321
313
  }
322
314
  };
323
- const getAPIForDataFunctions = (req = {}, api = {}) => {
324
- try {
325
- return {
326
- get: (getterName = "", getterOptions = {}) => {
327
- return get({
328
- getterName,
329
- getterOptions: api?.getters[getterName] || {},
330
- input: getterOptions?.input,
331
- output: getterOptions?.output,
332
- context: req?.context,
333
- APIOptions: api?.options
334
- });
335
- },
336
- set: (setterName = "", setterOptions = {}) => {
337
- return set({
338
- setterName,
339
- setterOptions: api?.setters[setterName] || {},
340
- input: setterOptions?.input,
341
- output: setterOptions?.output,
342
- context: req?.context,
343
- APIOptions: api?.options
344
- });
345
- }
346
- };
347
- } catch (exception) {
348
- throw new Error(`[ssr.getAPIForDataFunctions] ${exception.message}`);
349
- }
350
- };
351
315
  const validateOptions = (options) => {
352
316
  try {
353
317
  if (!options)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joystick.js/node-canary",
3
- "version": "0.0.0-canary.8",
3
+ "version": "0.0.0-canary.80",
4
4
  "type": "module",
5
5
  "description": "A Node.js framework for building web apps.",
6
6
  "main": "./dist/index.js",
@@ -38,6 +38,7 @@
38
38
  "node-html-parser": "^5.1.0",
39
39
  "nodemailer": "^6.7.0",
40
40
  "pg": "^8.7.3",
41
+ "pg-escape": "^0.2.0",
41
42
  "process": "^0.11.10",
42
43
  "query-string": "^7.0.1",
43
44
  "sanitize-html": "^2.7.3",
@@ -1,123 +0,0 @@
1
- import { jest } from "@jest/globals";
2
- import { killPortProcess } from "kill-port-process";
3
- import setAppSettingsForTest from "../../../tests/lib/setAppSettingsForTest";
4
- import startTestDatabase from "../../../tests/lib/databases/start";
5
- import stopTestDatabase from "../../../tests/lib/databases/stop";
6
- import { beforeEach, expect, test } from "@jest/globals";
7
- import roles from "./index";
8
- import accounts from "../index";
9
- jest.mock("../../../../node_modules/dayjs", () => {
10
- const _dayjs = jest.requireActual("../../../../node_modules/dayjs");
11
- const _utc = jest.requireActual("../../../../node_modules/dayjs/plugin/utc");
12
- _dayjs.extend(_utc);
13
- return () => _dayjs("2022-01-01T00:00:00.000Z");
14
- });
15
- setAppSettingsForTest({
16
- "config": {
17
- "databases": [
18
- {
19
- "provider": "mongodb",
20
- "users": true,
21
- "options": {}
22
- }
23
- ],
24
- "i18n": {
25
- "defaultLanguage": "en-US"
26
- },
27
- "middleware": {},
28
- "email": {
29
- "from": "app@test.com",
30
- "smtp": {
31
- "host": "fake.email.com",
32
- "port": 587,
33
- "username": "test",
34
- "password": "password"
35
- }
36
- }
37
- },
38
- "global": {},
39
- "public": {},
40
- "private": {}
41
- });
42
- global.joystick = {
43
- settings: {
44
- config: {
45
- databases: [{
46
- "provider": "mongodb",
47
- "users": true,
48
- "options": {}
49
- }]
50
- }
51
- }
52
- };
53
- const app = (await import("../../index")).default;
54
- let instance;
55
- describe("app/accounts/roles/index.js", () => {
56
- beforeAll(async () => {
57
- process.env.PORT = 3600;
58
- });
59
- beforeEach(async () => {
60
- instance = await app({});
61
- });
62
- afterEach(async () => {
63
- if (instance?.server?.close && typeof instance.server.close === "function") {
64
- instance.server.close();
65
- }
66
- await killPortProcess(process.env.PORT);
67
- });
68
- afterAll(async () => {
69
- });
70
- test("roles.add adds role to roles collection in database", async () => {
71
- await roles.add("admin");
72
- const roleExists = await process.databases.mongodb.collection("roles").findOne({ role: "admin" });
73
- expect(!!roleExists).toBe(true);
74
- });
75
- test("roles.remove removes role from roles collection in database", async () => {
76
- await roles.add("admin");
77
- await roles.remove("admin");
78
- const roleExists = await process.databases.mongodb.collection("roles").findOne({ role: "admin" });
79
- expect(!!roleExists).toBe(false);
80
- });
81
- test("roles.list returns a list of roles in the roles collection in database", async () => {
82
- await roles.add("admin");
83
- await roles.add("manager");
84
- await roles.add("employee");
85
- const rolesInDatabase = await roles.list();
86
- await roles.remove("admin");
87
- await roles.remove("manager");
88
- await roles.remove("employee");
89
- expect(rolesInDatabase).toEqual(["admin", "manager", "employee"]);
90
- });
91
- test("roles.grant adds role to user in users collection in database", async () => {
92
- await process.databases.mongodb.collection("users").deleteOne({ emailAddress: "test@test.com" });
93
- const user = await accounts.signup({ emailAddress: "test@test.com", password: "password" });
94
- await roles.grant(user?.userId, "admin");
95
- await roles.grant(user?.userId, "rolethatdoesntexist");
96
- const userAfterGrant = await process.databases.mongodb.collection("users").findOne({ _id: user?.userId });
97
- const rolesCreated = await process.databases.mongodb.collection("roles").find().toArray();
98
- expect(userAfterGrant?.roles?.includes("admin")).toBe(true);
99
- expect(rolesCreated?.length).toBe(2);
100
- });
101
- test("roles.revoke removes role from user in users collection in database", async () => {
102
- await process.databases.mongodb.collection("users").deleteOne({ emailAddress: "test@test.com" });
103
- const user = await accounts.signup({ emailAddress: "test@test.com", password: "password" });
104
- await roles.grant(user?.userId, "admin");
105
- await roles.revoke(user?.userId, "admin");
106
- const userAfterGrant = await process.databases.mongodb.collection("users").findOne({ _id: user?.userId });
107
- expect(userAfterGrant?.roles?.includes("admin")).toBe(false);
108
- });
109
- test("roles.userHasRole returns true if user has role", async () => {
110
- await process.databases.mongodb.collection("users").deleteOne({ emailAddress: "test@test.com" });
111
- const user = await accounts.signup({ emailAddress: "test@test.com", password: "password" });
112
- await roles.grant(user?.userId, "admin");
113
- const userHasRole = await roles.userHasRole(user?.userId, "admin");
114
- expect(userHasRole).toBe(true);
115
- });
116
- test("roles.userHasRole returns false if user does not have role", async () => {
117
- await process.databases.mongodb.collection("users").deleteOne({ emailAddress: "test@test.com" });
118
- const user = await accounts.signup({ emailAddress: "test@test.com", password: "password" });
119
- await roles.grant(user?.userId, "admin");
120
- const userHasRole = await roles.userHasRole(user?.userId, "manager");
121
- expect(userHasRole).toBe(false);
122
- });
123
- });