@joystick.js/node-canary 0.0.0-canary.31 → 0.0.0-canary.310

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 (91) hide show
  1. package/_package.json +2 -2
  2. package/dist/action/class.js +21 -0
  3. package/dist/api/get.js +15 -13
  4. package/dist/api/set.js +15 -13
  5. package/dist/app/accounts/createMetadataTableColumns.js +12 -0
  6. package/dist/app/accounts/deleteUser.js +7 -0
  7. package/dist/app/accounts/generateSession.js +2 -4
  8. package/dist/app/accounts/getBrowserSafeUser.js +5 -2
  9. package/dist/app/accounts/hasLoginTokenExpired.js +1 -2
  10. package/dist/app/accounts/index.js +2 -0
  11. package/dist/app/accounts/login.js +6 -0
  12. package/dist/app/accounts/recoverPassword.js +3 -0
  13. package/dist/app/accounts/resetPassword.js +6 -0
  14. package/dist/app/accounts/signup.js +50 -7
  15. package/dist/app/accounts/verifyEmail.js +3 -0
  16. package/dist/app/cluster.js +26 -0
  17. package/dist/app/databases/generate_sql_from_object.js +45 -0
  18. package/dist/app/databases/mongodb/buildConnectionString.js +1 -1
  19. package/dist/app/databases/mongodb/createAccountsIndexes.js +18 -0
  20. package/dist/app/databases/mongodb/createSessionsIndexes.js +10 -0
  21. package/dist/app/databases/mongodb/index.js +1 -1
  22. package/dist/app/databases/mongodb/queries/accounts.js +8 -1
  23. package/dist/app/databases/mongodb/queries/queues.js +40 -26
  24. package/dist/app/databases/mongodb/queries/sessions.js +26 -0
  25. package/dist/app/databases/postgresql/createSessionsIndexes.js +10 -0
  26. package/dist/app/databases/postgresql/createSessionsTables.js +14 -0
  27. package/dist/app/databases/postgresql/handleCleanupQueues.js +35 -0
  28. package/dist/app/databases/postgresql/index.js +66 -4
  29. package/dist/app/databases/postgresql/queries/accounts.js +5 -2
  30. package/dist/app/databases/postgresql/queries/queues.js +69 -36
  31. package/dist/app/databases/postgresql/queries/sessions.js +43 -0
  32. package/dist/app/databases/queryMap.js +6 -2
  33. package/dist/app/databases/stringToSnakeCase.js +6 -0
  34. package/dist/app/getBrowserSafeRequest.js +3 -2
  35. package/dist/app/index.js +222 -75
  36. package/dist/app/initExpress.js +1 -1
  37. package/dist/app/middleware/csp.js +2 -2
  38. package/dist/app/middleware/getTranslations.js +64 -0
  39. package/dist/app/middleware/get_insecure_landing_page_html.js +71 -0
  40. package/dist/app/middleware/hmr/client.js +13 -9
  41. package/dist/app/middleware/index.js +6 -5
  42. package/dist/app/middleware/insecure.js +3 -4
  43. package/dist/app/middleware/render.js +11 -68
  44. package/dist/app/middleware/session.js +12 -11
  45. package/dist/app/queues/index.js +64 -28
  46. package/dist/app/registerGetters.js +5 -6
  47. package/dist/app/registerSetters.js +5 -6
  48. package/dist/app/runGetter.js +17 -5
  49. package/dist/app/runSessionQuery.js +15 -0
  50. package/dist/app/runSetter.js +17 -5
  51. package/dist/app/sanitizeAPIResponse.js +1 -1
  52. package/dist/app/validateSession.js +8 -3
  53. package/dist/app/validateUploaderOptions.js +3 -3
  54. package/dist/app/validateUploads.js +12 -1
  55. package/dist/email/send.js +7 -1
  56. package/dist/email/templates/reset-password.js +0 -1
  57. package/dist/fixture/index.js +40 -0
  58. package/dist/index.js +19 -0
  59. package/dist/lib/escapeKeyValuePair.js +13 -0
  60. package/dist/lib/formatAPIError.js +0 -1
  61. package/dist/lib/getBuildPath.js +1 -1
  62. package/dist/lib/getSSLCertificates.js +3 -3
  63. package/dist/lib/importFile.js +7 -0
  64. package/dist/lib/isValidJSONString.js +1 -1
  65. package/dist/lib/log.js +0 -3
  66. package/dist/lib/objectToSQLKeysString.js +1 -1
  67. package/dist/lib/objectToSQLValuesString.js +1 -1
  68. package/dist/lib/serializeQueryParameters.js +1 -1
  69. package/dist/lib/timestamps.js +47 -0
  70. package/dist/lib/wait.js +8 -0
  71. package/dist/push/logs/index.js +10 -3
  72. package/dist/settings/load.js +3 -5
  73. package/dist/ssr/compileCSS.js +4 -4
  74. package/dist/ssr/findComponentInTree.js +1 -1
  75. package/dist/ssr/getAPIForDataFunctions.js +35 -0
  76. package/dist/ssr/getDataFromComponent.js +15 -0
  77. package/dist/ssr/index.js +19 -45
  78. package/dist/ssr/replaceWhenTags.js +2 -3
  79. package/dist/ssr/setHeadTagsInHTML.js +3 -3
  80. package/dist/test/index.js +9 -0
  81. package/dist/test/trackFunctionCall.js +17 -0
  82. package/dist/validation/inputWithSchema/index.js +3 -3
  83. package/dist/validation/schema/index.js +5 -5
  84. package/dist/websockets/index.js +4 -0
  85. package/getSanitizedContext.js +43 -0
  86. package/package.json +2 -1
  87. package/dist/app/accounts/roles/index.test.js +0 -123
  88. package/dist/app/index.test.js +0 -575
  89. package/dist/app/middleware/sanitizeRequestParameters.js +0 -21
  90. package/dist/email/send.test.js +0 -37
  91. package/dist/validation/index.test.js +0 -463
@@ -1,4 +1,5 @@
1
1
  import log from "../lib/log";
2
+ import trackFunctionCall from "../test/trackFunctionCall.js";
2
3
  const handleCheckUpload = ({
3
4
  uploaderName,
4
5
  maxSizeInMegabytes,
@@ -49,6 +50,16 @@ const formatUploads = ({
49
50
  try {
50
51
  return Promise.all(uploads.map(async (upload) => {
51
52
  const fileExtension = upload?.mimeType?.split("/").pop();
53
+ const fileNameIsFunction = typeof uploaderOptions?.fileName === "function";
54
+ if (fileNameIsFunction) {
55
+ trackFunctionCall(`node.uploaders.${uploaderName}.fileName`, [{
56
+ input,
57
+ fileName: upload?.originalname,
58
+ fileSize: upload?.size,
59
+ fileExtension,
60
+ mimeType: upload?.mimetype
61
+ }]);
62
+ }
52
63
  return {
53
64
  uploaderName,
54
65
  providers: uploaderOptions?.providers,
@@ -56,7 +67,7 @@ const formatUploads = ({
56
67
  s3: uploaderOptions?.s3,
57
68
  maxSizeInMegabytes: typeof uploaderOptions?.maxSizeInMegabytes === "function" ? await uploaderOptions?.maxSizeInMegabytes({ input, upload }) : uploaderOptions?.maxSizeInMegabytes,
58
69
  mimeTypes: uploaderOptions?.mimeTypes,
59
- fileName: typeof uploaderOptions?.fileName === "function" ? uploaderOptions.fileName({ input, fileName: upload?.originalname, fileSize: upload?.size, fileExtension, mimeType: upload?.mimetype }) : upload?.originalname,
70
+ fileName: fileNameIsFunction ? uploaderOptions.fileName({ input, fileName: upload?.originalname, fileSize: upload?.size, fileExtension, mimeType: upload?.mimetype }) : upload?.originalname,
60
71
  originalFileName: upload?.originalname,
61
72
  fileSize: upload?.size,
62
73
  mimeType: upload?.mimetype,
@@ -7,7 +7,13 @@ import settings from "../settings";
7
7
  import validateSMTPSettings from "./validateSMTPSettings";
8
8
  import render from "./render";
9
9
  import getBuildPath from "../lib/getBuildPath";
10
- var send_default = async ({ template: templateName, props, base: baseName, ...restOfOptions }) => {
10
+ import trackFunctionCall from "../test/trackFunctionCall.js";
11
+ var send_default = async (args) => {
12
+ const { template: templateName, props, base: baseName, ...restOfOptions } = args;
13
+ if (process.env.NODE_ENV === "test") {
14
+ trackFunctionCall("node.email.send", [args]);
15
+ return;
16
+ }
11
17
  const validSMTPSettings = validateSMTPSettings(settings?.config?.email?.smtp);
12
18
  if (!validSMTPSettings) {
13
19
  console.warn(chalk.redBright("Cannot send email, invalid SMTP settings."));
@@ -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>
@@ -0,0 +1,40 @@
1
+ class Fixture {
2
+ constructor(options = {}) {
3
+ this.options = options;
4
+ this.quantity = options?.quantity;
5
+ this.run = this.run.bind(this);
6
+ return this.run;
7
+ }
8
+ async run(input = {}) {
9
+ this.input = input;
10
+ const skip = typeof this?.options?.skip === "function" ? await this.options.skip(this, input) : false;
11
+ let dataToCreate = [];
12
+ if (!skip) {
13
+ dataToCreate = await this.generateDataToCreate(input);
14
+ if (typeof this?.options?.onCreate === "function") {
15
+ await this.options.onCreate(this, dataToCreate, (onAfterCreateEachInput = {}) => {
16
+ return this?.options?.onAfterCreateEach(this, onAfterCreateEachInput, input);
17
+ });
18
+ }
19
+ }
20
+ if (typeof this?.options?.onAfterCreateAll === "function") {
21
+ this.options.onAfterCreateAll(this, dataToCreate, input);
22
+ }
23
+ }
24
+ async generateDataToCreate(input = {}) {
25
+ const data = [];
26
+ for (let i = 0; i < this?.quantity; i += 1) {
27
+ if (typeof this?.options?.template === "function") {
28
+ const dataToCreate = await this.options?.template(this, i, input);
29
+ data.push(dataToCreate);
30
+ }
31
+ }
32
+ return data;
33
+ }
34
+ }
35
+ var fixture_default = (options = {}) => {
36
+ return new Fixture(options);
37
+ };
38
+ export {
39
+ fixture_default as default
40
+ };
package/dist/index.js CHANGED
@@ -4,22 +4,29 @@ import { dirname } from "path";
4
4
  import sanitizeHTML from "sanitize-html";
5
5
  import _accounts from "./app/accounts";
6
6
  import _action from "./action/index.js";
7
+ import _fixture from "./fixture/index.js";
8
+ import _test from "./test/index.js";
7
9
  import _websockets from "./websockets";
8
10
  import api from "./api/index.js";
9
11
  import app from "./app/index.js";
10
12
  import generateId from "./lib/generateId.js";
13
+ import _generate_sql_from_object from "./app/databases/generate_sql_from_object";
11
14
  import getOrigin from "./api/getOrigin";
12
15
  import loadSettings from "./settings/load";
13
16
  import pushLogs from "./push/logs/index.js";
14
17
  import nodeUrlPolyfills from "./lib/nodeUrlPolyfills.js";
15
18
  import sendEmail from "./email/send";
19
+ const { readFile } = fs.promises;
16
20
  if (process.env.NODE_ENV !== "development" && process.env.IS_PUSH_DEPLOYED) {
17
21
  pushLogs();
18
22
  }
23
+ const generate_sql_from_object = _generate_sql_from_object;
19
24
  const accounts = _accounts;
20
25
  const action = _action;
26
+ const fixture = _fixture;
21
27
  const get = api.get;
22
28
  const set = api.set;
29
+ const test = _test;
23
30
  const email = {
24
31
  send: sendEmail
25
32
  };
@@ -36,6 +43,11 @@ const __dirname = nodeUrlPolyfills.__dirname;
36
43
  const id = generateId;
37
44
  const origin = getOrigin();
38
45
  const settings = loadSettings();
46
+ const push = {
47
+ continent: fs.existsSync("/root/push/continent.txt") ? (await readFile("/root/push/continent.txt", "utf-8"))?.replace("\n", "") : null,
48
+ instance_token: fs.existsSync("/root/push/instance_token.txt") ? (await readFile("/root/push/instance_token.txt", "utf-8"))?.replace("\n", "") : null,
49
+ current_version: fs.existsSync("/root/push/versions/current") ? (await readFile("/root/push/versions/current", "utf-8"))?.replace("\n", "") : null
50
+ };
39
51
  global.joystick = {
40
52
  id: generateId,
41
53
  emitters: {},
@@ -51,9 +63,12 @@ var src_default = {
51
63
  action,
52
64
  app,
53
65
  email,
66
+ fixture,
67
+ generate_sql_from_object,
54
68
  get,
55
69
  id,
56
70
  origin,
71
+ push,
57
72
  sanitize,
58
73
  set,
59
74
  settings,
@@ -67,10 +82,14 @@ export {
67
82
  action,
68
83
  src_default as default,
69
84
  email,
85
+ fixture,
86
+ generate_sql_from_object,
70
87
  get,
71
88
  id,
72
89
  origin,
90
+ push,
73
91
  sanitize,
74
92
  set,
93
+ test,
75
94
  websockets
76
95
  };
@@ -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,4 +1,3 @@
1
- import getErrorObject from "./getErrorObject";
2
1
  var formatAPIError_default = (exception = {}, location = "", code = 0) => {
3
2
  return {
4
3
  code,
@@ -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 "";
@@ -1,12 +1,12 @@
1
1
  import fs from "fs";
2
2
  var getSSLCertificates_default = (ssl = null) => {
3
- const pushCertificatePath = "/lib/push/certs/cert.pem";
4
- const pushKeyPath = "/lib/push/certs/key.pem";
3
+ const pushCertificatePath = "/root/push/certs/cert.pem";
4
+ const pushKeyPath = "/root/push/certs/key.pem";
5
5
  const certPath = process.env.IS_PUSH_DEPLOYED ? pushCertificatePath : ssl?.cert || 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
+ };
@@ -1,10 +1,10 @@
1
1
  var isValidJSONString_default = (JSONString = "") => {
2
2
  try {
3
3
  JSON.parse(JSONString);
4
+ return true;
4
5
  } catch (error) {
5
6
  return false;
6
7
  }
7
- return true;
8
8
  };
9
9
  export {
10
10
  isValidJSONString_default as default
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,7 +1,7 @@
1
1
  import { isObject } from "../validation/lib/typeValidators";
2
2
  import camelPascalToSnake from "./camelPascalToSnake";
3
3
  const objectToSQLKeys = (objectToConvert = {}, target = []) => {
4
- const keyValuePairs = Object.entries(objectToConvert);
4
+ const keyValuePairs = Object.entries(objectToConvert || {});
5
5
  keyValuePairs.forEach(([key, value]) => {
6
6
  if (isObject(value)) {
7
7
  target.push(camelPascalToSnake(key));
@@ -1,6 +1,6 @@
1
1
  import { isObject } from "../validation/lib/typeValidators";
2
2
  const objectToSQLValues = (objectToConvert = {}, target = []) => {
3
- const keyValuePairs = Object.entries(objectToConvert);
3
+ const keyValuePairs = Object.entries(objectToConvert || {});
4
4
  keyValuePairs.forEach(([_key, value]) => {
5
5
  if (isObject(value)) {
6
6
  objectToSQLValues(value, target);
@@ -1,5 +1,5 @@
1
1
  var serializeQueryParameters_default = (queryParameters = {}) => {
2
- return Object.entries(queryParameters).map(([key, value]) => {
2
+ return Object.entries(queryParameters || {}).map(([key, value]) => {
3
3
  return `${key}=${value}`;
4
4
  })?.join("&");
5
5
  };
@@ -0,0 +1,47 @@
1
+ var timestamps_default = {
2
+ get_current_time: (options2 = {}) => {
3
+ const timestamp = new Date().toISOString();
4
+ return options2?.mongodb_ttl ? new Date(timestamp) : timestamp;
5
+ },
6
+ get_future_time: (unit = "", quantity = 0, options2 = {}) => {
7
+ const date = new Date();
8
+ switch (unit) {
9
+ case "seconds":
10
+ date.setSeconds(date.getSeconds() + quantity);
11
+ return options2?.mongodb_ttl ? new Date(date.toISOString()) : date.toISOString();
12
+ case "minutes":
13
+ date.setMinutes(date.getMinutes() + quantity);
14
+ return options2?.mongodb_ttl ? new Date(date.toISOString()) : date.toISOString();
15
+ case "hours":
16
+ date.setHours(date.getHours() + quantity);
17
+ return options2?.mongodb_ttl ? new Date(date.toISOString()) : date.toISOString();
18
+ case "days":
19
+ date.setHours(date.getHours() + quantity * 24);
20
+ return options2?.mongodb_ttl ? new Date(date.toISOString()) : date.toISOString();
21
+ default:
22
+ return options2?.mongodb_ttl ? new Date(date.toISOString()) : date.toISOString();
23
+ }
24
+ },
25
+ get_past_time: (unit = "", quantity = 0) => {
26
+ const date = new Date();
27
+ switch (unit) {
28
+ case "seconds":
29
+ date.setSeconds(date.getSeconds() - quantity);
30
+ return options?.mongodb_ttl ? new Date(date.toISOString()) : date.toISOString();
31
+ case "minutes":
32
+ date.setMinutes(date.getMinutes() - quantity);
33
+ return options?.mongodb_ttl ? new Date(date.toISOString()) : date.toISOString();
34
+ case "hours":
35
+ date.setHours(date.getHours() - quantity);
36
+ return options?.mongodb_ttl ? new Date(date.toISOString()) : date.toISOString();
37
+ case "days":
38
+ date.setHours(date.getHours() - quantity * 24);
39
+ return options?.mongodb_ttl ? new Date(date.toISOString()) : date.toISOString();
40
+ default:
41
+ return options?.mongodb_ttl ? new Date(new Date().toISOString()) : new Date().toISOString();
42
+ }
43
+ }
44
+ };
45
+ export {
46
+ timestamps_default as default
47
+ };
@@ -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
+ };
@@ -1,5 +1,6 @@
1
1
  import dayjs from "dayjs";
2
2
  import TuskDB from "@tuskdb/node";
3
+ import timestamps from "../../lib/timestamps";
3
4
  const captureLog = (callback = null) => {
4
5
  process.stdout.write = (data) => {
5
6
  if (callback) {
@@ -13,7 +14,12 @@ const captureLog = (callback = null) => {
13
14
  };
14
15
  process.on("uncaughtException", (error) => {
15
16
  if (callback) {
16
- callback("uncaughtException", error);
17
+ callback("uncaughtException", error?.message || "Uncaught Exception");
18
+ }
19
+ });
20
+ process.on("unhandledRejection", (error) => {
21
+ if (callback) {
22
+ callback("unhandledRejection", error?.message || "Unhandled Rejection");
17
23
  }
18
24
  });
19
25
  };
@@ -21,6 +27,7 @@ const writeLogsToDisk = () => {
21
27
  const db = new TuskDB({
22
28
  file: {
23
29
  development: "logs.json",
30
+ staging: "/root/logs.json",
24
31
  production: "/root/logs.json"
25
32
  }[process.env.NODE_ENV || "development"],
26
33
  collections: {
@@ -32,14 +39,14 @@ const writeLogsToDisk = () => {
32
39
  case "stdout":
33
40
  return db.collection("logs").insertOne({
34
41
  error: false,
35
- timestamp: dayjs().format(),
42
+ timestamp: timestamps.get_current_time(),
36
43
  data
37
44
  });
38
45
  case "stderr":
39
46
  case "uncaughtException":
40
47
  return db.collection("logs").insertOne({
41
48
  error: true,
42
- timestamp: dayjs().format(),
49
+ timestamp: timestamps.get_current_time(),
43
50
  data
44
51
  });
45
52
  default:
@@ -1,11 +1,9 @@
1
1
  import isValidJSONString from "../lib/isValidJSONString";
2
2
  const defaultSettings = {
3
3
  config: {},
4
- keys: {
5
- global: {},
6
- public: {},
7
- private: {}
8
- }
4
+ global: {},
5
+ public: {},
6
+ private: {}
9
7
  };
10
8
  var load_default = () => {
11
9
  try {
@@ -30,7 +30,7 @@ var compileCSS_default = (css = "", componentInstance = {}) => {
30
30
  `;
31
31
  }
32
32
  if (hasMinRules && hasMinWidthRules) {
33
- const minWidthRules = Object.entries(css?.min?.width);
33
+ const minWidthRules = Object.entries(css?.min?.width || {});
34
34
  for (let i = 0; i < minWidthRules.length; i += 1) {
35
35
  const [minWidth, minWidthRule] = minWidthRules[i];
36
36
  compiledCSS += `
@@ -41,7 +41,7 @@ var compileCSS_default = (css = "", componentInstance = {}) => {
41
41
  }
42
42
  }
43
43
  if (hasMinRules && hasMinHeightRules) {
44
- const minHeightRules = Object.entries(css?.min?.height);
44
+ const minHeightRules = Object.entries(css?.min?.height || {});
45
45
  for (let i = 0; i < minHeightRules.length; i += 1) {
46
46
  const [minHeight, minHeightRule] = minHeightRules[i];
47
47
  compiledCSS += `
@@ -52,7 +52,7 @@ var compileCSS_default = (css = "", componentInstance = {}) => {
52
52
  }
53
53
  }
54
54
  if (hasMaxRules && hasMaxWidthRules) {
55
- const maxWidthRules = Object.entries(css?.max?.width);
55
+ const maxWidthRules = Object.entries(css?.max?.width || {});
56
56
  for (let i = 0; i < maxWidthRules.length; i += 1) {
57
57
  const [maxWidth, maxWidthRule] = maxWidthRules[i];
58
58
  compiledCSS += `
@@ -63,7 +63,7 @@ var compileCSS_default = (css = "", componentInstance = {}) => {
63
63
  }
64
64
  }
65
65
  if (hasMaxRules && hasMaxHeightRules) {
66
- const maxHeightRules = Object.entries(css?.max?.height);
66
+ const maxHeightRules = Object.entries(css?.max?.height || {});
67
67
  for (let i = 0; i < maxHeightRules.length; i += 1) {
68
68
  const [maxHeight, maxHeightRule] = maxHeightRules[i];
69
69
  compiledCSS += `
@@ -4,7 +4,7 @@ const isObject = (value) => {
4
4
  const findComponentInTree = (tree = {}, componentId = "", callback = {}) => {
5
5
  const isTree = tree && tree.id;
6
6
  if (isObject(tree) && isTree) {
7
- const entries = Object.entries(tree);
7
+ const entries = Object.entries(tree || {});
8
8
  for (let i = 0; i < entries.length; i += 1) {
9
9
  const [treeKey, treeValue] = entries[i];
10
10
  if (treeKey === "id" && treeValue === componentId) {
@@ -0,0 +1,35 @@
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
+ skip: getterOptions?.skip,
11
+ input: getterOptions?.input,
12
+ output: getterOptions?.output,
13
+ context: req?.context,
14
+ APIOptions: api?.options
15
+ });
16
+ },
17
+ set: (setterName = "", setterOptions = {}) => {
18
+ return set({
19
+ setterName,
20
+ setterOptions: api?.setters[setterName] || {},
21
+ skip: setterOptions?.skip,
22
+ input: setterOptions?.input,
23
+ output: setterOptions?.output,
24
+ context: req?.context,
25
+ APIOptions: api?.options
26
+ });
27
+ }
28
+ };
29
+ } catch (exception) {
30
+ throw new Error(`[ssr.getAPIForDataFunctions] ${exception.message}`);
31
+ }
32
+ };
33
+ export {
34
+ getAPIForDataFunctions_default as default
35
+ };
@@ -0,0 +1,15 @@
1
+ var getDataFromComponent_default = async (componentInstance = {}, api = {}, browserSafeUser = {}, browserSafeRequest = {}) => {
2
+ try {
3
+ componentInstance.user = browserSafeUser;
4
+ const data = await componentInstance.handleFetchData(api, browserSafeRequest, {}, componentInstance);
5
+ return {
6
+ componentId: componentInstance?.id,
7
+ data
8
+ };
9
+ } catch (exception) {
10
+ throw new Error(`[ssr.getDataFromComponent] ${exception.message}`);
11
+ }
12
+ };
13
+ export {
14
+ getDataFromComponent_default as default
15
+ };
package/dist/ssr/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import fs from "fs";
2
- import { __package } from "../index.js";
2
+ import joystick, { __package } from "../index.js";
3
3
  import get from "../api/get";
4
4
  import set from "../api/set";
5
5
  import getBrowserSafeRequest from "../app/getBrowserSafeRequest";
@@ -8,6 +8,9 @@ import getCSSFromTree from "./getCSSFromTree";
8
8
  import replaceWhenTags from "./replaceWhenTags";
9
9
  import setHeadTagsInHTML from "./setHeadTagsInHTML";
10
10
  import { parseHTML } from "linkedom";
11
+ import getDataFromComponent from "./getDataFromComponent.js";
12
+ import getAPIForDataFunctions from "./getAPIForDataFunctions.js";
13
+ import getBrowserSafeUser from "../app/accounts/getBrowserSafeUser.js";
11
14
  const injectCSSIntoHTML = (html, baseCSS = "", css = "") => {
12
15
  try {
13
16
  return html.replace("${css}", css).replace("${globalCSS}", `<style>${baseCSS || ""}</style>`).replace("${componentCSS}", css);
@@ -21,6 +24,7 @@ const handleHTMLReplacementsForApp = ({
21
24
  componentInstance = {},
22
25
  dataFromComponent,
23
26
  dataForClient = {},
27
+ browserSafeUser = {},
24
28
  browserSafeRequest = {},
25
29
  props = {},
26
30
  translations = {},
@@ -44,9 +48,10 @@ const handleHTMLReplacementsForApp = ({
44
48
  window.__joystick_ssr__ = true;
45
49
  ${process.env.NODE_ENV === "development" ? `window.__joystick_hmr_port__ = ${parseInt(process.env.PORT, 10) + 1};` : ""}
46
50
  window.__joystick_data__ = ${JSON.stringify({
47
- [componentInstance.id]: dataFromComponent?.data || {},
51
+ [componentInstance.id]: dataFromComponent?.data,
48
52
  ...dataForClient || {}
49
53
  })};
54
+ window.__joystick_user__ = ${JSON.stringify(browserSafeUser)};
50
55
  window.__joystick_req__ = ${JSON.stringify(browserSafeRequest)};
51
56
  window.__joystick_ssr_props__ = ${JSON.stringify(props)};
52
57
  window.__joystick_i18n__ = ${JSON.stringify(translations)};
@@ -90,6 +95,7 @@ const getHTMLWithTargetReplacements = ({
90
95
  baseHTML = "",
91
96
  dataFromComponent = {},
92
97
  dataForClient = {},
98
+ browserSafeUser = {},
93
99
  browserSafeRequest = {},
94
100
  props = {},
95
101
  translations = {},
@@ -112,6 +118,7 @@ const getHTMLWithTargetReplacements = ({
112
118
  componentHTML,
113
119
  dataFromComponent,
114
120
  dataForClient,
121
+ browserSafeUser,
115
122
  browserSafeRequest,
116
123
  props,
117
124
  translations,
@@ -146,6 +153,7 @@ const processHTML = ({
146
153
  isEmailRender = false,
147
154
  emailSubject = "",
148
155
  emailPreheader = "",
156
+ browserSafeUser = {},
149
157
  browserSafeRequest = {},
150
158
  props = {},
151
159
  translations = {},
@@ -169,6 +177,7 @@ const processHTML = ({
169
177
  dataFromComponent,
170
178
  dataFromTree,
171
179
  dataForClient,
180
+ browserSafeUser,
172
181
  browserSafeRequest,
173
182
  props,
174
183
  translations,
@@ -200,7 +209,7 @@ const getBaseCSS = (baseHTMLName = "") => {
200
209
  };
201
210
  const addAttributesToDOM = (dom = {}, attributes = {}) => {
202
211
  try {
203
- const attributeKeys = Object.keys(attributes);
212
+ const attributeKeys = Object.keys(attributes || {});
204
213
  const attributeKeysWithoutClassList = attributeKeys?.filter((key) => key !== "class");
205
214
  if (Array.isArray(attributes?.class?.list)) {
206
215
  if (attributes?.class?.method === "replace") {
@@ -290,17 +299,6 @@ const buildTreeForComponent = (componentInstance = {}, ssrTree = {}, translation
290
299
  throw new Error(`[ssr.buildTreeForComponent] ${exception.message}`);
291
300
  }
292
301
  };
293
- const getDataFromComponent = async (componentInstance = {}, api = {}, browserSafeRequest = {}) => {
294
- try {
295
- const data = await componentInstance.handleFetchData(api, browserSafeRequest, {}, componentInstance);
296
- return {
297
- componentId: componentInstance?.id,
298
- data
299
- };
300
- } catch (exception) {
301
- throw new Error(`[ssr.getDataFromComponent] ${exception.message}`);
302
- }
303
- };
304
302
  const getTreeForSSR = (componentInstance = {}) => {
305
303
  try {
306
304
  return {
@@ -321,34 +319,6 @@ const getComponentInstance = (Component, options = {}) => {
321
319
  throw new Error(`[ssr.getComponentInstance] ${exception.message}`);
322
320
  }
323
321
  };
324
- const getAPIForDataFunctions = (req = {}, api = {}) => {
325
- try {
326
- return {
327
- get: (getterName = "", getterOptions = {}) => {
328
- return get({
329
- getterName,
330
- getterOptions: api?.getters[getterName] || {},
331
- input: getterOptions?.input,
332
- output: getterOptions?.output,
333
- context: req?.context,
334
- APIOptions: api?.options
335
- });
336
- },
337
- set: (setterName = "", setterOptions = {}) => {
338
- return set({
339
- setterName,
340
- setterOptions: api?.setters[setterName] || {},
341
- input: setterOptions?.input,
342
- output: setterOptions?.output,
343
- context: req?.context,
344
- APIOptions: api?.options
345
- });
346
- }
347
- };
348
- } catch (exception) {
349
- throw new Error(`[ssr.getAPIForDataFunctions] ${exception.message}`);
350
- }
351
- };
352
322
  const validateOptions = (options) => {
353
323
  try {
354
324
  if (!options)
@@ -363,6 +333,7 @@ const ssr = async (options, { resolve, reject }) => {
363
333
  try {
364
334
  validateOptions(options);
365
335
  const apiForDataFunctions = getAPIForDataFunctions(options.req, options?.api);
336
+ const browserSafeUser = getBrowserSafeUser(options?.req?.context?.user);
366
337
  const browserSafeRequest = options?.email ? {} : getBrowserSafeRequest({ ...options?.req || {} });
367
338
  const componentInstance = getComponentInstance(options.componentFunction, {
368
339
  props: options?.props || {},
@@ -371,13 +342,14 @@ const ssr = async (options, { resolve, reject }) => {
371
342
  api: apiForDataFunctions,
372
343
  req: browserSafeRequest
373
344
  });
345
+ componentInstance.user = browserSafeUser;
374
346
  const ssrTree = getTreeForSSR(componentInstance);
375
347
  const ssrTreeForCSS = getTreeForSSR(componentInstance);
376
- const dataFromComponent = await getDataFromComponent(componentInstance, apiForDataFunctions, browserSafeRequest).then((data) => data).catch((error) => {
348
+ const dataFromComponent = await getDataFromComponent(componentInstance, apiForDataFunctions, browserSafeUser, browserSafeRequest).then((data) => data).catch((error) => {
377
349
  return [{ error }];
378
350
  });
379
- buildTreeForComponent(componentInstance, ssrTree);
380
- buildTreeForComponent(componentInstance, ssrTreeForCSS);
351
+ buildTreeForComponent(componentInstance, ssrTree, options?.translations);
352
+ buildTreeForComponent(componentInstance, ssrTreeForCSS, options?.translations);
381
353
  const dataFromTree = await getDataFromTree(ssrTree).then((data) => data).catch((error) => {
382
354
  return [{ error }];
383
355
  });
@@ -397,6 +369,7 @@ const ssr = async (options, { resolve, reject }) => {
397
369
  isEmailRender: options?.email,
398
370
  emailSubject: options?.emailSubject,
399
371
  emailPreheader: options?.emailPreheader,
372
+ browserSafeUser,
400
373
  browserSafeRequest,
401
374
  props: options?.props,
402
375
  translations: options?.translations,
@@ -417,6 +390,7 @@ const ssr = async (options, { resolve, reject }) => {
417
390
  isEmailRender: options?.email,
418
391
  emailSubject: options?.emailSubject,
419
392
  emailPreheader: options?.emailPreheader,
393
+ browserSafeUser,
420
394
  browserSafeRequest,
421
395
  props: options?.props,
422
396
  translations: options?.translations,