@joystick.js/node-canary 0.0.0-canary.33 → 0.0.0-canary.331
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 +51 -28
- 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 +36 -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 +83 -38
- 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 +229 -78
- 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 +8 -66
- package/dist/app/middleware/session.js +12 -11
- package/dist/app/queues/index.js +82 -32
- 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 +35 -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
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import mongodbAccountsQueries from "./mongodb/queries/accounts";
|
|
2
2
|
import mongodbQueuesQueries from "./mongodb/queries/queues";
|
|
3
|
+
import mongodbSessionsQueries from "./mongodb/queries/sessions";
|
|
3
4
|
import postgresqlAccountsQueries from "./postgresql/queries/accounts";
|
|
4
5
|
import postgresqlQueuesQueries from "./postgresql/queries/queues";
|
|
6
|
+
import postgresqlSessionsQueries from "./postgresql/queries/sessions";
|
|
5
7
|
var queryMap_default = {
|
|
6
8
|
mongodb: {
|
|
7
9
|
accounts: mongodbAccountsQueries,
|
|
8
|
-
queues: mongodbQueuesQueries
|
|
10
|
+
queues: mongodbQueuesQueries,
|
|
11
|
+
sessions: mongodbSessionsQueries
|
|
9
12
|
},
|
|
10
13
|
postgresql: {
|
|
11
14
|
accounts: postgresqlAccountsQueries,
|
|
12
|
-
queues: postgresqlQueuesQueries
|
|
15
|
+
queues: postgresqlQueuesQueries,
|
|
16
|
+
sessions: postgresqlSessionsQueries
|
|
13
17
|
}
|
|
14
18
|
};
|
|
15
19
|
export {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import getBrowserSafeUser from "./accounts/getBrowserSafeUser";
|
|
2
|
+
import escapeKeyValuePair from "../lib/escapeKeyValuePair.js";
|
|
2
3
|
var getBrowserSafeRequest_default = (req = {}) => {
|
|
3
4
|
const browserSafeRequest = {};
|
|
4
|
-
browserSafeRequest.params = req.params;
|
|
5
|
-
browserSafeRequest.query = req.query;
|
|
5
|
+
browserSafeRequest.params = escapeKeyValuePair(req.params);
|
|
6
|
+
browserSafeRequest.query = escapeKeyValuePair(req.query);
|
|
6
7
|
browserSafeRequest.context = {
|
|
7
8
|
user: getBrowserSafeUser(req.context.user)
|
|
8
9
|
};
|
package/dist/app/index.js
CHANGED
|
@@ -6,6 +6,8 @@ import queryString from "query-string";
|
|
|
6
6
|
import multer from "multer";
|
|
7
7
|
import cron from "node-cron";
|
|
8
8
|
import { execSync } from "child_process";
|
|
9
|
+
import dayjs from "dayjs";
|
|
10
|
+
import cluster from "./cluster.js";
|
|
9
11
|
import initExpress from "./initExpress.js";
|
|
10
12
|
import handleProcessErrors from "./handleProcessErrors";
|
|
11
13
|
import registerGetters from "./registerGetters.js";
|
|
@@ -25,49 +27,58 @@ import runUploader from "./runUploader";
|
|
|
25
27
|
import generateId from "../lib/generateId.js";
|
|
26
28
|
import getOutput from "./getOutput.js";
|
|
27
29
|
import defaultUserOutputFields from "./accounts/defaultUserOutputFields.js";
|
|
30
|
+
import createMongoDBAccountsIndexes from "./databases/mongodb/createAccountsIndexes";
|
|
31
|
+
import createMongoDBSessionsIndexes from "./databases/mongodb/createSessionsIndexes";
|
|
28
32
|
import createPostgreSQLAccountsTables from "./databases/postgresql/createAccountsTables";
|
|
29
33
|
import createPostgreSQLAccountsIndexes from "./databases/postgresql/createAccountsIndexes";
|
|
34
|
+
import createPostgreSQLSessionsTables from "./databases/postgresql/createSessionsTables";
|
|
35
|
+
import createPostgreSQLSessionsIndexes from "./databases/postgresql/createSessionsIndexes";
|
|
30
36
|
import loadSettings from "../settings/load.js";
|
|
31
37
|
import Queue from "./queues/index.js";
|
|
32
38
|
import readDirectory from "../lib/readDirectory.js";
|
|
33
39
|
import getBuildPath from "../lib/getBuildPath.js";
|
|
34
40
|
import generateMachineId from "../lib/generateMachineId.js";
|
|
41
|
+
import importFile from "../lib/importFile.js";
|
|
35
42
|
import emitWebsocketEvent from "../websockets/emitWebsocketEvent.js";
|
|
36
43
|
import getTargetDatabaseConnection from "./databases/getTargetDatabaseConnection.js";
|
|
44
|
+
import getAPIForDataFunctions from "../ssr/getAPIForDataFunctions.js";
|
|
45
|
+
import getBrowserSafeRequest from "./getBrowserSafeRequest.js";
|
|
46
|
+
import getDataFromComponent from "../ssr/getDataFromComponent.js";
|
|
47
|
+
import getTranslations from "./middleware/getTranslations.js";
|
|
48
|
+
import runUserQuery from "./accounts/runUserQuery.js";
|
|
49
|
+
import wait from "../lib/wait.js";
|
|
50
|
+
import trackFunctionCall from "../test/trackFunctionCall.js";
|
|
51
|
+
import getBrowserSafeUser from "./accounts/getBrowserSafeUser.js";
|
|
37
52
|
process.setMaxListeners(0);
|
|
38
53
|
class App {
|
|
39
54
|
constructor(options = {}) {
|
|
40
55
|
this.setMachineId();
|
|
41
56
|
this.setJoystickProcessId();
|
|
42
57
|
handleProcessErrors(options?.events);
|
|
43
|
-
const HMRSessions = JSON.parse(process.env.HMR_SESSIONS || "{}");
|
|
44
|
-
this.sessions = new Map(HMRSessions ? Object.entries(HMRSessions) : []);
|
|
45
58
|
this.databases = [];
|
|
46
59
|
this.express = {};
|
|
47
60
|
this.options = options || {};
|
|
61
|
+
process.joystick = {
|
|
62
|
+
_app: {
|
|
63
|
+
options
|
|
64
|
+
}
|
|
65
|
+
};
|
|
48
66
|
}
|
|
49
67
|
async start(options = {}) {
|
|
50
68
|
await this.invalidateCache();
|
|
51
69
|
this.databases = await this.loadDatabases();
|
|
52
70
|
this.express = initExpress(this.onStartApp, options, this);
|
|
53
71
|
this.initWebsockets(options?.websockets || {});
|
|
54
|
-
this.
|
|
55
|
-
this.
|
|
56
|
-
this.
|
|
72
|
+
this.initAccounts(options?.accounts);
|
|
73
|
+
this.initTests();
|
|
74
|
+
this.initPush();
|
|
57
75
|
this.initAPI(options?.api);
|
|
58
|
-
this.initRoutes(options?.routes);
|
|
59
76
|
this.initUploaders(options?.uploaders);
|
|
77
|
+
this.initIndexes(options?.indexes);
|
|
60
78
|
this.initFixtures(options?.fixtures);
|
|
61
79
|
this.initQueues(options?.queues);
|
|
62
80
|
this.initCronJobs(options?.cronJobs);
|
|
63
|
-
|
|
64
|
-
process.on("message", (message) => {
|
|
65
|
-
const parsedMessage = typeof message === "string" ? JSON.parse(message) : message;
|
|
66
|
-
if (parsedMessage?.type === " RESTART_SERVER") {
|
|
67
|
-
this.express?.server?.close();
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
}
|
|
81
|
+
this.initRoutes(options?.routes);
|
|
71
82
|
}
|
|
72
83
|
async invalidateCache() {
|
|
73
84
|
const uiFiles = fs.existsSync(`${getBuildPath()}ui`) ? await readDirectory(`${getBuildPath()}ui`) : [];
|
|
@@ -85,9 +96,21 @@ class App {
|
|
|
85
96
|
const hasQueuesDatabase = settings?.config?.databases?.some((database = {}) => {
|
|
86
97
|
return !!database?.queues;
|
|
87
98
|
});
|
|
99
|
+
const hasSessionsDatabase = settings?.config?.databases?.some((database = {}) => {
|
|
100
|
+
return !!database?.sessions;
|
|
101
|
+
});
|
|
102
|
+
const hasMongoDBUsersDatabase = settings?.config?.databases?.some((database = {}) => {
|
|
103
|
+
return database?.provider === "mongodb" && database?.users;
|
|
104
|
+
});
|
|
105
|
+
const hasMongoDBSessionsDatabase = settings?.config?.databases?.some((database = {}) => {
|
|
106
|
+
return database?.provider === "mongodb" && database?.sessions;
|
|
107
|
+
});
|
|
88
108
|
const hasPostgreSQLUsersDatabase = settings?.config?.databases?.some((database = {}) => {
|
|
89
109
|
return database?.provider === "postgresql" && database?.users;
|
|
90
110
|
});
|
|
111
|
+
const hasPostgreSQLSessionsDatabase = settings?.config?.databases?.some((database = {}) => {
|
|
112
|
+
return database?.provider === "postgresql" && database?.sessions;
|
|
113
|
+
});
|
|
91
114
|
const databases = settings?.config?.databases?.map((database) => {
|
|
92
115
|
return {
|
|
93
116
|
provider: database?.provider,
|
|
@@ -114,12 +137,22 @@ class App {
|
|
|
114
137
|
...process.databases || {},
|
|
115
138
|
postgresql: !hasMultipleOfProvider ? {
|
|
116
139
|
...postgresql?.pool,
|
|
117
|
-
|
|
140
|
+
add_column: postgresql?.add_column,
|
|
141
|
+
create_table: postgresql?.create_table,
|
|
142
|
+
insert: postgresql?.insert,
|
|
143
|
+
query: postgresql?.query,
|
|
144
|
+
select: postgresql?.select,
|
|
145
|
+
update: postgresql?.update
|
|
118
146
|
} : {
|
|
119
147
|
...process?.databases?.postgresql || {},
|
|
120
148
|
[database?.settings?.name || `postgresql_${databasePort}`]: {
|
|
121
149
|
...postgresql?.pool,
|
|
122
|
-
|
|
150
|
+
add_column: postgresql?.add_column,
|
|
151
|
+
create_table: postgresql?.create_table,
|
|
152
|
+
insert: postgresql?.insert,
|
|
153
|
+
query: postgresql?.query,
|
|
154
|
+
select: postgresql?.select,
|
|
155
|
+
update: postgresql?.update
|
|
123
156
|
}
|
|
124
157
|
}
|
|
125
158
|
};
|
|
@@ -131,19 +164,40 @@ class App {
|
|
|
131
164
|
if (hasQueuesDatabase) {
|
|
132
165
|
process.databases._queues = getTargetDatabaseConnection("queues")?.connection;
|
|
133
166
|
}
|
|
167
|
+
if (hasSessionsDatabase) {
|
|
168
|
+
process.databases._sessions = getTargetDatabaseConnection("sessions")?.connection;
|
|
169
|
+
}
|
|
170
|
+
if (hasMongoDBUsersDatabase) {
|
|
171
|
+
await createMongoDBAccountsIndexes();
|
|
172
|
+
}
|
|
173
|
+
if (hasMongoDBSessionsDatabase) {
|
|
174
|
+
await createMongoDBSessionsIndexes();
|
|
175
|
+
}
|
|
134
176
|
if (hasPostgreSQLUsersDatabase) {
|
|
135
177
|
await createPostgreSQLAccountsTables();
|
|
136
178
|
await createPostgreSQLAccountsIndexes();
|
|
137
179
|
}
|
|
180
|
+
if (hasPostgreSQLSessionsDatabase) {
|
|
181
|
+
await createPostgreSQLSessionsTables();
|
|
182
|
+
await createPostgreSQLSessionsIndexes();
|
|
183
|
+
}
|
|
138
184
|
return process.databases;
|
|
139
185
|
}
|
|
140
|
-
onStartApp(express = {}) {
|
|
186
|
+
onStartApp(express = {}, joystick_app_instance = {}) {
|
|
141
187
|
process.on("message", (message) => {
|
|
142
188
|
if (typeof message === "string") {
|
|
143
|
-
|
|
189
|
+
const parsed_message = JSON.parse(message);
|
|
190
|
+
if (parsed_message?.type === "BUILD_ERROR") {
|
|
191
|
+
process.BUILD_ERROR = JSON.parse(message);
|
|
192
|
+
}
|
|
193
|
+
if (parsed_message?.type === "RESTART_SERVER") {
|
|
194
|
+
console.log("HANDLE RESTART");
|
|
195
|
+
}
|
|
144
196
|
}
|
|
145
197
|
});
|
|
146
|
-
|
|
198
|
+
if (process.env.NODE_ENV !== "test") {
|
|
199
|
+
console.log(`App running at: http://localhost:${express.port}`);
|
|
200
|
+
}
|
|
147
201
|
}
|
|
148
202
|
setMachineId() {
|
|
149
203
|
generateMachineId();
|
|
@@ -156,10 +210,78 @@ class App {
|
|
|
156
210
|
fs.writeFileSync("./.joystick/PROCESS_ID", `${generateId(32)}`);
|
|
157
211
|
}
|
|
158
212
|
}
|
|
159
|
-
|
|
160
|
-
if (process.env.NODE_ENV === "
|
|
213
|
+
initTests() {
|
|
214
|
+
if (process.env.NODE_ENV === "test") {
|
|
215
|
+
this.express.app.get("/api/_test/bootstrap", async (req, res) => {
|
|
216
|
+
const buildPath = `${process.cwd()}/.joystick/build`;
|
|
217
|
+
const Component = req?.query?.pathToComponent ? await importFile(`${buildPath}/${req?.query?.pathToComponent}`) : null;
|
|
218
|
+
if (Component) {
|
|
219
|
+
const componentInstance = Component();
|
|
220
|
+
const apiForDataFunctions = await getAPIForDataFunctions(req, this?.options?.api);
|
|
221
|
+
const browserSafeRequest = getBrowserSafeRequest(req);
|
|
222
|
+
const browserSafeUser = getBrowserSafeUser(req?.context?.user);
|
|
223
|
+
const data = await getDataFromComponent(componentInstance, apiForDataFunctions, browserSafeUser, browserSafeRequest);
|
|
224
|
+
const translations = await getTranslations({ build: buildPath, page: req?.query?.pathToComponent }, req);
|
|
225
|
+
const settings = loadSettings();
|
|
226
|
+
return res.status(200).send({
|
|
227
|
+
data: {
|
|
228
|
+
[data?.componentId]: data?.data
|
|
229
|
+
},
|
|
230
|
+
req: browserSafeRequest,
|
|
231
|
+
settings,
|
|
232
|
+
translations
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
res.status(200).send({ data: {}, translations: {} });
|
|
236
|
+
});
|
|
237
|
+
this.express.app.get("/api/_test/process", async (req, res) => {
|
|
238
|
+
res.status(200).send({
|
|
239
|
+
test: process?.test || {}
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
this.express.app.post("/api/_test/accounts/signup", async (req, res) => {
|
|
243
|
+
const existingUser = await runUserQuery("user", { emailAddress: req?.body?.emailAddress });
|
|
244
|
+
if (existingUser) {
|
|
245
|
+
await runUserQuery("deleteUser", { userId: existingUser?._id || existingUser?.user_id });
|
|
246
|
+
}
|
|
247
|
+
const signup = await accounts.signup({
|
|
248
|
+
emailAddress: req?.body?.emailAddress,
|
|
249
|
+
password: req?.body?.password,
|
|
250
|
+
metadata: req?.body?.metadata,
|
|
251
|
+
output: req?.body?.output || defaultUserOutputFields
|
|
252
|
+
});
|
|
253
|
+
res.status(200).send(JSON.stringify({
|
|
254
|
+
...signup?.user || {},
|
|
255
|
+
joystickLoginToken: signup?.token,
|
|
256
|
+
joystickLoginTokenExpiresAt: signup?.tokenExpiresAt
|
|
257
|
+
}));
|
|
258
|
+
});
|
|
259
|
+
this.express.app.delete("/api/_test/accounts", async (req, res) => {
|
|
260
|
+
await runUserQuery("deleteUser", { userId: req?.body?.userId });
|
|
261
|
+
res.status(200).send({ data: {} });
|
|
262
|
+
});
|
|
263
|
+
this.express.app.post("/api/_test/queues", async (req, res) => {
|
|
264
|
+
const queue = process?.queues[req?.body?.queue];
|
|
265
|
+
const job = this?.options?.queues[req?.body?.queue]?.jobs[req?.body?.job];
|
|
266
|
+
if (!queue) {
|
|
267
|
+
return res.status(404).send({ status: 404, error: `Queue ${req?.body?.queue} not found.` });
|
|
268
|
+
}
|
|
269
|
+
if (!job) {
|
|
270
|
+
return res.status(400).send({ status: 400, error: `Couldn't find a job called ${req?.body?.job} for the ${req?.body?.queue} queue.` });
|
|
271
|
+
}
|
|
272
|
+
await queue.handleNextJob({
|
|
273
|
+
_id: "joystick_test",
|
|
274
|
+
job: req?.body?.job,
|
|
275
|
+
payload: req?.body?.payload
|
|
276
|
+
});
|
|
277
|
+
res.status(200).send({ data: {} });
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
initPush() {
|
|
282
|
+
if (process.env.NODE_ENV !== "development" && process.env.IS_PUSH_DEPLOYED) {
|
|
161
283
|
this.express.app.get("/api/_push/pre-version", async (req, res) => {
|
|
162
|
-
const instanceToken = fs.readFileSync("/root/
|
|
284
|
+
const instanceToken = fs.readFileSync("/root/push/instance_token.txt", "utf-8");
|
|
163
285
|
if (req?.headers["x-instance-token"] === instanceToken?.replace("\n", "")) {
|
|
164
286
|
if (this.options?.events?.onBeforeDeployment && typeof this.options?.events?.onBeforeDeployment === "function") {
|
|
165
287
|
await this.options.events.onBeforeDeployment(req?.query?.instance || "", req?.query?.version);
|
|
@@ -170,28 +292,12 @@ class App {
|
|
|
170
292
|
return res.status(403).send("Sorry, you must pass a valid instance token to access this endpoint.");
|
|
171
293
|
});
|
|
172
294
|
this.express.app.get("/api/_push/health", async (req, res) => {
|
|
173
|
-
const instanceToken = fs.readFileSync("/root/
|
|
295
|
+
const instanceToken = fs.readFileSync("/root/push/instance_token.txt", "utf-8");
|
|
174
296
|
if (req?.headers["x-instance-token"] === instanceToken?.replace("\n", "")) {
|
|
175
297
|
return res.status(200).send("ok");
|
|
176
298
|
}
|
|
177
299
|
return res.status(403).send("Sorry, you must pass a valid instance token to access this endpoint.");
|
|
178
300
|
});
|
|
179
|
-
this.express.app.get("/api/_push/logs", async (req, res) => {
|
|
180
|
-
const instanceToken = fs.readFileSync("/root/token.txt", "utf-8");
|
|
181
|
-
if (req?.headers["x-instance-token"] === instanceToken?.replace("\n", "")) {
|
|
182
|
-
const logs = execSync(`export NODE_ENV=production && instance logs${req?.query?.before ? ` --before ${req?.query?.before}` : ""}${req?.query?.after ? ` --after ${req?.query?.after}` : ""}`);
|
|
183
|
-
return res.status(200).send(logs);
|
|
184
|
-
}
|
|
185
|
-
return res.status(403).send("Sorry, you must pass a valid instance token to access this endpoint.");
|
|
186
|
-
});
|
|
187
|
-
this.express.app.get("/api/_push/metrics", async (req, res) => {
|
|
188
|
-
const instanceToken = fs.readFileSync("/root/token.txt", "utf-8");
|
|
189
|
-
if (req?.headers["x-instance-token"] === instanceToken?.replace("\n", "")) {
|
|
190
|
-
const metrics = execSync(`export NODE_ENV=production && instance metrics`);
|
|
191
|
-
return res.status(200).send(metrics);
|
|
192
|
-
}
|
|
193
|
-
return res.status(403).send("Sorry, you must pass a valid instance token to access this endpoint.");
|
|
194
|
-
});
|
|
195
301
|
}
|
|
196
302
|
}
|
|
197
303
|
initAPI(api = {}) {
|
|
@@ -199,15 +305,15 @@ class App {
|
|
|
199
305
|
const setters = api?.setters;
|
|
200
306
|
const options = api?.options;
|
|
201
307
|
const context = api?.context;
|
|
202
|
-
if (getters && isObject(getters) && Object.keys(getters).length > 0) {
|
|
203
|
-
registerGetters(this.express, Object.entries(getters), context, options, this);
|
|
308
|
+
if (getters && isObject(getters) && Object.keys(getters || {}).length > 0) {
|
|
309
|
+
registerGetters(this.express, Object.entries(getters || {}), context, options, this);
|
|
204
310
|
}
|
|
205
|
-
if (setters && isObject(setters) && Object.keys(setters).length > 0) {
|
|
206
|
-
registerSetters(this.express, Object.entries(setters), context, options, this);
|
|
311
|
+
if (setters && isObject(setters) && Object.keys(setters || {}).length > 0) {
|
|
312
|
+
registerSetters(this.express, Object.entries(setters || {}), context, options, this);
|
|
207
313
|
}
|
|
208
314
|
}
|
|
209
315
|
initRoutes(routes = {}) {
|
|
210
|
-
Object.entries(routes).forEach(([path, callback]) => {
|
|
316
|
+
Object.entries(routes || {}).forEach(([path, callback]) => {
|
|
211
317
|
const isObjectBasedRoute = path && callback && typeof callback === "object";
|
|
212
318
|
const isFunctionBasedRoute = path && callback && typeof callback === "function";
|
|
213
319
|
const method = callback?.method?.toLowerCase();
|
|
@@ -331,20 +437,29 @@ class App {
|
|
|
331
437
|
path: "/api/_websockets/uploaders"
|
|
332
438
|
})
|
|
333
439
|
},
|
|
334
|
-
...Object.entries(userWebsockets).reduce((definitions = {}, [userWebsocketName, userWebsocketDefinition]) => {
|
|
440
|
+
...Object.entries(userWebsockets || {}).reduce((definitions = {}, [userWebsocketName, userWebsocketDefinition]) => {
|
|
335
441
|
definitions[userWebsocketName] = {
|
|
336
442
|
server: new WebSocket.WebSocketServer({
|
|
337
443
|
noServer: true,
|
|
338
444
|
path: `/api/_websockets/${userWebsocketName}`
|
|
339
445
|
}),
|
|
340
|
-
onOpen:
|
|
341
|
-
|
|
342
|
-
|
|
446
|
+
onOpen: (...args) => {
|
|
447
|
+
trackFunctionCall(`node.websockets.${userWebsocketName}.onOpen`, args);
|
|
448
|
+
return userWebsocketDefinition?.onOpen ? userWebsocketDefinition?.onOpen(...args) : null;
|
|
449
|
+
},
|
|
450
|
+
onMessage: (...args) => {
|
|
451
|
+
trackFunctionCall(`node.websockets.${userWebsocketName}.onMessage`, args);
|
|
452
|
+
return userWebsocketDefinition?.onMessage ? userWebsocketDefinition?.onMessage(...args) : null;
|
|
453
|
+
},
|
|
454
|
+
onClose: (...args) => {
|
|
455
|
+
trackFunctionCall(`node.websockets.${userWebsocketName}.onClose`, args);
|
|
456
|
+
return userWebsocketDefinition?.onClose ? userWebsocketDefinition.onClose(...args) : null;
|
|
457
|
+
}
|
|
343
458
|
};
|
|
344
459
|
return definitions;
|
|
345
460
|
}, {})
|
|
346
461
|
};
|
|
347
|
-
Object.entries(websocketServers).forEach(([websocketName, websocketDefinition]) => {
|
|
462
|
+
Object.entries(websocketServers || {}).forEach(([websocketName, websocketDefinition]) => {
|
|
348
463
|
websocketDefinition.server.on("connection", function connection(websocketConnection, connectionRequest) {
|
|
349
464
|
try {
|
|
350
465
|
const [_path, params] = connectionRequest?.url?.split("?");
|
|
@@ -400,18 +515,7 @@ class App {
|
|
|
400
515
|
}
|
|
401
516
|
});
|
|
402
517
|
}
|
|
403
|
-
|
|
404
|
-
if (process.env.NODE_ENV === "development") {
|
|
405
|
-
this.express.app.get("/api/_joystick/sessions", async (req, res) => {
|
|
406
|
-
const sessions = Array.from(this.sessions.entries())?.reduce((acc = {}, [key, value]) => {
|
|
407
|
-
acc[key] = value;
|
|
408
|
-
return acc;
|
|
409
|
-
}, {});
|
|
410
|
-
res.status(200).send(JSON.stringify(sessions));
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
initAccounts() {
|
|
518
|
+
initAccounts(options = {}) {
|
|
415
519
|
this.express.app.get("/api/_accounts/authenticated", async (req, res) => {
|
|
416
520
|
const loginTokenHasExpired = await hasLoginTokenExpired(res, req?.cookies?.joystickLoginToken, req?.cookies?.joystickLoginTokenExpiresAt);
|
|
417
521
|
const status = !loginTokenHasExpired ? 200 : 401;
|
|
@@ -431,11 +535,20 @@ class App {
|
|
|
431
535
|
metadata: req?.body?.metadata,
|
|
432
536
|
output: req?.body?.output || defaultUserOutputFields
|
|
433
537
|
});
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
538
|
+
if (!process.env.NODE_ENV !== "test") {
|
|
539
|
+
accounts._setAuthenticationCookie(res, {
|
|
540
|
+
token: signup?.token,
|
|
541
|
+
tokenExpiresAt: signup?.tokenExpiresAt
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
const response = {
|
|
545
|
+
...signup?.user || {}
|
|
546
|
+
};
|
|
547
|
+
if (process.env.NODE_ENV === "test") {
|
|
548
|
+
response.joystickToken = signup?.token;
|
|
549
|
+
response.joystickLoginTokenExpiresAt = signup?.tokenExpiresAt;
|
|
550
|
+
}
|
|
551
|
+
res.status(200).send(JSON.stringify(response));
|
|
439
552
|
} catch (exception) {
|
|
440
553
|
console.log(exception);
|
|
441
554
|
return res.status(500).send(JSON.stringify({
|
|
@@ -451,11 +564,20 @@ class App {
|
|
|
451
564
|
password: req?.body?.password,
|
|
452
565
|
output: req?.body?.output || defaultUserOutputFields
|
|
453
566
|
});
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
567
|
+
if (!process.env.NODE_ENV !== "test") {
|
|
568
|
+
accounts._setAuthenticationCookie(res, {
|
|
569
|
+
token: login?.token,
|
|
570
|
+
tokenExpiresAt: login?.tokenExpiresAt
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
const response = {
|
|
574
|
+
...login?.user || {}
|
|
575
|
+
};
|
|
576
|
+
if (process.env.NODE_ENV === "test") {
|
|
577
|
+
response.joystickToken = login?.token;
|
|
578
|
+
response.joystickLoginTokenExpiresAt = login?.tokenExpiresAt;
|
|
579
|
+
}
|
|
580
|
+
res.status(200).send(JSON.stringify(response));
|
|
459
581
|
} catch (exception) {
|
|
460
582
|
console.log(exception);
|
|
461
583
|
return res.status(500).send(JSON.stringify({
|
|
@@ -465,8 +587,10 @@ class App {
|
|
|
465
587
|
});
|
|
466
588
|
this.express.app.post("/api/_accounts/logout", async (req, res) => {
|
|
467
589
|
try {
|
|
468
|
-
this.sessions.delete(req?.context?.user?._id || req?.context?.user?.user_id);
|
|
469
590
|
accounts._unsetAuthenticationCookie(res);
|
|
591
|
+
if (typeof options?.onLogout === "function") {
|
|
592
|
+
options.onLogout(req?.context?.user);
|
|
593
|
+
}
|
|
470
594
|
res.status(200).send(JSON.stringify({}));
|
|
471
595
|
} catch (exception) {
|
|
472
596
|
console.log(exception);
|
|
@@ -523,7 +647,7 @@ class App {
|
|
|
523
647
|
}
|
|
524
648
|
initUploaders(uploaders = {}) {
|
|
525
649
|
const { app } = this.express;
|
|
526
|
-
Object.entries(uploaders).forEach(([uploaderName, uploaderOptions]) => {
|
|
650
|
+
Object.entries(uploaders || {}).forEach(([uploaderName, uploaderOptions]) => {
|
|
527
651
|
const errors = validateUploaderOptions(uploaderOptions);
|
|
528
652
|
if (errors?.length > 0) {
|
|
529
653
|
log(errors, {
|
|
@@ -561,6 +685,11 @@ class App {
|
|
|
561
685
|
req,
|
|
562
686
|
uploads: validatedUploads
|
|
563
687
|
});
|
|
688
|
+
trackFunctionCall(`node.uploaders.${uploaderName}.onBeforeUpload`, [{
|
|
689
|
+
input,
|
|
690
|
+
req,
|
|
691
|
+
uploads: validatedUploads
|
|
692
|
+
}]);
|
|
564
693
|
}
|
|
565
694
|
const fileSize = parseInt(req.headers["content-length"], 10);
|
|
566
695
|
const providers = uploaderOptions?.providers?.includes("local") ? uploaderOptions?.providers.length : uploaderOptions?.providers?.length + 1;
|
|
@@ -578,6 +707,11 @@ class App {
|
|
|
578
707
|
req,
|
|
579
708
|
uploads
|
|
580
709
|
});
|
|
710
|
+
trackFunctionCall(`node.uploaders.${uploaderName}.onAfterUpload`, [{
|
|
711
|
+
input,
|
|
712
|
+
req,
|
|
713
|
+
uploads
|
|
714
|
+
}]);
|
|
581
715
|
}
|
|
582
716
|
res.status(200).send(JSON.stringify({
|
|
583
717
|
status: 200,
|
|
@@ -604,6 +738,11 @@ class App {
|
|
|
604
738
|
}
|
|
605
739
|
});
|
|
606
740
|
}
|
|
741
|
+
initIndexes(indexes = null) {
|
|
742
|
+
if (indexes && typeof indexes === "function") {
|
|
743
|
+
indexes();
|
|
744
|
+
}
|
|
745
|
+
}
|
|
607
746
|
initFixtures(fixtures = null) {
|
|
608
747
|
if (fixtures && typeof fixtures === "function") {
|
|
609
748
|
fixtures();
|
|
@@ -611,7 +750,7 @@ class App {
|
|
|
611
750
|
}
|
|
612
751
|
initQueues(queues = null) {
|
|
613
752
|
if (queues && typeof queues === "object" && !Array.isArray(queues)) {
|
|
614
|
-
const queueDefinitions = Object.entries(queues);
|
|
753
|
+
const queueDefinitions = Object.entries(queues || {});
|
|
615
754
|
for (let i = 0; i < queueDefinitions.length; i += 1) {
|
|
616
755
|
const [queueName, queueOptions] = queueDefinitions[i];
|
|
617
756
|
process.queues = {
|
|
@@ -623,7 +762,7 @@ class App {
|
|
|
623
762
|
}
|
|
624
763
|
initCronJobs(cronJobs = null) {
|
|
625
764
|
if (cronJobs && typeof cronJobs === "object" && !Array.isArray(cronJobs)) {
|
|
626
|
-
const cronJobDefinitions = Object.entries(cronJobs);
|
|
765
|
+
const cronJobDefinitions = Object.entries(cronJobs || {});
|
|
627
766
|
for (let i = 0; i < cronJobDefinitions.length; i += 1) {
|
|
628
767
|
const [cronJobName, cronJobOptions] = cronJobDefinitions[i];
|
|
629
768
|
if (cronJobOptions?.schedule && cronJobOptions?.run && typeof cronJobOptions?.run === "function") {
|
|
@@ -641,11 +780,23 @@ class App {
|
|
|
641
780
|
}
|
|
642
781
|
}
|
|
643
782
|
}
|
|
783
|
+
;
|
|
784
|
+
const handleStartApp = async (options = {}) => {
|
|
785
|
+
const app = new App(options);
|
|
786
|
+
await app.start(options);
|
|
787
|
+
return app;
|
|
788
|
+
};
|
|
644
789
|
var app_default = (options = {}) => {
|
|
645
790
|
return new Promise(async (resolve) => {
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
791
|
+
if (options?.cluster) {
|
|
792
|
+
cluster(async () => {
|
|
793
|
+
const app = await handleStartApp(options);
|
|
794
|
+
return resolve(app.express);
|
|
795
|
+
});
|
|
796
|
+
} else {
|
|
797
|
+
const app = await handleStartApp(options);
|
|
798
|
+
return resolve(app.express);
|
|
799
|
+
}
|
|
649
800
|
});
|
|
650
801
|
};
|
|
651
802
|
export {
|
package/dist/app/initExpress.js
CHANGED
|
@@ -27,7 +27,7 @@ var csp_default = (req, res, next, config = null) => {
|
|
|
27
27
|
directiveDefaults["script-src"].push("'unsafe-eval'");
|
|
28
28
|
directiveDefaults["connect-src"].push("ws:");
|
|
29
29
|
}
|
|
30
|
-
const directiveNames = Object.keys(directiveDefaults);
|
|
30
|
+
const directiveNames = Object.keys(directiveDefaults || {});
|
|
31
31
|
for (let i = 0; i < directiveNames?.length; i += 1) {
|
|
32
32
|
const directive = directiveNames[i];
|
|
33
33
|
directiveDefaults[directive] = [
|
|
@@ -36,7 +36,7 @@ var csp_default = (req, res, next, config = null) => {
|
|
|
36
36
|
...directives[directive] || []
|
|
37
37
|
];
|
|
38
38
|
}
|
|
39
|
-
const csp = Object.keys(directiveDefaults).map((source) => {
|
|
39
|
+
const csp = Object.keys(directiveDefaults || {}).map((source) => {
|
|
40
40
|
return `${source} ${directiveDefaults[source].join(" ")}`;
|
|
41
41
|
})?.join("; ");
|
|
42
42
|
res.setHeader("Content-Security-Policy", csp);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import importFile from "../../lib/importFile.js";
|
|
3
|
+
import { isObject } from "../../validation/lib/typeValidators.js";
|
|
4
|
+
import settings from "../../settings/index.js";
|
|
5
|
+
const getTranslationsFile = async (languageFilePath = "", paths = "") => {
|
|
6
|
+
const languageFile = await importFile(`${paths.build}/i18n/${languageFilePath}`);
|
|
7
|
+
const isValidLanguageFile = languageFile && isObject(languageFile);
|
|
8
|
+
if (isValidLanguageFile) {
|
|
9
|
+
const translationsForPage = languageFile[paths.page];
|
|
10
|
+
return translationsForPage ? translationsForPage : languageFile;
|
|
11
|
+
}
|
|
12
|
+
return {};
|
|
13
|
+
};
|
|
14
|
+
const getLanguagePreferenceRegexes = (userLanguage = "", browserLanguages = []) => {
|
|
15
|
+
let languagePreferences = [];
|
|
16
|
+
if (userLanguage) {
|
|
17
|
+
languagePreferences.push(userLanguage);
|
|
18
|
+
}
|
|
19
|
+
const filteredBrowserLanguages = browserLanguages?.filter((language) => {
|
|
20
|
+
return !language?.includes("*");
|
|
21
|
+
});
|
|
22
|
+
languagePreferences.push(...filteredBrowserLanguages);
|
|
23
|
+
languagePreferences.push(settings?.config?.i18n?.defaultLanguage);
|
|
24
|
+
return languagePreferences?.flatMap((language) => {
|
|
25
|
+
const variants = [language];
|
|
26
|
+
if (language?.length === 2) {
|
|
27
|
+
variants.push(`${language.substring(0, 2)}-`);
|
|
28
|
+
}
|
|
29
|
+
if (language?.length > 2) {
|
|
30
|
+
variants.push(`${language?.split("-")[0]}`);
|
|
31
|
+
variants.push(`${language?.split("-")[0]}-`);
|
|
32
|
+
}
|
|
33
|
+
return variants;
|
|
34
|
+
})?.map((languageString) => {
|
|
35
|
+
const lastCharacter = languageString[languageString.length - 1];
|
|
36
|
+
if (lastCharacter === "-") {
|
|
37
|
+
return new RegExp(`^${languageString}[A-Z]+.js`, "g");
|
|
38
|
+
}
|
|
39
|
+
return new RegExp(`^${languageString}.js`, "g");
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
const parseBrowserLanguages = (languages = "") => {
|
|
43
|
+
const rawLanguages = languages.split(",");
|
|
44
|
+
return rawLanguages?.map((rawLanguage) => rawLanguage.split(";")[0]);
|
|
45
|
+
};
|
|
46
|
+
var getTranslations_default = async (paths = {}, req = {}) => {
|
|
47
|
+
const languageFiles = fs.readdirSync(`${paths.build}/i18n`);
|
|
48
|
+
const browserLanguages = parseBrowserLanguages(req?.headers["accept-language"]);
|
|
49
|
+
const languagePreferences = getLanguagePreferenceRegexes(req?.context?.user?.language, browserLanguages);
|
|
50
|
+
let matchingFile = null;
|
|
51
|
+
for (let i = 0; i < languagePreferences.length; i += 1) {
|
|
52
|
+
const languageRegex = languagePreferences[i];
|
|
53
|
+
const match = languageFiles.find((languageFile) => !!languageFile.match(languageRegex));
|
|
54
|
+
if (match) {
|
|
55
|
+
matchingFile = match;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const translationsFile = await getTranslationsFile(matchingFile, paths);
|
|
60
|
+
return translationsFile;
|
|
61
|
+
};
|
|
62
|
+
export {
|
|
63
|
+
getTranslations_default as default
|
|
64
|
+
};
|