@joystick.js/node-canary 0.0.0-canary.32 → 0.0.0-canary.321
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.
- package/_package.json +2 -3
- package/dist/action/class.js +21 -0
- package/dist/api/get.js +15 -13
- package/dist/api/set.js +15 -13
- package/dist/app/accounts/createMetadataTableColumns.js +12 -0
- package/dist/app/accounts/deleteUser.js +7 -0
- package/dist/app/accounts/generateSession.js +2 -4
- package/dist/app/accounts/getBrowserSafeUser.js +5 -2
- package/dist/app/accounts/hasLoginTokenExpired.js +1 -2
- package/dist/app/accounts/index.js +2 -0
- package/dist/app/accounts/login.js +6 -0
- package/dist/app/accounts/recoverPassword.js +3 -0
- package/dist/app/accounts/resetPassword.js +6 -0
- package/dist/app/accounts/signup.js +50 -7
- package/dist/app/accounts/verifyEmail.js +3 -0
- package/dist/app/cluster.js +26 -0
- package/dist/app/databases/generate_sql_from_object.js +60 -0
- package/dist/app/databases/mongodb/buildConnectionString.js +1 -1
- package/dist/app/databases/mongodb/createAccountsIndexes.js +18 -0
- package/dist/app/databases/mongodb/createSessionsIndexes.js +10 -0
- package/dist/app/databases/mongodb/index.js +1 -1
- package/dist/app/databases/mongodb/queries/accounts.js +8 -1
- package/dist/app/databases/mongodb/queries/queues.js +40 -26
- package/dist/app/databases/mongodb/queries/sessions.js +26 -0
- package/dist/app/databases/postgresql/createSessionsIndexes.js +10 -0
- package/dist/app/databases/postgresql/createSessionsTables.js +14 -0
- package/dist/app/databases/postgresql/handleCleanupQueues.js +35 -0
- package/dist/app/databases/postgresql/index.js +88 -2
- package/dist/app/databases/postgresql/queries/accounts.js +5 -2
- package/dist/app/databases/postgresql/queries/queues.js +71 -37
- package/dist/app/databases/postgresql/queries/sessions.js +43 -0
- package/dist/app/databases/queryMap.js +6 -2
- package/dist/app/databases/stringToSnakeCase.js +6 -0
- package/dist/app/getBrowserSafeRequest.js +3 -2
- package/dist/app/index.js +226 -75
- package/dist/app/initExpress.js +1 -1
- package/dist/app/middleware/csp.js +2 -2
- package/dist/app/middleware/getTranslations.js +64 -0
- package/dist/app/middleware/get_insecure_landing_page_html.js +71 -0
- package/dist/app/middleware/hmr/client.js +13 -9
- package/dist/app/middleware/index.js +6 -5
- package/dist/app/middleware/insecure.js +3 -4
- package/dist/app/middleware/render.js +11 -68
- package/dist/app/middleware/session.js +12 -11
- package/dist/app/queues/index.js +64 -28
- package/dist/app/registerGetters.js +5 -6
- package/dist/app/registerSetters.js +5 -6
- package/dist/app/runGetter.js +17 -5
- package/dist/app/runSessionQuery.js +15 -0
- package/dist/app/runSetter.js +17 -5
- package/dist/app/sanitizeAPIResponse.js +1 -1
- package/dist/app/validateInstanceToken.js +16 -0
- package/dist/app/validateSession.js +8 -3
- package/dist/app/validateUploaderOptions.js +3 -3
- package/dist/app/validateUploads.js +12 -1
- package/dist/email/send.js +7 -1
- package/dist/email/templates/reset-password.js +0 -1
- package/dist/fixture/index.js +40 -0
- package/dist/index.js +19 -0
- package/dist/lib/escapeKeyValuePair.js +13 -0
- package/dist/lib/formatAPIError.js +0 -1
- package/dist/lib/getBuildPath.js +1 -1
- package/dist/lib/getSSLCertificates.js +3 -3
- package/dist/lib/importFile.js +7 -0
- package/dist/lib/isValidJSONString.js +1 -1
- package/dist/lib/log.js +0 -3
- package/dist/lib/objectToSQLKeysString.js +1 -1
- package/dist/lib/objectToSQLValuesString.js +1 -1
- package/dist/lib/serializeQueryParameters.js +1 -1
- package/dist/lib/timestamps.js +47 -0
- package/dist/lib/wait.js +8 -0
- package/dist/push/logs/index.js +32 -17
- package/dist/settings/load.js +3 -5
- package/dist/ssr/compileCSS.js +4 -4
- package/dist/ssr/findComponentInTree.js +1 -1
- package/dist/ssr/getAPIForDataFunctions.js +35 -0
- package/dist/ssr/getDataFromComponent.js +15 -0
- package/dist/ssr/index.js +19 -45
- package/dist/ssr/replaceWhenTags.js +2 -3
- package/dist/ssr/setHeadTagsInHTML.js +3 -3
- package/dist/test/index.js +9 -0
- package/dist/test/trackFunctionCall.js +17 -0
- package/dist/validation/inputWithSchema/index.js +3 -3
- package/dist/validation/schema/index.js +5 -5
- package/dist/websockets/index.js +4 -0
- package/getSanitizedContext.js +43 -0
- package/package.json +2 -2
- package/dist/app/accounts/roles/index.test.js +0 -123
- package/dist/app/index.test.js +0 -575
- package/dist/app/middleware/sanitizeRequestParameters.js +0 -26
- package/dist/email/send.test.js +0 -37
- package/dist/validation/index.test.js +0 -463
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,
|
|
@@ -25,9 +25,8 @@ const flattenAndReplaceWhenElements = (dom = {}, options = {}) => {
|
|
|
25
25
|
};
|
|
26
26
|
var replaceWhenTags_default = (html = "") => {
|
|
27
27
|
try {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
return dom.toString();
|
|
28
|
+
const whenRegex = new RegExp("<when>|</when>", "g");
|
|
29
|
+
return html?.replace(whenRegex, "");
|
|
31
30
|
} catch (exception) {
|
|
32
31
|
throw new Error(`[ssr.replaceWhenTags] ${exception.message}`);
|
|
33
32
|
}
|
|
@@ -28,7 +28,7 @@ var setHeadTagsInHTML_default = (htmlString = "", head = null, req = {}) => {
|
|
|
28
28
|
const metaTag = head.tags.meta[currentMetaTag];
|
|
29
29
|
const existingTag = headTag.querySelector(`meta[name="${metaTag.name}"]`);
|
|
30
30
|
const newTag = htmlParser.parse(`<meta />`);
|
|
31
|
-
const metaTagEntries = Object.entries(metaTag);
|
|
31
|
+
const metaTagEntries = Object.entries(metaTag || {});
|
|
32
32
|
let currentMetaTagEntry = metaTagEntries.length;
|
|
33
33
|
while (currentMetaTagEntry--) {
|
|
34
34
|
const [attributeName, attributeValue] = metaTagEntries[currentMetaTagEntry];
|
|
@@ -47,7 +47,7 @@ var setHeadTagsInHTML_default = (htmlString = "", head = null, req = {}) => {
|
|
|
47
47
|
while (currentLinkTag--) {
|
|
48
48
|
const linkTag = head.tags.link[currentLinkTag];
|
|
49
49
|
const newTag = htmlParser.parse(`<link />`);
|
|
50
|
-
let linkTagEntries = Object.entries(linkTag);
|
|
50
|
+
let linkTagEntries = Object.entries(linkTag || {});
|
|
51
51
|
let currentLinkTagEntry = linkTagEntries.length;
|
|
52
52
|
while (currentLinkTagEntry--) {
|
|
53
53
|
const [attributeName, attributeValue] = linkTagEntries[currentLinkTagEntry];
|
|
@@ -61,7 +61,7 @@ var setHeadTagsInHTML_default = (htmlString = "", head = null, req = {}) => {
|
|
|
61
61
|
while (currentScriptTag--) {
|
|
62
62
|
const scriptTag = head.tags.script[currentScriptTag];
|
|
63
63
|
const newTag = htmlParser.parse(`<script><\/script>`);
|
|
64
|
-
let scriptTagEntries = Object.entries(scriptTag);
|
|
64
|
+
let scriptTagEntries = Object.entries(scriptTag || {});
|
|
65
65
|
let currentScriptTagEntry = scriptTagEntries.length;
|
|
66
66
|
while (currentScriptTagEntry--) {
|
|
67
67
|
const [attributeName, attributeValue] = scriptTagEntries[currentScriptTagEntry];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
var trackFunctionCall_default = (path = "", args = []) => {
|
|
2
|
+
if (process.env.NODE_ENV === "test") {
|
|
3
|
+
process.test = {
|
|
4
|
+
...process.test || {},
|
|
5
|
+
functionCalls: {
|
|
6
|
+
...process?.test?.functionCalls || {},
|
|
7
|
+
[path]: [
|
|
8
|
+
...process?.test?.functionCalls && process?.test?.functionCalls[path] || [],
|
|
9
|
+
{ calledAt: new Date().toISOString(), args }
|
|
10
|
+
]
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
trackFunctionCall_default as default
|
|
17
|
+
};
|
|
@@ -47,7 +47,7 @@ const addToValidationQueue = (queue = [], schema = {}, input = {}, parentPath =
|
|
|
47
47
|
}
|
|
48
48
|
const rulesOnlySchema = !!(schema.type && constants.types.includes(schema.type));
|
|
49
49
|
if (!rulesOnlySchema) {
|
|
50
|
-
Object.entries(schema).forEach(([field, rules]) => {
|
|
50
|
+
Object.entries(schema || {}).forEach(([field, rules]) => {
|
|
51
51
|
const path = `${parentPath ? `${parentPath}.${field}` : field}`;
|
|
52
52
|
const validationTask = addValidationTask({
|
|
53
53
|
queue,
|
|
@@ -77,12 +77,12 @@ const validateInputWithSchema = async (input = null, schema = null, parentPath =
|
|
|
77
77
|
if (!input) {
|
|
78
78
|
errors.push("Input is required.");
|
|
79
79
|
}
|
|
80
|
-
if (schema && Object.keys(schema) && !schema.type) {
|
|
80
|
+
if (schema && Object.keys(schema || {}) && !schema.type) {
|
|
81
81
|
validateSchema(schema);
|
|
82
82
|
}
|
|
83
83
|
const queue = addToValidationQueue([], schema, input, parentPath);
|
|
84
84
|
await Promise.all(queue.flatMap((validationTask) => {
|
|
85
|
-
return Object.entries(validationTask.rules).flatMap(async ([ruleName, ruleValue]) => {
|
|
85
|
+
return Object.entries(validationTask.rules || {}).flatMap(async ([ruleName, ruleValue]) => {
|
|
86
86
|
const validator = constants.rules[ruleName];
|
|
87
87
|
if (validator && !validationTask.path.includes(".$.")) {
|
|
88
88
|
const result = await validator(ruleValue, validationTask.inputValue, validationTask.path);
|
|
@@ -2,16 +2,16 @@ import throwError from "../lib/throwError";
|
|
|
2
2
|
import { isObject } from "../lib/typeValidators";
|
|
3
3
|
import constants from "../lib/constants";
|
|
4
4
|
const validateRuleType = (schema) => {
|
|
5
|
-
Object.entries(schema).forEach(([field, rules]) => {
|
|
5
|
+
Object.entries(schema || {}).forEach(([field, rules]) => {
|
|
6
6
|
if (rules && rules.type && !constants.types.includes(rules.type)) {
|
|
7
7
|
throw new Error(`Invalid value for schema field "${field}" type rule. ${rules.type} is not supported. Use one of the following: ${constants.types.slice(0, constants.types.length - 1).join(", ")}, or ${constants.types[constants.types.length - 1]}.`);
|
|
8
8
|
}
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
const validateRuleNames = (schema) => {
|
|
12
|
-
Object.entries(schema).forEach(([field, rules]) => {
|
|
13
|
-
Object.keys(rules).forEach((ruleName) => {
|
|
14
|
-
const ruleNames = Object.keys(constants.rules);
|
|
12
|
+
Object.entries(schema || {}).forEach(([field, rules]) => {
|
|
13
|
+
Object.keys(rules || {}).forEach((ruleName) => {
|
|
14
|
+
const ruleNames = Object.keys(constants.rules || {});
|
|
15
15
|
if (!ruleNames.includes(ruleName)) {
|
|
16
16
|
throw new Error(`Invalid rule name ${ruleName} in rule for ${field} field.`);
|
|
17
17
|
}
|
|
@@ -19,7 +19,7 @@ const validateRuleNames = (schema) => {
|
|
|
19
19
|
});
|
|
20
20
|
};
|
|
21
21
|
const validateRulesAreObjects = (schema) => {
|
|
22
|
-
Object.entries(schema).forEach(([field, rules]) => {
|
|
22
|
+
Object.entries(schema || {}).forEach(([field, rules]) => {
|
|
23
23
|
if (!isObject(rules)) {
|
|
24
24
|
throw new Error(`Must pass an object containing rules to validate by for ${field} field.`);
|
|
25
25
|
}
|
package/dist/websockets/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import emitWebsocketEvent from "./emitWebsocketEvent";
|
|
2
|
+
import trackFunctionCall from "../test/trackFunctionCall.js";
|
|
2
3
|
var websockets_default = (serverName = "") => {
|
|
3
4
|
return {
|
|
4
5
|
send: (payload = {}, uniqueConnectionId = "") => {
|
|
5
6
|
const emitterName = uniqueConnectionId ? `${serverName}_${uniqueConnectionId}` : serverName;
|
|
7
|
+
trackFunctionCall(`node.websockets.${serverName}.send`, [
|
|
8
|
+
payload
|
|
9
|
+
]);
|
|
6
10
|
emitWebsocketEvent(emitterName, "message", payload);
|
|
7
11
|
}
|
|
8
12
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export default (context = {}) => {
|
|
2
|
+
const sanitizedContext = { ...context };
|
|
3
|
+
|
|
4
|
+
if (sanitizedContext?.req) {
|
|
5
|
+
delete sanitizedContext.req;
|
|
6
|
+
sanitizedContext.req = {
|
|
7
|
+
method: context?.req?.method,
|
|
8
|
+
headers: context?.req?.headers,
|
|
9
|
+
url: context?.req?.url,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (sanitizedContext?.res) {
|
|
14
|
+
delete sanitizedContext.res;
|
|
15
|
+
sanitizedContext.res = {
|
|
16
|
+
method: context?.res?.method,
|
|
17
|
+
headers: context?.res?.headers,
|
|
18
|
+
url: context?.res?.url,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (sanitizedContext.mongodb) {
|
|
23
|
+
delete sanitizedContext.mongodb;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (sanitizedContext.postgresql) {
|
|
27
|
+
delete sanitizedContext.postgresql;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (sanitizedContext.redis) {
|
|
31
|
+
delete sanitizedContext.redis;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (sanitizedContext._users) {
|
|
35
|
+
delete sanitizedContext._users;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (sanitizedContext._queues) {
|
|
39
|
+
delete sanitizedContext._queues;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return sanitizedContext;
|
|
43
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joystick.js/node-canary",
|
|
3
|
-
"version": "0.0.0-canary.
|
|
3
|
+
"version": "0.0.0-canary.321",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A Node.js framework for building web apps.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
"author": "",
|
|
17
17
|
"license": "SAUCR",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@tuskdb/node": "^0.11.0",
|
|
20
19
|
"aws-sdk": "^2.1046.0",
|
|
21
20
|
"bcrypt": "^5.0.1",
|
|
22
21
|
"chalk": "^4.1.2",
|
|
@@ -38,6 +37,7 @@
|
|
|
38
37
|
"node-html-parser": "^5.1.0",
|
|
39
38
|
"nodemailer": "^6.7.0",
|
|
40
39
|
"pg": "^8.7.3",
|
|
40
|
+
"pg-escape": "^0.2.0",
|
|
41
41
|
"process": "^0.11.10",
|
|
42
42
|
"query-string": "^7.0.1",
|
|
43
43
|
"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
|
-
});
|