@strapi-community/plugin-io 5.3.1 → 5.3.3
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/dist/_chunks/{LivePresencePanel-D_vzQr4B.mjs → LivePresencePanel-GVXmNi4P.mjs} +1 -1
- package/dist/_chunks/{LivePresencePanel-BkeWL4kq.js → LivePresencePanel-vr2O8XCP.js} +1 -1
- package/dist/_chunks/{MonitoringPage-CYGqkzva.js → MonitoringPage-BF7j_o-y.js} +1 -1
- package/dist/_chunks/{MonitoringPage-DKfhYUgU.mjs → MonitoringPage-D_-Z46BS.mjs} +1 -1
- package/dist/_chunks/{OnlineEditorsWidget-Bf8hfVha.js → OnlineEditorsWidget-CIvPvATB.js} +1 -2
- package/dist/_chunks/{OnlineEditorsWidget-RcYLxQke.mjs → OnlineEditorsWidget-HoSM-JvQ.mjs} +2 -3
- package/dist/_chunks/{SettingsPage-Qi0iMaWc.mjs → SettingsPage-CbtGTI5C.mjs} +1 -1
- package/dist/_chunks/{SettingsPage-0k9qPAJZ.js → SettingsPage-Cq__0eJy.js} +1 -1
- package/dist/_chunks/{index-Bw7WjN5H.mjs → index-6OLmXhVw.mjs} +4 -4
- package/dist/_chunks/{index-DVNfszio.js → index-BOmMSyxA.js} +4 -4
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +864 -272
- package/dist/server/index.mjs +865 -272
- package/package.json +1 -1
package/dist/server/index.mjs
CHANGED
|
@@ -16,6 +16,7 @@ import require$$0$c from "constants";
|
|
|
16
16
|
import { Writable } from "node:stream";
|
|
17
17
|
import { z as z$1 } from "zod";
|
|
18
18
|
import * as z from "zod/v4";
|
|
19
|
+
import { z as z$2 } from "zod/v4";
|
|
19
20
|
var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
|
|
20
21
|
function getDefaultExportFromCjs(x) {
|
|
21
22
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
@@ -51,10 +52,10 @@ const require$$0$3 = {
|
|
|
51
52
|
strapi: strapi$1
|
|
52
53
|
};
|
|
53
54
|
const pluginPkg = require$$0$3;
|
|
54
|
-
const pluginId$
|
|
55
|
-
var pluginId_1 = { pluginId: pluginId$
|
|
56
|
-
const { pluginId: pluginId$
|
|
57
|
-
function getService$3({ name, plugin = pluginId$
|
|
55
|
+
const pluginId$a = pluginPkg.strapi.name;
|
|
56
|
+
var pluginId_1 = { pluginId: pluginId$a };
|
|
57
|
+
const { pluginId: pluginId$9 } = pluginId_1;
|
|
58
|
+
function getService$3({ name, plugin = pluginId$9, type: type2 = "plugin" }) {
|
|
58
59
|
let serviceUID = `${type2}::${plugin}`;
|
|
59
60
|
if (name && name.length) {
|
|
60
61
|
serviceUID += `.${name}`;
|
|
@@ -97,7 +98,7 @@ async function handshake$2(socket, next) {
|
|
|
97
98
|
room = strategyService["role"].getRoomName(role);
|
|
98
99
|
}
|
|
99
100
|
if (room) {
|
|
100
|
-
socket.join(room.
|
|
101
|
+
socket.join(room.replaceAll(" ", "-"));
|
|
101
102
|
} else {
|
|
102
103
|
throw new Error("No valid room found");
|
|
103
104
|
}
|
|
@@ -124,7 +125,7 @@ var constants$7 = {
|
|
|
124
125
|
const { Server } = require$$0$4;
|
|
125
126
|
const { handshake } = middleware;
|
|
126
127
|
const { getService: getService$1 } = getService_1;
|
|
127
|
-
const { pluginId: pluginId$
|
|
128
|
+
const { pluginId: pluginId$8 } = pluginId_1;
|
|
128
129
|
const { API_TOKEN_TYPE: API_TOKEN_TYPE$1 } = constants$7;
|
|
129
130
|
let SocketIO$2 = class SocketIO {
|
|
130
131
|
constructor(options) {
|
|
@@ -166,7 +167,7 @@ let SocketIO$2 = class SocketIO {
|
|
|
166
167
|
});
|
|
167
168
|
const roomName = strategy2.getRoomName(room);
|
|
168
169
|
const data = transformService.response({ data: sanitizedData, schema: schema2 });
|
|
169
|
-
this._socket.to(roomName.
|
|
170
|
+
this._socket.to(roomName.replaceAll(" ", "-")).emit(eventName, { ...data });
|
|
170
171
|
if (entityRoomName) {
|
|
171
172
|
this._socket.to(entityRoomName).emit(eventName, { ...data });
|
|
172
173
|
}
|
|
@@ -202,21 +203,25 @@ function requireSanitizeSensitiveFields() {
|
|
|
202
203
|
hasRequiredSanitizeSensitiveFields = 1;
|
|
203
204
|
const SENSITIVE_FIELDS = [
|
|
204
205
|
"password",
|
|
206
|
+
"passwordHash",
|
|
205
207
|
"resetPasswordToken",
|
|
206
208
|
"registrationToken",
|
|
207
209
|
"confirmationToken",
|
|
208
210
|
"privateKey",
|
|
209
211
|
"secretKey",
|
|
210
212
|
"apiKey",
|
|
211
|
-
"secret"
|
|
212
|
-
"hash"
|
|
213
|
+
"secret"
|
|
213
214
|
];
|
|
214
|
-
|
|
215
|
+
const MAX_SANITIZE_DEPTH = 20;
|
|
216
|
+
function deepSanitize(obj, depth2 = 0) {
|
|
215
217
|
if (!obj || typeof obj !== "object") {
|
|
216
218
|
return obj;
|
|
217
219
|
}
|
|
220
|
+
if (depth2 >= MAX_SANITIZE_DEPTH) {
|
|
221
|
+
return obj;
|
|
222
|
+
}
|
|
218
223
|
if (Array.isArray(obj)) {
|
|
219
|
-
return obj.map((item) => deepSanitize(item));
|
|
224
|
+
return obj.map((item) => deepSanitize(item, depth2 + 1));
|
|
220
225
|
}
|
|
221
226
|
const sanitized = {};
|
|
222
227
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -224,7 +229,7 @@ function requireSanitizeSensitiveFields() {
|
|
|
224
229
|
continue;
|
|
225
230
|
}
|
|
226
231
|
if (value && typeof value === "object") {
|
|
227
|
-
sanitized[key] = deepSanitize(value);
|
|
232
|
+
sanitized[key] = deepSanitize(value, depth2 + 1);
|
|
228
233
|
} else {
|
|
229
234
|
sanitized[key] = value;
|
|
230
235
|
}
|
|
@@ -244,11 +249,57 @@ function requireSanitizeSensitiveFields() {
|
|
|
244
249
|
return sanitizeSensitiveFields;
|
|
245
250
|
}
|
|
246
251
|
const { SocketIO: SocketIO2 } = structures;
|
|
247
|
-
const { pluginId: pluginId$
|
|
252
|
+
const { pluginId: pluginId$7 } = pluginId_1;
|
|
253
|
+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
254
|
+
const MAX_FIELD_VALUE_SIZE = 1e5;
|
|
255
|
+
function safeHandler(handler, expectsObject = true) {
|
|
256
|
+
return function(...args) {
|
|
257
|
+
try {
|
|
258
|
+
if (expectsObject) {
|
|
259
|
+
const data = args[0];
|
|
260
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
261
|
+
const callback = typeof args[args.length - 1] === "function" ? args[args.length - 1] : null;
|
|
262
|
+
if (callback) callback({ success: false, error: "Invalid payload" });
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const result = handler.apply(this, args);
|
|
267
|
+
if (result && typeof result.catch === "function") {
|
|
268
|
+
result.catch((err) => {
|
|
269
|
+
strapi.log.error(`socket.io: Unhandled error in event handler: ${err.message}`);
|
|
270
|
+
const callback = typeof args[args.length - 1] === "function" ? args[args.length - 1] : null;
|
|
271
|
+
if (callback) callback({ success: false, error: "Internal error" });
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
} catch (err) {
|
|
275
|
+
strapi.log.error(`socket.io: Error in event handler: ${err.message}`);
|
|
276
|
+
const callback = typeof args[args.length - 1] === "function" ? args[args.length - 1] : null;
|
|
277
|
+
if (callback) callback({ success: false, error: "Internal error" });
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function resolveClientIp(socket) {
|
|
282
|
+
const xff = socket.handshake.headers?.["x-forwarded-for"];
|
|
283
|
+
if (xff) {
|
|
284
|
+
return xff.split(",")[0].trim();
|
|
285
|
+
}
|
|
286
|
+
return socket.handshake.address;
|
|
287
|
+
}
|
|
288
|
+
function redactUrl(url) {
|
|
289
|
+
try {
|
|
290
|
+
const parsed = new URL(url);
|
|
291
|
+
if (parsed.password) {
|
|
292
|
+
parsed.password = "***";
|
|
293
|
+
}
|
|
294
|
+
return parsed.toString();
|
|
295
|
+
} catch {
|
|
296
|
+
return url.replace(/:([^@/]+)@/, ":***@");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
248
299
|
async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
249
|
-
const settingsService = strapi2.plugin(pluginId$
|
|
300
|
+
const settingsService = strapi2.plugin(pluginId$7).service("settings");
|
|
250
301
|
const settings2 = await settingsService.getSettings();
|
|
251
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
302
|
+
const monitoringService = strapi2.plugin(pluginId$7).service("monitoring");
|
|
252
303
|
const serverOptions = {
|
|
253
304
|
cors: {
|
|
254
305
|
origin: settings2.cors?.origins || ["http://localhost:3000"],
|
|
@@ -260,7 +311,7 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
260
311
|
connectTimeout: settings2.connection?.connectionTimeout || 45e3,
|
|
261
312
|
maxHttpBufferSize: 1e6,
|
|
262
313
|
transports: ["websocket", "polling"],
|
|
263
|
-
allowEIO3:
|
|
314
|
+
allowEIO3: settings2.connection?.allowEIO3 ?? false
|
|
264
315
|
};
|
|
265
316
|
if (settings2.redis?.enabled) {
|
|
266
317
|
try {
|
|
@@ -272,13 +323,15 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
272
323
|
const subClient = pubClient.duplicate();
|
|
273
324
|
await Promise.all([pubClient.connect(), subClient.connect()]);
|
|
274
325
|
serverOptions.adapter = createAdapter(pubClient, subClient);
|
|
275
|
-
|
|
326
|
+
serverOptions._redisClients = { pubClient, subClient };
|
|
327
|
+
strapi2.log.info(`socket.io: Redis adapter enabled (${redactUrl(settings2.redis.url)})`);
|
|
276
328
|
} catch (err) {
|
|
277
329
|
strapi2.log.error(`socket.io: Redis adapter failed: ${err.message}`);
|
|
278
330
|
}
|
|
279
331
|
}
|
|
280
332
|
const io2 = new SocketIO2(serverOptions);
|
|
281
333
|
strapi2.$io = io2;
|
|
334
|
+
strapi2.$io._redisClients = serverOptions._redisClients || null;
|
|
282
335
|
strapi2.$ioSettings = settings2;
|
|
283
336
|
const sanitizeSensitiveFields2 = requireSanitizeSensitiveFields();
|
|
284
337
|
sanitizeSensitiveFields2({ strapi: strapi2 });
|
|
@@ -304,7 +357,7 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
304
357
|
}
|
|
305
358
|
strapi2.$io.namespaces = namespaces;
|
|
306
359
|
io2.server.use(async (socket, next) => {
|
|
307
|
-
const clientIp = socket
|
|
360
|
+
const clientIp = resolveClientIp(socket);
|
|
308
361
|
if (settings2.security?.ipWhitelist?.length > 0) {
|
|
309
362
|
if (!settings2.security.ipWhitelist.includes(clientIp)) {
|
|
310
363
|
return next(new Error("IP not whitelisted"));
|
|
@@ -317,30 +370,22 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
317
370
|
if (currentConnections >= (settings2.connection?.maxConnections || 1e3)) {
|
|
318
371
|
return next(new Error("Max connections reached"));
|
|
319
372
|
}
|
|
320
|
-
const token = socket.handshake.auth?.token
|
|
321
|
-
const strategy2 = socket.handshake.auth?.strategy;
|
|
322
|
-
const isAdmin = socket.handshake.auth?.isAdmin === true;
|
|
373
|
+
const token = socket.handshake.auth?.token;
|
|
323
374
|
if (token) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
strapi2.log.info(`socket.io: Admin authenticated - ${socket.user.username} (ID: ${session.userId})`);
|
|
339
|
-
} else {
|
|
340
|
-
strapi2.log.warn(`socket.io: Admin session token invalid or expired`);
|
|
341
|
-
}
|
|
342
|
-
} catch (err) {
|
|
343
|
-
strapi2.log.warn(`socket.io: Admin session verification failed: ${err.message}`);
|
|
375
|
+
const isAdminToken = UUID_REGEX.test(token);
|
|
376
|
+
if (isAdminToken) {
|
|
377
|
+
if (socket.adminUser) {
|
|
378
|
+
const admin2 = socket.adminUser;
|
|
379
|
+
socket.user = {
|
|
380
|
+
id: admin2.id,
|
|
381
|
+
username: `${admin2.firstname || ""} ${admin2.lastname || ""}`.trim() || `Admin ${admin2.id}`,
|
|
382
|
+
email: admin2.email || `admin-${admin2.id}`,
|
|
383
|
+
role: "strapi-super-admin",
|
|
384
|
+
isAdmin: true
|
|
385
|
+
};
|
|
386
|
+
strapi2.log.info(`socket.io: Admin connected - ${socket.user.username} (ID: ${admin2.id})`);
|
|
387
|
+
} else {
|
|
388
|
+
strapi2.log.warn("socket.io: Admin token present but handshake did not authenticate");
|
|
344
389
|
}
|
|
345
390
|
} else {
|
|
346
391
|
try {
|
|
@@ -406,13 +451,13 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
406
451
|
}
|
|
407
452
|
});
|
|
408
453
|
}
|
|
409
|
-
const presenceService = strapi2.plugin(pluginId$
|
|
410
|
-
const previewService = strapi2.plugin(pluginId$
|
|
454
|
+
const presenceService = strapi2.plugin(pluginId$7).service("presence");
|
|
455
|
+
const previewService = strapi2.plugin(pluginId$7).service("preview");
|
|
411
456
|
if (settings2.presence?.enabled !== false) {
|
|
412
457
|
presenceService.startCleanupInterval();
|
|
413
458
|
}
|
|
414
459
|
io2.server.on("connection", (socket) => {
|
|
415
|
-
const clientIp = socket
|
|
460
|
+
const clientIp = resolveClientIp(socket);
|
|
416
461
|
const username = socket.user?.username || "anonymous";
|
|
417
462
|
if (settings2.monitoring?.enableConnectionLogging) {
|
|
418
463
|
strapi2.log.info(`socket.io: Client connected (id: ${socket.id}, user: ${username}, ip: ${clientIp})`);
|
|
@@ -458,19 +503,24 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
458
503
|
if (callback) callback({ success: true, room: roomName });
|
|
459
504
|
});
|
|
460
505
|
socket.on("leave-room", (roomName, callback) => {
|
|
461
|
-
if (typeof roomName
|
|
462
|
-
socket.leave(roomName);
|
|
463
|
-
strapi2.log.debug(`socket.io: Socket ${socket.id} left room: ${roomName}`);
|
|
464
|
-
if (callback) callback({ success: true, room: roomName });
|
|
465
|
-
} else {
|
|
506
|
+
if (typeof roomName !== "string" || roomName.length === 0) {
|
|
466
507
|
if (callback) callback({ success: false, error: "Invalid room name" });
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
const sanitizedRoom = roomName.replace(/[^a-zA-Z0-9\-_:]/g, "");
|
|
511
|
+
if (sanitizedRoom !== roomName) {
|
|
512
|
+
if (callback) callback({ success: false, error: "Room name contains invalid characters" });
|
|
513
|
+
return;
|
|
467
514
|
}
|
|
515
|
+
socket.leave(roomName);
|
|
516
|
+
strapi2.log.debug(`socket.io: Socket ${socket.id} left room: ${roomName}`);
|
|
517
|
+
if (callback) callback({ success: true, room: roomName });
|
|
468
518
|
});
|
|
469
519
|
socket.on("get-rooms", (callback) => {
|
|
470
520
|
const rooms = Array.from(socket.rooms).filter((r) => r !== socket.id);
|
|
471
521
|
if (callback) callback({ success: true, rooms });
|
|
472
522
|
});
|
|
473
|
-
socket.on("presence:join", async ({ uid, documentId }, callback) => {
|
|
523
|
+
socket.on("presence:join", safeHandler(async ({ uid, documentId }, callback) => {
|
|
474
524
|
if (settings2.presence?.enabled === false) {
|
|
475
525
|
if (callback) callback({ success: false, error: "Presence is disabled" });
|
|
476
526
|
return;
|
|
@@ -481,8 +531,8 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
481
531
|
}
|
|
482
532
|
const result = await presenceService.joinEntity(socket.id, uid, documentId);
|
|
483
533
|
if (callback) callback(result);
|
|
484
|
-
});
|
|
485
|
-
socket.on("presence:leave", async ({ uid, documentId }, callback) => {
|
|
534
|
+
}));
|
|
535
|
+
socket.on("presence:leave", safeHandler(async ({ uid, documentId }, callback) => {
|
|
486
536
|
if (settings2.presence?.enabled === false) {
|
|
487
537
|
if (callback) callback({ success: false, error: "Presence is disabled" });
|
|
488
538
|
return;
|
|
@@ -493,24 +543,26 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
493
543
|
}
|
|
494
544
|
const result = await presenceService.leaveEntity(socket.id, uid, documentId);
|
|
495
545
|
if (callback) callback(result);
|
|
496
|
-
});
|
|
546
|
+
}));
|
|
497
547
|
socket.on("presence:heartbeat", (callback) => {
|
|
498
548
|
const result = presenceService.heartbeat(socket.id);
|
|
499
549
|
if (callback) callback(result);
|
|
500
550
|
});
|
|
501
|
-
socket.on("presence:typing", ({ uid, documentId, fieldName }) => {
|
|
551
|
+
socket.on("presence:typing", safeHandler(({ uid, documentId, fieldName }) => {
|
|
502
552
|
if (settings2.presence?.enabled === false) return;
|
|
553
|
+
if (!socket.user) return;
|
|
554
|
+
if (typeof fieldName !== "string" || fieldName.length > 200) return;
|
|
503
555
|
presenceService.broadcastTyping(socket.id, uid, documentId, fieldName);
|
|
504
|
-
});
|
|
505
|
-
socket.on("presence:check", async ({ uid, documentId }, callback) => {
|
|
556
|
+
}));
|
|
557
|
+
socket.on("presence:check", safeHandler(async ({ uid, documentId }, callback) => {
|
|
506
558
|
if (settings2.presence?.enabled === false) {
|
|
507
559
|
if (callback) callback({ success: false, error: "Presence is disabled" });
|
|
508
560
|
return;
|
|
509
561
|
}
|
|
510
562
|
const editors = await presenceService.getEntityEditors(uid, documentId);
|
|
511
563
|
if (callback) callback({ success: true, editors, isBeingEdited: editors.length > 0 });
|
|
512
|
-
});
|
|
513
|
-
socket.on("preview:subscribe", async ({ uid, documentId }, callback) => {
|
|
564
|
+
}));
|
|
565
|
+
socket.on("preview:subscribe", safeHandler(async ({ uid, documentId }, callback) => {
|
|
514
566
|
if (settings2.livePreview?.enabled === false) {
|
|
515
567
|
if (callback) callback({ success: false, error: "Live preview is disabled" });
|
|
516
568
|
return;
|
|
@@ -519,22 +571,33 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
519
571
|
if (callback) callback({ success: false, error: "uid and documentId are required" });
|
|
520
572
|
return;
|
|
521
573
|
}
|
|
574
|
+
const userRole = socket.userRole || "public";
|
|
575
|
+
const rolePerms = (settings2.rolePermissions || {})[userRole] || {};
|
|
576
|
+
const ctPerms = rolePerms.contentTypes?.[uid];
|
|
577
|
+
if (!ctPerms && settings2.security?.requireAuthentication) {
|
|
578
|
+
if (callback) callback({ success: false, error: "Permission denied" });
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
522
581
|
const result = await previewService.subscribe(socket.id, uid, documentId);
|
|
523
582
|
if (callback) callback(result);
|
|
524
|
-
});
|
|
525
|
-
socket.on("preview:unsubscribe", ({ uid, documentId }, callback) => {
|
|
583
|
+
}));
|
|
584
|
+
socket.on("preview:unsubscribe", safeHandler(({ uid, documentId }, callback) => {
|
|
526
585
|
if (!uid || !documentId) {
|
|
527
586
|
if (callback) callback({ success: false, error: "uid and documentId are required" });
|
|
528
587
|
return;
|
|
529
588
|
}
|
|
530
589
|
const result = previewService.unsubscribe(socket.id, uid, documentId);
|
|
531
590
|
if (callback) callback(result);
|
|
532
|
-
});
|
|
533
|
-
socket.on("preview:field-change", ({ uid, documentId, fieldName, value }) => {
|
|
591
|
+
}));
|
|
592
|
+
socket.on("preview:field-change", safeHandler(({ uid, documentId, fieldName, value }) => {
|
|
534
593
|
if (settings2.livePreview?.enabled === false) return;
|
|
594
|
+
if (!socket.user) return;
|
|
595
|
+
if (typeof fieldName !== "string" || fieldName.length > 200) return;
|
|
596
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
597
|
+
if (serialized && serialized.length > MAX_FIELD_VALUE_SIZE) return;
|
|
535
598
|
previewService.emitFieldChange(socket.id, uid, documentId, fieldName, value);
|
|
536
|
-
});
|
|
537
|
-
socket.on("subscribe-entity", async ({ uid, id }, callback) => {
|
|
599
|
+
}));
|
|
600
|
+
socket.on("subscribe-entity", safeHandler(async ({ uid, id }, callback) => {
|
|
538
601
|
if (settings2.entitySubscriptions?.enabled === false) {
|
|
539
602
|
if (callback) callback({ success: false, error: "Entity subscriptions are disabled" });
|
|
540
603
|
return;
|
|
@@ -609,8 +672,8 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
609
672
|
}
|
|
610
673
|
strapi2.log.debug(`socket.io: Socket ${socket.id} subscribed to entity: ${entityRoomName}`);
|
|
611
674
|
if (callback) callback({ success: true, room: entityRoomName, uid, id });
|
|
612
|
-
});
|
|
613
|
-
socket.on("unsubscribe-entity", ({ uid, id }, callback) => {
|
|
675
|
+
}));
|
|
676
|
+
socket.on("unsubscribe-entity", safeHandler(({ uid, id }, callback) => {
|
|
614
677
|
if (settings2.entitySubscriptions?.enabled === false) {
|
|
615
678
|
if (callback) callback({ success: false, error: "Entity subscriptions are disabled" });
|
|
616
679
|
return;
|
|
@@ -631,9 +694,9 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
631
694
|
}
|
|
632
695
|
strapi2.log.debug(`socket.io: Socket ${socket.id} unsubscribed from entity: ${entityRoomName}`);
|
|
633
696
|
if (callback) callback({ success: true, room: entityRoomName, uid, id });
|
|
634
|
-
});
|
|
697
|
+
}));
|
|
635
698
|
socket.on("get-entity-subscriptions", (callback) => {
|
|
636
|
-
const rooms = Array.from(socket.rooms).filter((r) => r !== socket.id && r.
|
|
699
|
+
const rooms = Array.from(socket.rooms).filter((r) => r !== socket.id && /^(api|plugin)::/.test(r) && !r.startsWith("presence:") && !r.startsWith("preview:")).map((room) => {
|
|
637
700
|
const lastColonIndex = room.lastIndexOf(":");
|
|
638
701
|
const uid = room.substring(0, lastColonIndex);
|
|
639
702
|
const id = room.substring(lastColonIndex + 1);
|
|
@@ -641,7 +704,7 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
641
704
|
});
|
|
642
705
|
if (callback) callback({ success: true, subscriptions: rooms });
|
|
643
706
|
});
|
|
644
|
-
socket.on("private-message", ({ to, message }, callback) => {
|
|
707
|
+
socket.on("private-message", safeHandler(({ to, message }, callback) => {
|
|
645
708
|
if (settings2.rooms?.enablePrivateRooms === false) {
|
|
646
709
|
strapi2.log.warn(`socket.io: Private messages disabled for socket ${socket.id}`);
|
|
647
710
|
if (callback) callback({ success: false, error: "Private messages are disabled" });
|
|
@@ -669,7 +732,7 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
669
732
|
});
|
|
670
733
|
strapi2.log.debug(`socket.io: Private message from ${socket.id} to ${to}`);
|
|
671
734
|
if (callback) callback({ success: true });
|
|
672
|
-
});
|
|
735
|
+
}));
|
|
673
736
|
socket.on("disconnect", async (reason) => {
|
|
674
737
|
if (settings2.monitoring?.enableConnectionLogging) {
|
|
675
738
|
strapi2.log.info(`socket.io: Client disconnected (id: ${socket.id}, user: ${username}, reason: ${reason})`);
|
|
@@ -686,7 +749,7 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
686
749
|
previewService.cleanupSocket(socket.id);
|
|
687
750
|
}
|
|
688
751
|
try {
|
|
689
|
-
const presenceController = strapi2.plugin(pluginId$
|
|
752
|
+
const presenceController = strapi2.plugin(pluginId$7).controller("presence");
|
|
690
753
|
if (presenceController?.unregisterSocket) {
|
|
691
754
|
presenceController.unregisterSocket(socket.id);
|
|
692
755
|
}
|
|
@@ -954,7 +1017,7 @@ function getTransactionCtx() {
|
|
|
954
1017
|
}
|
|
955
1018
|
return transactionCtx;
|
|
956
1019
|
}
|
|
957
|
-
const { pluginId: pluginId$
|
|
1020
|
+
const { pluginId: pluginId$6 } = pluginId_1;
|
|
958
1021
|
function scheduleAfterTransaction(callback, delay = 0) {
|
|
959
1022
|
const runner = () => setTimeout(callback, delay);
|
|
960
1023
|
const ctx = getTransactionCtx();
|
|
@@ -1064,8 +1127,8 @@ async function bootstrapLifecycles$1({ strapi: strapi2 }) {
|
|
|
1064
1127
|
const modelInfo = { singularName: event.model.singularName, uid: event.model.uid };
|
|
1065
1128
|
scheduleAfterTransaction(() => {
|
|
1066
1129
|
try {
|
|
1067
|
-
const diffService = strapi2.plugin(pluginId$
|
|
1068
|
-
const previewService = strapi2.plugin(pluginId$
|
|
1130
|
+
const diffService = strapi2.plugin(pluginId$6).service("diff");
|
|
1131
|
+
const previewService = strapi2.plugin(pluginId$6).service("preview");
|
|
1069
1132
|
const fieldLevelEnabled = strapi2.$ioSettings?.fieldLevelChanges?.enabled !== false;
|
|
1070
1133
|
let eventPayload;
|
|
1071
1134
|
if (fieldLevelEnabled && previousData && diffService) {
|
|
@@ -1182,14 +1245,14 @@ var config$1 = {
|
|
|
1182
1245
|
validator(config2) {
|
|
1183
1246
|
}
|
|
1184
1247
|
};
|
|
1185
|
-
const { pluginId: pluginId$
|
|
1248
|
+
const { pluginId: pluginId$5 } = pluginId_1;
|
|
1186
1249
|
var settings$3 = ({ strapi: strapi2 }) => ({
|
|
1187
1250
|
/**
|
|
1188
1251
|
* GET /io/settings
|
|
1189
1252
|
* Retrieve current plugin settings
|
|
1190
1253
|
*/
|
|
1191
1254
|
async getSettings(ctx) {
|
|
1192
|
-
const settingsService = strapi2.plugin(pluginId$
|
|
1255
|
+
const settingsService = strapi2.plugin(pluginId$5).service("settings");
|
|
1193
1256
|
const settings2 = await settingsService.getSettings();
|
|
1194
1257
|
ctx.body = { data: settings2 };
|
|
1195
1258
|
},
|
|
@@ -1198,8 +1261,33 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1198
1261
|
* Update plugin settings and hot-reload Socket.IO
|
|
1199
1262
|
*/
|
|
1200
1263
|
async updateSettings(ctx) {
|
|
1201
|
-
const settingsService = strapi2.plugin(pluginId$
|
|
1264
|
+
const settingsService = strapi2.plugin(pluginId$5).service("settings");
|
|
1202
1265
|
const { body } = ctx.request;
|
|
1266
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
1267
|
+
return ctx.badRequest("Request body must be a JSON object");
|
|
1268
|
+
}
|
|
1269
|
+
const ALLOWED_KEYS = [
|
|
1270
|
+
"enabled",
|
|
1271
|
+
"cors",
|
|
1272
|
+
"connection",
|
|
1273
|
+
"security",
|
|
1274
|
+
"contentTypes",
|
|
1275
|
+
"events",
|
|
1276
|
+
"rooms",
|
|
1277
|
+
"entitySubscriptions",
|
|
1278
|
+
"rolePermissions",
|
|
1279
|
+
"redis",
|
|
1280
|
+
"namespaces",
|
|
1281
|
+
"middleware",
|
|
1282
|
+
"monitoring",
|
|
1283
|
+
"presence",
|
|
1284
|
+
"livePreview",
|
|
1285
|
+
"fieldLevelChanges"
|
|
1286
|
+
];
|
|
1287
|
+
const unknownKeys = Object.keys(body).filter((k) => !ALLOWED_KEYS.includes(k));
|
|
1288
|
+
if (unknownKeys.length > 0) {
|
|
1289
|
+
return ctx.badRequest(`Unknown settings keys: ${unknownKeys.join(", ")}`);
|
|
1290
|
+
}
|
|
1203
1291
|
await settingsService.getSettings();
|
|
1204
1292
|
const updatedSettings = await settingsService.setSettings(body);
|
|
1205
1293
|
strapi2.$ioSettings = updatedSettings;
|
|
@@ -1231,7 +1319,7 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1231
1319
|
* Get connection and event statistics
|
|
1232
1320
|
*/
|
|
1233
1321
|
async getStats(ctx) {
|
|
1234
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
1322
|
+
const monitoringService = strapi2.plugin(pluginId$5).service("monitoring");
|
|
1235
1323
|
const connectionStats = monitoringService.getConnectionStats();
|
|
1236
1324
|
const eventStats = monitoringService.getEventStats();
|
|
1237
1325
|
ctx.body = {
|
|
@@ -1246,7 +1334,7 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1246
1334
|
* Get recent event log
|
|
1247
1335
|
*/
|
|
1248
1336
|
async getEventLog(ctx) {
|
|
1249
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
1337
|
+
const monitoringService = strapi2.plugin(pluginId$5).service("monitoring");
|
|
1250
1338
|
const limit = parseInt(ctx.query.limit) || 50;
|
|
1251
1339
|
const log = monitoringService.getEventLog(limit);
|
|
1252
1340
|
ctx.body = { data: log };
|
|
@@ -1256,10 +1344,11 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1256
1344
|
* Send a test event
|
|
1257
1345
|
*/
|
|
1258
1346
|
async sendTestEvent(ctx) {
|
|
1259
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
1347
|
+
const monitoringService = strapi2.plugin(pluginId$5).service("monitoring");
|
|
1260
1348
|
const { eventName, data } = ctx.request.body;
|
|
1261
1349
|
try {
|
|
1262
|
-
const
|
|
1350
|
+
const safeName = (eventName || "test").replace(/[^a-zA-Z0-9:._-]/g, "").substring(0, 50);
|
|
1351
|
+
const result = monitoringService.sendTestEvent(safeName, data || {});
|
|
1263
1352
|
ctx.body = { data: result };
|
|
1264
1353
|
} catch (error2) {
|
|
1265
1354
|
ctx.throw(500, error2.message);
|
|
@@ -1270,7 +1359,7 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1270
1359
|
* Reset monitoring statistics
|
|
1271
1360
|
*/
|
|
1272
1361
|
async resetStats(ctx) {
|
|
1273
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
1362
|
+
const monitoringService = strapi2.plugin(pluginId$5).service("monitoring");
|
|
1274
1363
|
monitoringService.resetStats();
|
|
1275
1364
|
ctx.body = { data: { success: true } };
|
|
1276
1365
|
},
|
|
@@ -1294,7 +1383,7 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1294
1383
|
* Get lightweight stats for dashboard widget
|
|
1295
1384
|
*/
|
|
1296
1385
|
async getMonitoringStats(ctx) {
|
|
1297
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
1386
|
+
const monitoringService = strapi2.plugin(pluginId$5).service("monitoring");
|
|
1298
1387
|
const connectionStats = monitoringService.getConnectionStats();
|
|
1299
1388
|
const eventStats = monitoringService.getEventStats();
|
|
1300
1389
|
ctx.body = {
|
|
@@ -1320,10 +1409,11 @@ const refreshThrottle = /* @__PURE__ */ new Map();
|
|
|
1320
1409
|
const SESSION_TTL = 10 * 60 * 1e3;
|
|
1321
1410
|
const REFRESH_COOLDOWN = 3 * 1e3;
|
|
1322
1411
|
const CLEANUP_INTERVAL = 2 * 60 * 1e3;
|
|
1412
|
+
let tokenCleanupInterval = null;
|
|
1323
1413
|
const hashToken = (token) => {
|
|
1324
1414
|
return createHash("sha256").update(token).digest("hex");
|
|
1325
1415
|
};
|
|
1326
|
-
|
|
1416
|
+
const runTokenCleanup = () => {
|
|
1327
1417
|
const now = Date.now();
|
|
1328
1418
|
let cleaned = 0;
|
|
1329
1419
|
for (const [tokenHash, session] of sessionTokens.entries()) {
|
|
@@ -1340,8 +1430,23 @@ setInterval(() => {
|
|
|
1340
1430
|
if (cleaned > 0) {
|
|
1341
1431
|
console.log(`[plugin-io] [CLEANUP] Removed ${cleaned} expired session tokens`);
|
|
1342
1432
|
}
|
|
1343
|
-
}
|
|
1433
|
+
};
|
|
1434
|
+
const startTokenCleanup = () => {
|
|
1435
|
+
if (!tokenCleanupInterval) {
|
|
1436
|
+
tokenCleanupInterval = setInterval(runTokenCleanup, CLEANUP_INTERVAL);
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
const stopTokenCleanup = () => {
|
|
1440
|
+
if (tokenCleanupInterval) {
|
|
1441
|
+
clearInterval(tokenCleanupInterval);
|
|
1442
|
+
tokenCleanupInterval = null;
|
|
1443
|
+
}
|
|
1444
|
+
};
|
|
1344
1445
|
var presence$3 = ({ strapi: strapi2 }) => ({
|
|
1446
|
+
/**
|
|
1447
|
+
* Stops the background token cleanup interval (called on plugin destroy)
|
|
1448
|
+
*/
|
|
1449
|
+
stopTokenCleanup,
|
|
1345
1450
|
/**
|
|
1346
1451
|
* Creates a session token for admin users to connect to Socket.IO
|
|
1347
1452
|
* Implements rate limiting and secure token storage
|
|
@@ -1360,6 +1465,7 @@ var presence$3 = ({ strapi: strapi2 }) => ({
|
|
|
1360
1465
|
strapi2.log.warn(`[plugin-io] Rate limit: User ${adminUser.id} must wait ${waitTime}s`);
|
|
1361
1466
|
return ctx.tooManyRequests(`Please wait ${waitTime} seconds before requesting a new session`);
|
|
1362
1467
|
}
|
|
1468
|
+
startTokenCleanup();
|
|
1363
1469
|
try {
|
|
1364
1470
|
const token = randomUUID();
|
|
1365
1471
|
const tokenHash = hashToken(token);
|
|
@@ -1460,6 +1566,26 @@ var presence$3 = ({ strapi: strapi2 }) => ({
|
|
|
1460
1566
|
strapi2.log.info(`[plugin-io] Invalidated ${invalidated} sessions for user ${userId}`);
|
|
1461
1567
|
return invalidated;
|
|
1462
1568
|
},
|
|
1569
|
+
/**
|
|
1570
|
+
* Returns all active (non-expired) admin sessions
|
|
1571
|
+
* Used by admin strategy for broadcasting to connected admin users
|
|
1572
|
+
* @returns {Array} Array of active session objects
|
|
1573
|
+
*/
|
|
1574
|
+
getActiveSessions() {
|
|
1575
|
+
const now = Date.now();
|
|
1576
|
+
const activeSessions = [];
|
|
1577
|
+
for (const session of sessionTokens.values()) {
|
|
1578
|
+
if (session.expiresAt > now) {
|
|
1579
|
+
activeSessions.push({
|
|
1580
|
+
userId: session.userId,
|
|
1581
|
+
user: session.user,
|
|
1582
|
+
createdAt: session.createdAt,
|
|
1583
|
+
expiresAt: session.expiresAt
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
return activeSessions;
|
|
1588
|
+
},
|
|
1463
1589
|
/**
|
|
1464
1590
|
* Gets session statistics (for monitoring) - internal method
|
|
1465
1591
|
* @returns {object} Session statistics
|
|
@@ -1931,7 +2057,7 @@ lodash_min.exports;
|
|
|
1931
2057
|
function Q(n2) {
|
|
1932
2058
|
return n2.match(Fr) || [];
|
|
1933
2059
|
}
|
|
1934
|
-
var X, nn = "4.17.
|
|
2060
|
+
var X, nn = "4.17.23", tn = 200, rn = "Unsupported core-js use. Try https://npms.io/search?q=ponyfill.", en = "Expected a function", un = "Invalid `variable` option passed into `_.template`", on = "__lodash_hash_undefined__", fn = 500, cn = "__lodash_placeholder__", an = 1, ln = 2, sn = 4, hn = 1, pn = 2, _n = 1, vn = 2, gn = 4, yn = 8, dn = 16, bn = 32, wn = 64, mn = 128, xn = 256, jn = 512, An = 30, kn = "...", On = 800, In = 16, Rn = 1, zn = 2, En = 3, Sn = 1 / 0, Wn = 9007199254740991, Ln = 17976931348623157e292, Cn = NaN, Un = 4294967295, Bn = Un - 1, Tn = Un >>> 1, $n = [["ary", mn], ["bind", _n], ["bindKey", vn], ["curry", yn], ["curryRight", dn], ["flip", jn], ["partial", bn], ["partialRight", wn], ["rearg", xn]], Dn = "[object Arguments]", Mn = "[object Array]", Fn = "[object AsyncFunction]", Nn = "[object Boolean]", Pn = "[object Date]", qn = "[object DOMException]", Zn = "[object Error]", Kn = "[object Function]", Vn = "[object GeneratorFunction]", Gn = "[object Map]", Hn = "[object Number]", Jn = "[object Null]", Yn = "[object Object]", Qn = "[object Promise]", Xn = "[object Proxy]", nt = "[object RegExp]", tt = "[object Set]", rt = "[object String]", et = "[object Symbol]", ut = "[object Undefined]", it = "[object WeakMap]", ot = "[object WeakSet]", ft = "[object ArrayBuffer]", ct = "[object DataView]", at = "[object Float32Array]", lt = "[object Float64Array]", st = "[object Int8Array]", ht = "[object Int16Array]", pt = "[object Int32Array]", _t = "[object Uint8Array]", vt = "[object Uint8ClampedArray]", gt = "[object Uint16Array]", yt = "[object Uint32Array]", dt = /\b__p \+= '';/g, bt = /\b(__p \+=) '' \+/g, wt = /(__e\(.*?\)|\b__t\)) \+\n'';/g, mt = /&(?:amp|lt|gt|quot|#39);/g, xt = /[&<>"']/g, jt = RegExp(mt.source), At = RegExp(xt.source), kt = /<%-([\s\S]+?)%>/g, Ot = /<%([\s\S]+?)%>/g, It = /<%=([\s\S]+?)%>/g, Rt = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, zt = /^\w*$/, Et = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g, St = /[\\^$.*+?()[\]{}|]/g, Wt = RegExp(St.source), Lt = /^\s+/, Ct = /\s/, Ut = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, Bt = /\{\n\/\* \[wrapped with (.+)\] \*/, Tt = /,? & /, $t = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g, Dt = /[()=,{}\[\]\/\s]/, Mt = /\\(\\)?/g, Ft = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g, Nt = /\w*$/, Pt = /^[-+]0x[0-9a-f]+$/i, qt = /^0b[01]+$/i, Zt = /^\[object .+?Constructor\]$/, Kt = /^0o[0-7]+$/i, Vt = /^(?:0|[1-9]\d*)$/, Gt = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g, Ht = /($^)/, Jt = /['\n\r\u2028\u2029\\]/g, Yt = "\\ud800-\\udfff", Qt = "\\u0300-\\u036f", Xt = "\\ufe20-\\ufe2f", nr = "\\u20d0-\\u20ff", tr = Qt + Xt + nr, rr = "\\u2700-\\u27bf", er = "a-z\\xdf-\\xf6\\xf8-\\xff", ur = "\\xac\\xb1\\xd7\\xf7", ir = "\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf", or = "\\u2000-\\u206f", fr = " \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000", cr = "A-Z\\xc0-\\xd6\\xd8-\\xde", ar = "\\ufe0e\\ufe0f", lr = ur + ir + or + fr, sr = "['’]", hr = "[" + Yt + "]", pr = "[" + lr + "]", _r = "[" + tr + "]", vr = "\\d+", gr = "[" + rr + "]", yr = "[" + er + "]", dr = "[^" + Yt + lr + vr + rr + er + cr + "]", br = "\\ud83c[\\udffb-\\udfff]", wr = "(?:" + _r + "|" + br + ")", mr = "[^" + Yt + "]", xr = "(?:\\ud83c[\\udde6-\\uddff]){2}", jr = "[\\ud800-\\udbff][\\udc00-\\udfff]", Ar = "[" + cr + "]", kr = "\\u200d", Or = "(?:" + yr + "|" + dr + ")", Ir = "(?:" + Ar + "|" + dr + ")", Rr = "(?:" + sr + "(?:d|ll|m|re|s|t|ve))?", zr = "(?:" + sr + "(?:D|LL|M|RE|S|T|VE))?", Er = wr + "?", Sr = "[" + ar + "]?", Wr = "(?:" + kr + "(?:" + [mr, xr, jr].join("|") + ")" + Sr + Er + ")*", Lr = "\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])", Cr = "\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])", Ur = Sr + Er + Wr, Br = "(?:" + [gr, xr, jr].join("|") + ")" + Ur, Tr = "(?:" + [mr + _r + "?", _r, xr, jr, hr].join("|") + ")", $r = RegExp(sr, "g"), Dr = RegExp(_r, "g"), Mr = RegExp(br + "(?=" + br + ")|" + Tr + Ur, "g"), Fr = RegExp([Ar + "?" + yr + "+" + Rr + "(?=" + [pr, Ar, "$"].join("|") + ")", Ir + "+" + zr + "(?=" + [pr, Ar + Or, "$"].join("|") + ")", Ar + "?" + Or + "+" + Rr, Ar + "+" + zr, Cr, Lr, vr, Br].join("|"), "g"), Nr = RegExp("[" + kr + Yt + tr + ar + "]"), Pr = /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/, qr = ["Array", "Buffer", "DataView", "Date", "Error", "Float32Array", "Float64Array", "Function", "Int8Array", "Int16Array", "Int32Array", "Map", "Math", "Object", "Promise", "RegExp", "Set", "String", "Symbol", "TypeError", "Uint8Array", "Uint8ClampedArray", "Uint16Array", "Uint32Array", "WeakMap", "_", "clearTimeout", "isFinite", "parseInt", "setTimeout"], Zr = -1, Kr = {};
|
|
1935
2061
|
Kr[at] = Kr[lt] = Kr[st] = Kr[ht] = Kr[pt] = Kr[_t] = Kr[vt] = Kr[gt] = Kr[yt] = true, Kr[Dn] = Kr[Mn] = Kr[ft] = Kr[Nn] = Kr[ct] = Kr[Pn] = Kr[Zn] = Kr[Kn] = Kr[Gn] = Kr[Hn] = Kr[Yn] = Kr[nt] = Kr[tt] = Kr[rt] = Kr[it] = false;
|
|
1936
2062
|
var Vr = {};
|
|
1937
2063
|
Vr[Dn] = Vr[Mn] = Vr[ft] = Vr[ct] = Vr[Nn] = Vr[Pn] = Vr[at] = Vr[lt] = Vr[st] = Vr[ht] = Vr[pt] = Vr[Gn] = Vr[Hn] = Vr[Yn] = Vr[nt] = Vr[tt] = Vr[rt] = Vr[et] = Vr[_t] = Vr[vt] = Vr[gt] = Vr[yt] = true, Vr[Zn] = Vr[Kn] = Vr[it] = false;
|
|
@@ -2784,7 +2910,21 @@ lodash_min.exports;
|
|
|
2784
2910
|
return a2;
|
|
2785
2911
|
}
|
|
2786
2912
|
function yu(n2, t2) {
|
|
2787
|
-
|
|
2913
|
+
t2 = ku(t2, n2);
|
|
2914
|
+
var r2 = -1, e2 = t2.length;
|
|
2915
|
+
if (!e2) return true;
|
|
2916
|
+
for (var u2 = null == n2 || "object" != typeof n2 && "function" != typeof n2; ++r2 < e2; ) {
|
|
2917
|
+
var i2 = t2[r2];
|
|
2918
|
+
if ("string" == typeof i2) {
|
|
2919
|
+
if ("__proto__" === i2 && !bl.call(n2, "__proto__")) return false;
|
|
2920
|
+
if ("constructor" === i2 && r2 + 1 < e2 && "string" == typeof t2[r2 + 1] && "prototype" === t2[r2 + 1]) {
|
|
2921
|
+
if (u2 && 0 === r2) continue;
|
|
2922
|
+
return false;
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
var o2 = Gi(n2, t2);
|
|
2927
|
+
return null == o2 || delete o2[no(jo(t2))];
|
|
2788
2928
|
}
|
|
2789
2929
|
function du(n2, t2, r2, e2) {
|
|
2790
2930
|
return fu(n2, t2, r2(_e2(n2, t2)), e2);
|
|
@@ -5636,7 +5776,7 @@ lodash.exports;
|
|
|
5636
5776
|
(function(module, exports$1) {
|
|
5637
5777
|
(function() {
|
|
5638
5778
|
var undefined$1;
|
|
5639
|
-
var VERSION = "4.17.
|
|
5779
|
+
var VERSION = "4.17.23";
|
|
5640
5780
|
var LARGE_ARRAY_SIZE2 = 200;
|
|
5641
5781
|
var CORE_ERROR_TEXT = "Unsupported core-js use. Try https://npms.io/search?q=ponyfill.", FUNC_ERROR_TEXT2 = "Expected a function", INVALID_TEMPL_VAR_ERROR_TEXT = "Invalid `variable` option passed into `_.template`";
|
|
5642
5782
|
var HASH_UNDEFINED2 = "__lodash_hash_undefined__";
|
|
@@ -7564,8 +7704,28 @@ lodash.exports;
|
|
|
7564
7704
|
}
|
|
7565
7705
|
function baseUnset(object2, path2) {
|
|
7566
7706
|
path2 = castPath2(path2, object2);
|
|
7567
|
-
|
|
7568
|
-
|
|
7707
|
+
var index2 = -1, length = path2.length;
|
|
7708
|
+
if (!length) {
|
|
7709
|
+
return true;
|
|
7710
|
+
}
|
|
7711
|
+
var isRootPrimitive = object2 == null || typeof object2 !== "object" && typeof object2 !== "function";
|
|
7712
|
+
while (++index2 < length) {
|
|
7713
|
+
var key = path2[index2];
|
|
7714
|
+
if (typeof key !== "string") {
|
|
7715
|
+
continue;
|
|
7716
|
+
}
|
|
7717
|
+
if (key === "__proto__" && !hasOwnProperty2.call(object2, "__proto__")) {
|
|
7718
|
+
return false;
|
|
7719
|
+
}
|
|
7720
|
+
if (key === "constructor" && index2 + 1 < length && typeof path2[index2 + 1] === "string" && path2[index2 + 1] === "prototype") {
|
|
7721
|
+
if (isRootPrimitive && index2 === 0) {
|
|
7722
|
+
continue;
|
|
7723
|
+
}
|
|
7724
|
+
return false;
|
|
7725
|
+
}
|
|
7726
|
+
}
|
|
7727
|
+
var obj = parent(object2, path2);
|
|
7728
|
+
return obj == null || delete obj[toKey2(last(path2))];
|
|
7569
7729
|
}
|
|
7570
7730
|
function baseUpdate(object2, path2, updater, customizer) {
|
|
7571
7731
|
return baseSet(object2, path2, updater(baseGet2(object2, path2)), customizer);
|
|
@@ -11218,73 +11378,76 @@ function envFn(key, defaultValue) {
|
|
|
11218
11378
|
function getKey(key) {
|
|
11219
11379
|
return process.env[key] ?? "";
|
|
11220
11380
|
}
|
|
11221
|
-
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11234
|
-
|
|
11235
|
-
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
throw new Error(`Invalid json environment variable ${key}: ${error2.message}`);
|
|
11249
|
-
}
|
|
11250
|
-
throw error2;
|
|
11251
|
-
}
|
|
11252
|
-
},
|
|
11253
|
-
array(key, defaultValue) {
|
|
11254
|
-
if (!___default.has(process.env, key)) {
|
|
11255
|
-
return defaultValue;
|
|
11256
|
-
}
|
|
11257
|
-
let value = getKey(key);
|
|
11258
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
11259
|
-
value = value.substring(1, value.length - 1);
|
|
11260
|
-
}
|
|
11261
|
-
return value.split(",").map((v) => {
|
|
11262
|
-
return ___default.trim(___default.trim(v, " "), '"');
|
|
11263
|
-
});
|
|
11264
|
-
},
|
|
11265
|
-
date(key, defaultValue) {
|
|
11266
|
-
if (!___default.has(process.env, key)) {
|
|
11267
|
-
return defaultValue;
|
|
11268
|
-
}
|
|
11269
|
-
return new Date(getKey(key));
|
|
11270
|
-
},
|
|
11271
|
-
/**
|
|
11272
|
-
* Gets a value from env that matches oneOf provided values
|
|
11273
|
-
* @param {string} key
|
|
11274
|
-
* @param {string[]} expectedValues
|
|
11275
|
-
* @param {string|undefined} defaultValue
|
|
11276
|
-
* @returns {string|undefined}
|
|
11277
|
-
*/
|
|
11278
|
-
oneOf(key, expectedValues, defaultValue) {
|
|
11279
|
-
if (!expectedValues) {
|
|
11280
|
-
throw new Error(`env.oneOf requires expectedValues`);
|
|
11281
|
-
}
|
|
11282
|
-
if (defaultValue && !expectedValues.includes(defaultValue)) {
|
|
11283
|
-
throw new Error(`env.oneOf requires defaultValue to be included in expectedValues`);
|
|
11381
|
+
function int$1(key, defaultValue) {
|
|
11382
|
+
if (!___default.has(process.env, key)) {
|
|
11383
|
+
return defaultValue;
|
|
11384
|
+
}
|
|
11385
|
+
return parseInt(getKey(key), 10);
|
|
11386
|
+
}
|
|
11387
|
+
function float$1(key, defaultValue) {
|
|
11388
|
+
if (!___default.has(process.env, key)) {
|
|
11389
|
+
return defaultValue;
|
|
11390
|
+
}
|
|
11391
|
+
return parseFloat(getKey(key));
|
|
11392
|
+
}
|
|
11393
|
+
function bool$1(key, defaultValue) {
|
|
11394
|
+
if (!___default.has(process.env, key)) {
|
|
11395
|
+
return defaultValue;
|
|
11396
|
+
}
|
|
11397
|
+
return getKey(key) === "true";
|
|
11398
|
+
}
|
|
11399
|
+
function json$1(key, defaultValue) {
|
|
11400
|
+
if (!___default.has(process.env, key)) {
|
|
11401
|
+
return defaultValue;
|
|
11402
|
+
}
|
|
11403
|
+
try {
|
|
11404
|
+
return JSON.parse(getKey(key));
|
|
11405
|
+
} catch (error2) {
|
|
11406
|
+
if (error2 instanceof Error) {
|
|
11407
|
+
throw new Error(`Invalid json environment variable ${key}: ${error2.message}`);
|
|
11284
11408
|
}
|
|
11285
|
-
|
|
11286
|
-
|
|
11409
|
+
throw error2;
|
|
11410
|
+
}
|
|
11411
|
+
}
|
|
11412
|
+
function array$1(key, defaultValue) {
|
|
11413
|
+
if (!___default.has(process.env, key)) {
|
|
11414
|
+
return defaultValue;
|
|
11415
|
+
}
|
|
11416
|
+
let value = getKey(key);
|
|
11417
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
11418
|
+
value = value.substring(1, value.length - 1);
|
|
11419
|
+
}
|
|
11420
|
+
return value.split(",").map((v) => {
|
|
11421
|
+
return ___default.trim(___default.trim(v, " "), '"');
|
|
11422
|
+
});
|
|
11423
|
+
}
|
|
11424
|
+
function date$1(key, defaultValue) {
|
|
11425
|
+
if (!___default.has(process.env, key)) {
|
|
11426
|
+
return defaultValue;
|
|
11287
11427
|
}
|
|
11428
|
+
return new Date(getKey(key));
|
|
11429
|
+
}
|
|
11430
|
+
function oneOf(key, expectedValues, defaultValue) {
|
|
11431
|
+
if (!expectedValues) {
|
|
11432
|
+
throw new Error(`env.oneOf requires expectedValues`);
|
|
11433
|
+
}
|
|
11434
|
+
if (defaultValue && !expectedValues.includes(defaultValue)) {
|
|
11435
|
+
throw new Error(`env.oneOf requires defaultValue to be included in expectedValues`);
|
|
11436
|
+
}
|
|
11437
|
+
const rawValue = env(key, defaultValue);
|
|
11438
|
+
if (rawValue !== void 0 && expectedValues.includes(rawValue)) {
|
|
11439
|
+
return rawValue;
|
|
11440
|
+
}
|
|
11441
|
+
return defaultValue;
|
|
11442
|
+
}
|
|
11443
|
+
const utils$9 = {
|
|
11444
|
+
int: int$1,
|
|
11445
|
+
float: float$1,
|
|
11446
|
+
bool: bool$1,
|
|
11447
|
+
json: json$1,
|
|
11448
|
+
array: array$1,
|
|
11449
|
+
date: date$1,
|
|
11450
|
+
oneOf
|
|
11288
11451
|
};
|
|
11289
11452
|
const env = Object.assign(envFn, utils$9);
|
|
11290
11453
|
const SINGLE_TYPE = "singleType";
|
|
@@ -11309,6 +11472,22 @@ const constants$6 = {
|
|
|
11309
11472
|
SINGLE_TYPE,
|
|
11310
11473
|
COLLECTION_TYPE
|
|
11311
11474
|
};
|
|
11475
|
+
const ID_FIELDS = [
|
|
11476
|
+
ID_ATTRIBUTE$4,
|
|
11477
|
+
DOC_ID_ATTRIBUTE$4
|
|
11478
|
+
];
|
|
11479
|
+
const MORPH_TO_KEYS = [
|
|
11480
|
+
"__type"
|
|
11481
|
+
];
|
|
11482
|
+
const DYNAMIC_ZONE_KEYS = [
|
|
11483
|
+
"__component"
|
|
11484
|
+
];
|
|
11485
|
+
const RELATION_OPERATION_KEYS = [
|
|
11486
|
+
"connect",
|
|
11487
|
+
"disconnect",
|
|
11488
|
+
"set",
|
|
11489
|
+
"options"
|
|
11490
|
+
];
|
|
11312
11491
|
const getTimestamps = (model) => {
|
|
11313
11492
|
const attributes = [];
|
|
11314
11493
|
if (fp.has(CREATED_AT_ATTRIBUTE, model.attributes)) {
|
|
@@ -11412,10 +11591,10 @@ const HAS_RELATION_REORDERING = [
|
|
|
11412
11591
|
"oneToMany"
|
|
11413
11592
|
];
|
|
11414
11593
|
const hasRelationReordering = (attribute) => isRelationalAttribute(attribute) && HAS_RELATION_REORDERING.includes(attribute.relation);
|
|
11415
|
-
const isComponentAttribute = (attribute) => [
|
|
11594
|
+
const isComponentAttribute = (attribute) => !!attribute && [
|
|
11416
11595
|
"component",
|
|
11417
11596
|
"dynamiczone"
|
|
11418
|
-
].includes(attribute
|
|
11597
|
+
].includes(attribute.type);
|
|
11419
11598
|
const isDynamicZoneAttribute = (attribute) => !!attribute && attribute.type === "dynamiczone";
|
|
11420
11599
|
const isMorphToRelationalAttribute = (attribute) => {
|
|
11421
11600
|
return !!attribute && isRelationalAttribute(attribute) && attribute.relation?.startsWith?.("morphTo");
|
|
@@ -11452,6 +11631,10 @@ const getContentTypeRoutePrefix = (contentType) => {
|
|
|
11452
11631
|
};
|
|
11453
11632
|
const contentTypes$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
11454
11633
|
__proto__: null,
|
|
11634
|
+
DYNAMIC_ZONE_KEYS,
|
|
11635
|
+
ID_FIELDS,
|
|
11636
|
+
MORPH_TO_KEYS,
|
|
11637
|
+
RELATION_OPERATION_KEYS,
|
|
11455
11638
|
constants: constants$6,
|
|
11456
11639
|
getComponentAttributes,
|
|
11457
11640
|
getContentTypeRoutePrefix,
|
|
@@ -11637,12 +11820,22 @@ const providerFactory = (options = {}) => {
|
|
|
11637
11820
|
}
|
|
11638
11821
|
};
|
|
11639
11822
|
};
|
|
11823
|
+
const parallelWithOrderedErrors = async (promises) => {
|
|
11824
|
+
const results = await Promise.allSettled(promises);
|
|
11825
|
+
for (let i = 0; i < results.length; i += 1) {
|
|
11826
|
+
const result = results[i];
|
|
11827
|
+
if (result.status === "rejected") {
|
|
11828
|
+
throw result.reason;
|
|
11829
|
+
}
|
|
11830
|
+
}
|
|
11831
|
+
return results.map((r) => r.value);
|
|
11832
|
+
};
|
|
11640
11833
|
const traverseEntity = async (visitor2, options, entity) => {
|
|
11641
11834
|
const { path: path2 = {
|
|
11642
11835
|
raw: null,
|
|
11643
11836
|
attribute: null,
|
|
11644
11837
|
rawWithIndices: null
|
|
11645
|
-
}, schema: schema2, getModel } = options;
|
|
11838
|
+
}, schema: schema2, getModel, allowedExtraRootKeys } = options;
|
|
11646
11839
|
let parent = options.parent;
|
|
11647
11840
|
const traverseMorphRelationTarget = async (visitor3, path3, entry) => {
|
|
11648
11841
|
const targetSchema = getModel(entry.__type);
|
|
@@ -11650,7 +11843,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11650
11843
|
schema: targetSchema,
|
|
11651
11844
|
path: path3,
|
|
11652
11845
|
getModel,
|
|
11653
|
-
parent
|
|
11846
|
+
parent,
|
|
11847
|
+
allowedExtraRootKeys
|
|
11654
11848
|
};
|
|
11655
11849
|
return traverseEntity(visitor3, traverseOptions, entry);
|
|
11656
11850
|
};
|
|
@@ -11659,7 +11853,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11659
11853
|
schema: schema3,
|
|
11660
11854
|
path: path3,
|
|
11661
11855
|
getModel,
|
|
11662
|
-
parent
|
|
11856
|
+
parent,
|
|
11857
|
+
allowedExtraRootKeys
|
|
11663
11858
|
};
|
|
11664
11859
|
return traverseEntity(visitor3, traverseOptions, entry);
|
|
11665
11860
|
};
|
|
@@ -11670,7 +11865,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11670
11865
|
schema: targetSchema,
|
|
11671
11866
|
path: path3,
|
|
11672
11867
|
getModel,
|
|
11673
|
-
parent
|
|
11868
|
+
parent,
|
|
11869
|
+
allowedExtraRootKeys
|
|
11674
11870
|
};
|
|
11675
11871
|
return traverseEntity(visitor3, traverseOptions, entry);
|
|
11676
11872
|
};
|
|
@@ -11679,7 +11875,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11679
11875
|
schema: schema3,
|
|
11680
11876
|
path: path3,
|
|
11681
11877
|
getModel,
|
|
11682
|
-
parent
|
|
11878
|
+
parent,
|
|
11879
|
+
allowedExtraRootKeys
|
|
11683
11880
|
};
|
|
11684
11881
|
return traverseEntity(visitor3, traverseOptions, entry);
|
|
11685
11882
|
};
|
|
@@ -11689,7 +11886,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11689
11886
|
schema: targetSchema,
|
|
11690
11887
|
path: path3,
|
|
11691
11888
|
getModel,
|
|
11692
|
-
parent
|
|
11889
|
+
parent,
|
|
11890
|
+
allowedExtraRootKeys
|
|
11693
11891
|
};
|
|
11694
11892
|
return traverseEntity(visitor3, traverseOptions, entry);
|
|
11695
11893
|
};
|
|
@@ -11720,7 +11918,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11720
11918
|
attribute,
|
|
11721
11919
|
path: newPath,
|
|
11722
11920
|
getModel,
|
|
11723
|
-
parent
|
|
11921
|
+
parent,
|
|
11922
|
+
allowedExtraRootKeys
|
|
11724
11923
|
};
|
|
11725
11924
|
await visitor2(visitorOptions, visitorUtils);
|
|
11726
11925
|
const value = copy[key];
|
|
@@ -11737,15 +11936,13 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11737
11936
|
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
|
11738
11937
|
const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
|
|
11739
11938
|
if (fp.isArray(value)) {
|
|
11740
|
-
|
|
11741
|
-
for (let i2 = 0; i2 < value.length; i2 += 1) {
|
|
11939
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i2) => {
|
|
11742
11940
|
const arrayPath = {
|
|
11743
11941
|
...newPath,
|
|
11744
11942
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i2}` : `${newPath.rawWithIndices}.${i2}`
|
|
11745
11943
|
};
|
|
11746
|
-
|
|
11747
|
-
}
|
|
11748
|
-
copy[key] = res;
|
|
11944
|
+
return method(visitor2, arrayPath, item);
|
|
11945
|
+
}));
|
|
11749
11946
|
} else {
|
|
11750
11947
|
copy[key] = await method(visitor2, newPath, value);
|
|
11751
11948
|
}
|
|
@@ -11759,15 +11956,13 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11759
11956
|
path: newPath
|
|
11760
11957
|
};
|
|
11761
11958
|
if (fp.isArray(value)) {
|
|
11762
|
-
|
|
11763
|
-
for (let i2 = 0; i2 < value.length; i2 += 1) {
|
|
11959
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i2) => {
|
|
11764
11960
|
const arrayPath = {
|
|
11765
11961
|
...newPath,
|
|
11766
11962
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i2}` : `${newPath.rawWithIndices}.${i2}`
|
|
11767
11963
|
};
|
|
11768
|
-
|
|
11769
|
-
}
|
|
11770
|
-
copy[key] = res;
|
|
11964
|
+
return traverseMediaTarget(visitor2, arrayPath, item);
|
|
11965
|
+
}));
|
|
11771
11966
|
} else {
|
|
11772
11967
|
copy[key] = await traverseMediaTarget(visitor2, newPath, value);
|
|
11773
11968
|
}
|
|
@@ -11782,15 +11977,13 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11782
11977
|
};
|
|
11783
11978
|
const targetSchema = getModel(attribute.component);
|
|
11784
11979
|
if (fp.isArray(value)) {
|
|
11785
|
-
|
|
11786
|
-
for (let i2 = 0; i2 < value.length; i2 += 1) {
|
|
11980
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i2) => {
|
|
11787
11981
|
const arrayPath = {
|
|
11788
11982
|
...newPath,
|
|
11789
11983
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i2}` : `${newPath.rawWithIndices}.${i2}`
|
|
11790
11984
|
};
|
|
11791
|
-
|
|
11792
|
-
}
|
|
11793
|
-
copy[key] = res;
|
|
11985
|
+
return traverseComponent(visitor2, arrayPath, targetSchema, item);
|
|
11986
|
+
}));
|
|
11794
11987
|
} else {
|
|
11795
11988
|
copy[key] = await traverseComponent(visitor2, newPath, targetSchema, value);
|
|
11796
11989
|
}
|
|
@@ -11803,15 +11996,13 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11803
11996
|
attribute,
|
|
11804
11997
|
path: newPath
|
|
11805
11998
|
};
|
|
11806
|
-
|
|
11807
|
-
for (let i2 = 0; i2 < value.length; i2 += 1) {
|
|
11999
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i2) => {
|
|
11808
12000
|
const arrayPath = {
|
|
11809
12001
|
...newPath,
|
|
11810
12002
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i2}` : `${newPath.rawWithIndices}.${i2}`
|
|
11811
12003
|
};
|
|
11812
|
-
|
|
11813
|
-
}
|
|
11814
|
-
copy[key] = res;
|
|
12004
|
+
return visitDynamicZoneEntry(visitor2, arrayPath, item);
|
|
12005
|
+
}));
|
|
11815
12006
|
continue;
|
|
11816
12007
|
}
|
|
11817
12008
|
}
|
|
@@ -12557,6 +12748,23 @@ const generateInstallId = (projectId, installId) => {
|
|
|
12557
12748
|
return require$$1.randomUUID();
|
|
12558
12749
|
}
|
|
12559
12750
|
};
|
|
12751
|
+
const createModelCache = (getModelFn) => {
|
|
12752
|
+
const cache = /* @__PURE__ */ new Map();
|
|
12753
|
+
return {
|
|
12754
|
+
getModel(uid) {
|
|
12755
|
+
const cached = cache.get(uid);
|
|
12756
|
+
if (cached) {
|
|
12757
|
+
return cached;
|
|
12758
|
+
}
|
|
12759
|
+
const model = getModelFn(uid);
|
|
12760
|
+
cache.set(uid, model);
|
|
12761
|
+
return model;
|
|
12762
|
+
},
|
|
12763
|
+
clear() {
|
|
12764
|
+
cache.clear();
|
|
12765
|
+
}
|
|
12766
|
+
};
|
|
12767
|
+
};
|
|
12560
12768
|
var map$2;
|
|
12561
12769
|
try {
|
|
12562
12770
|
map$2 = Map;
|
|
@@ -14056,27 +14264,11 @@ Cache.prototype.set = function(key, value) {
|
|
|
14056
14264
|
return this._values[key] = value;
|
|
14057
14265
|
};
|
|
14058
14266
|
var SPLIT_REGEX = /[^.^\]^[]+|(?=\[\]|\.\.)/g, DIGIT_REGEX = /^\d+$/, LEAD_DIGIT_REGEX = /^\d/, SPEC_CHAR_REGEX = /[~`!#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g, CLEAN_QUOTES_REGEX = /^\s*(['"]?)(.*?)(\1)\s*$/, MAX_CACHE_SIZE = 512;
|
|
14059
|
-
var pathCache = new Cache(MAX_CACHE_SIZE)
|
|
14267
|
+
var pathCache = new Cache(MAX_CACHE_SIZE);
|
|
14268
|
+
new Cache(MAX_CACHE_SIZE);
|
|
14269
|
+
var getCache = new Cache(MAX_CACHE_SIZE);
|
|
14060
14270
|
var propertyExpr = {
|
|
14061
|
-
Cache,
|
|
14062
14271
|
split,
|
|
14063
|
-
normalizePath,
|
|
14064
|
-
setter: function(path2) {
|
|
14065
|
-
var parts = normalizePath(path2);
|
|
14066
|
-
return setCache.get(path2) || setCache.set(path2, function setter(obj, value) {
|
|
14067
|
-
var index2 = 0;
|
|
14068
|
-
var len = parts.length;
|
|
14069
|
-
var data = obj;
|
|
14070
|
-
while (index2 < len - 1) {
|
|
14071
|
-
var part = parts[index2];
|
|
14072
|
-
if (part === "__proto__" || part === "constructor" || part === "prototype") {
|
|
14073
|
-
return obj;
|
|
14074
|
-
}
|
|
14075
|
-
data = data[parts[index2++]];
|
|
14076
|
-
}
|
|
14077
|
-
data[parts[index2]] = value;
|
|
14078
|
-
});
|
|
14079
|
-
},
|
|
14080
14272
|
getter: function(path2, safe) {
|
|
14081
14273
|
var parts = normalizePath(path2);
|
|
14082
14274
|
return getCache.get(path2) || getCache.set(path2, function getter(data) {
|
|
@@ -14088,11 +14280,6 @@ var propertyExpr = {
|
|
|
14088
14280
|
return data;
|
|
14089
14281
|
});
|
|
14090
14282
|
},
|
|
14091
|
-
join: function(segments) {
|
|
14092
|
-
return segments.reduce(function(path2, part) {
|
|
14093
|
-
return path2 + (isQuoted(part) || DIGIT_REGEX.test(part) ? "[" + part + "]" : (path2 ? "." : "") + part);
|
|
14094
|
-
}, "");
|
|
14095
|
-
},
|
|
14096
14283
|
forEach: function(path2, cb, thisArg) {
|
|
14097
14284
|
forEach(Array.isArray(path2) ? path2 : split(path2), cb, thisArg);
|
|
14098
14285
|
}
|
|
@@ -16922,10 +17109,10 @@ const createTransformer = ({ getModel }) => {
|
|
|
16922
17109
|
}
|
|
16923
17110
|
return pageVal;
|
|
16924
17111
|
};
|
|
16925
|
-
const convertPageSizeQueryParams = (pageSize,
|
|
17112
|
+
const convertPageSizeQueryParams = (pageSize, _page) => {
|
|
16926
17113
|
const pageSizeVal = fp.toNumber(pageSize);
|
|
16927
17114
|
if (!fp.isInteger(pageSizeVal) || pageSizeVal <= 0) {
|
|
16928
|
-
throw new PaginationError(`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${
|
|
17115
|
+
throw new PaginationError(`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${pageSize}`);
|
|
16929
17116
|
}
|
|
16930
17117
|
return pageSizeVal;
|
|
16931
17118
|
};
|
|
@@ -17100,7 +17287,7 @@ const createTransformer = ({ getModel }) => {
|
|
|
17100
17287
|
query.page = convertPageQueryParams(page);
|
|
17101
17288
|
}
|
|
17102
17289
|
if (!fp.isNil(pageSize)) {
|
|
17103
|
-
query.pageSize = convertPageSizeQueryParams(pageSize
|
|
17290
|
+
query.pageSize = convertPageSizeQueryParams(pageSize);
|
|
17104
17291
|
}
|
|
17105
17292
|
if (!fp.isNil(start)) {
|
|
17106
17293
|
query.offset = convertStartQueryParams(start);
|
|
@@ -17248,7 +17435,7 @@ const createTransformer = ({ getModel }) => {
|
|
|
17248
17435
|
query.page = convertPageQueryParams(page);
|
|
17249
17436
|
}
|
|
17250
17437
|
if (!fp.isNil(pageSize)) {
|
|
17251
|
-
query.pageSize = convertPageSizeQueryParams(pageSize
|
|
17438
|
+
query.pageSize = convertPageSizeQueryParams(pageSize);
|
|
17252
17439
|
}
|
|
17253
17440
|
if (!fp.isNil(start)) {
|
|
17254
17441
|
query.offset = convertStartQueryParams(start);
|
|
@@ -17275,6 +17462,43 @@ const convertQueryParams = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
|
|
|
17275
17462
|
__proto__: null,
|
|
17276
17463
|
createTransformer
|
|
17277
17464
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
17465
|
+
const SHARED_QUERY_PARAM_KEYS = [
|
|
17466
|
+
"filters",
|
|
17467
|
+
"sort",
|
|
17468
|
+
"fields",
|
|
17469
|
+
"populate",
|
|
17470
|
+
"status",
|
|
17471
|
+
"locale",
|
|
17472
|
+
"page",
|
|
17473
|
+
"pageSize",
|
|
17474
|
+
"start",
|
|
17475
|
+
"limit",
|
|
17476
|
+
"_q",
|
|
17477
|
+
"hasPublishedVersion"
|
|
17478
|
+
];
|
|
17479
|
+
const ALLOWED_QUERY_PARAM_KEYS = [
|
|
17480
|
+
...SHARED_QUERY_PARAM_KEYS,
|
|
17481
|
+
"pagination",
|
|
17482
|
+
"count",
|
|
17483
|
+
"ordering"
|
|
17484
|
+
];
|
|
17485
|
+
const RESERVED_INPUT_PARAM_KEYS = [
|
|
17486
|
+
constants$6.ID_ATTRIBUTE,
|
|
17487
|
+
constants$6.DOC_ID_ATTRIBUTE
|
|
17488
|
+
];
|
|
17489
|
+
function getExtraQueryKeysFromRoute(route) {
|
|
17490
|
+
if (!route?.request?.query) return [];
|
|
17491
|
+
const coreKeys = new Set(ALLOWED_QUERY_PARAM_KEYS);
|
|
17492
|
+
return Object.keys(route.request.query).filter((key) => !coreKeys.has(key));
|
|
17493
|
+
}
|
|
17494
|
+
function getExtraRootKeysFromRouteBody(route) {
|
|
17495
|
+
const bodySchema = route?.request?.body?.["application/json"];
|
|
17496
|
+
if (!bodySchema || typeof bodySchema !== "object") return [];
|
|
17497
|
+
if ("shape" in bodySchema && typeof bodySchema.shape === "object") {
|
|
17498
|
+
return Object.keys(bodySchema.shape);
|
|
17499
|
+
}
|
|
17500
|
+
return [];
|
|
17501
|
+
}
|
|
17278
17502
|
var indentString$2 = (string2, count = 1, options) => {
|
|
17279
17503
|
options = {
|
|
17280
17504
|
indent: " ",
|
|
@@ -17662,6 +17886,35 @@ var removeRestrictedFields = (restrictedFields = null) => ({ key, path: { attrib
|
|
|
17662
17886
|
remove(key);
|
|
17663
17887
|
}
|
|
17664
17888
|
};
|
|
17889
|
+
const removeUnrecognizedFields = ({ key, attribute, path: path2, schema: schema2, parent, allowedExtraRootKeys }, { remove }) => {
|
|
17890
|
+
if (attribute) {
|
|
17891
|
+
return;
|
|
17892
|
+
}
|
|
17893
|
+
if (path2.attribute === null) {
|
|
17894
|
+
if (ID_FIELDS.includes(key)) {
|
|
17895
|
+
return;
|
|
17896
|
+
}
|
|
17897
|
+
if (allowedExtraRootKeys?.includes(key)) {
|
|
17898
|
+
return;
|
|
17899
|
+
}
|
|
17900
|
+
remove(key);
|
|
17901
|
+
return;
|
|
17902
|
+
}
|
|
17903
|
+
if (isMorphToRelationalAttribute(parent?.attribute) && MORPH_TO_KEYS.includes(key)) {
|
|
17904
|
+
return;
|
|
17905
|
+
}
|
|
17906
|
+
if (isComponentSchema(schema2) && isDynamicZoneAttribute(parent?.attribute) && DYNAMIC_ZONE_KEYS.includes(key)) {
|
|
17907
|
+
return;
|
|
17908
|
+
}
|
|
17909
|
+
if ((isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute)) && RELATION_OPERATION_KEYS.includes(key)) {
|
|
17910
|
+
return;
|
|
17911
|
+
}
|
|
17912
|
+
const canUseID = isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute) || isComponentAttribute(parent?.attribute);
|
|
17913
|
+
if (canUseID && ID_FIELDS.includes(key)) {
|
|
17914
|
+
return;
|
|
17915
|
+
}
|
|
17916
|
+
remove(key);
|
|
17917
|
+
};
|
|
17665
17918
|
const visitor$4 = ({ schema: schema2, key, value }, { set: set2 }) => {
|
|
17666
17919
|
if (key === "" && value === "*") {
|
|
17667
17920
|
const { attributes } = schema2;
|
|
@@ -17686,7 +17939,8 @@ const index$5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
17686
17939
|
removePassword: visitor$8,
|
|
17687
17940
|
removePrivate: visitor$7,
|
|
17688
17941
|
removeRestrictedFields,
|
|
17689
|
-
removeRestrictedRelations
|
|
17942
|
+
removeRestrictedRelations,
|
|
17943
|
+
removeUnrecognizedFields
|
|
17690
17944
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
17691
17945
|
const DEFAULT_PATH = {
|
|
17692
17946
|
raw: null,
|
|
@@ -18537,15 +18791,18 @@ const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
|
|
|
18537
18791
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
18538
18792
|
const createAPISanitizers = (opts) => {
|
|
18539
18793
|
const { getModel } = opts;
|
|
18540
|
-
const sanitizeInput = (data, schema2, { auth } = {}) => {
|
|
18794
|
+
const sanitizeInput = (data, schema2, { auth, strictParams = false, route } = {}) => {
|
|
18541
18795
|
if (!schema2) {
|
|
18542
18796
|
throw new Error("Missing schema in sanitizeInput");
|
|
18543
18797
|
}
|
|
18544
18798
|
if (fp.isArray(data)) {
|
|
18545
18799
|
return Promise.all(data.map((entry) => sanitizeInput(entry, schema2, {
|
|
18546
|
-
auth
|
|
18800
|
+
auth,
|
|
18801
|
+
strictParams,
|
|
18802
|
+
route
|
|
18547
18803
|
})));
|
|
18548
18804
|
}
|
|
18805
|
+
const allowedExtraRootKeys = getExtraRootKeysFromRouteBody(route);
|
|
18549
18806
|
const nonWritableAttributes = getNonWritableAttributes(schema2);
|
|
18550
18807
|
const transforms = [
|
|
18551
18808
|
// Remove first level ID in inputs
|
|
@@ -18557,6 +18814,13 @@ const createAPISanitizers = (opts) => {
|
|
|
18557
18814
|
getModel
|
|
18558
18815
|
})
|
|
18559
18816
|
];
|
|
18817
|
+
if (strictParams) {
|
|
18818
|
+
transforms.push(traverseEntity$1(removeUnrecognizedFields, {
|
|
18819
|
+
schema: schema2,
|
|
18820
|
+
getModel,
|
|
18821
|
+
allowedExtraRootKeys
|
|
18822
|
+
}));
|
|
18823
|
+
}
|
|
18560
18824
|
if (auth) {
|
|
18561
18825
|
transforms.push(traverseEntity$1(removeRestrictedRelations(auth), {
|
|
18562
18826
|
schema: schema2,
|
|
@@ -18564,6 +18828,28 @@ const createAPISanitizers = (opts) => {
|
|
|
18564
18828
|
}));
|
|
18565
18829
|
}
|
|
18566
18830
|
opts?.sanitizers?.input?.forEach((sanitizer) => transforms.push(sanitizer(schema2)));
|
|
18831
|
+
const routeBodySanitizeTransform = async (data2) => {
|
|
18832
|
+
if (!data2 || typeof data2 !== "object" || Array.isArray(data2)) return data2;
|
|
18833
|
+
const obj = data2;
|
|
18834
|
+
const bodySchema = route?.request?.body?.["application/json"];
|
|
18835
|
+
if (bodySchema && typeof bodySchema === "object" && "shape" in bodySchema) {
|
|
18836
|
+
const shape = bodySchema.shape;
|
|
18837
|
+
for (const key of Object.keys(shape)) {
|
|
18838
|
+
if (key === "data" || !(key in obj)) continue;
|
|
18839
|
+
const zodSchema = shape[key];
|
|
18840
|
+
if (zodSchema && typeof zodSchema.safeParse === "function") {
|
|
18841
|
+
const result = zodSchema.safeParse(obj[key]);
|
|
18842
|
+
if (result.success) {
|
|
18843
|
+
obj[key] = result.data;
|
|
18844
|
+
} else {
|
|
18845
|
+
delete obj[key];
|
|
18846
|
+
}
|
|
18847
|
+
}
|
|
18848
|
+
}
|
|
18849
|
+
}
|
|
18850
|
+
return data2;
|
|
18851
|
+
};
|
|
18852
|
+
transforms.push(routeBodySanitizeTransform);
|
|
18567
18853
|
return pipe$1(...transforms)(data);
|
|
18568
18854
|
};
|
|
18569
18855
|
const sanitizeOutput = async (data, schema2, { auth } = {}) => {
|
|
@@ -18594,7 +18880,7 @@ const createAPISanitizers = (opts) => {
|
|
|
18594
18880
|
opts?.sanitizers?.output?.forEach((sanitizer) => transforms.push(sanitizer(schema2)));
|
|
18595
18881
|
return pipe$1(...transforms)(data);
|
|
18596
18882
|
};
|
|
18597
|
-
const sanitizeQuery = async (query, schema2, { auth } = {}) => {
|
|
18883
|
+
const sanitizeQuery = async (query, schema2, { auth, strictParams = false, route } = {}) => {
|
|
18598
18884
|
if (!schema2) {
|
|
18599
18885
|
throw new Error("Missing schema in sanitizeQuery");
|
|
18600
18886
|
}
|
|
@@ -18624,6 +18910,30 @@ const createAPISanitizers = (opts) => {
|
|
|
18624
18910
|
populate: await sanitizePopulate(populate2, schema2)
|
|
18625
18911
|
});
|
|
18626
18912
|
}
|
|
18913
|
+
const extraQueryKeys = getExtraQueryKeysFromRoute(route);
|
|
18914
|
+
const routeQuerySchema = route?.request?.query;
|
|
18915
|
+
if (routeQuerySchema) {
|
|
18916
|
+
for (const key of extraQueryKeys) {
|
|
18917
|
+
if (key in query) {
|
|
18918
|
+
const zodSchema = routeQuerySchema[key];
|
|
18919
|
+
if (zodSchema && typeof zodSchema.safeParse === "function") {
|
|
18920
|
+
const result = zodSchema.safeParse(query[key]);
|
|
18921
|
+
if (result.success) {
|
|
18922
|
+
sanitizedQuery[key] = result.data;
|
|
18923
|
+
} else {
|
|
18924
|
+
delete sanitizedQuery[key];
|
|
18925
|
+
}
|
|
18926
|
+
}
|
|
18927
|
+
}
|
|
18928
|
+
}
|
|
18929
|
+
}
|
|
18930
|
+
if (strictParams) {
|
|
18931
|
+
const allowedKeys = [
|
|
18932
|
+
...ALLOWED_QUERY_PARAM_KEYS,
|
|
18933
|
+
...extraQueryKeys
|
|
18934
|
+
];
|
|
18935
|
+
return fp.pick(allowedKeys, sanitizedQuery);
|
|
18936
|
+
}
|
|
18627
18937
|
return sanitizedQuery;
|
|
18628
18938
|
};
|
|
18629
18939
|
const sanitizeFilters = (filters2, schema2, { auth } = {}) => {
|
|
@@ -18926,54 +19236,38 @@ var throwRestrictedFields = (restrictedFields = null) => ({ key, path: { attribu
|
|
|
18926
19236
|
});
|
|
18927
19237
|
}
|
|
18928
19238
|
};
|
|
18929
|
-
const
|
|
18930
|
-
constants$6.DOC_ID_ATTRIBUTE,
|
|
18931
|
-
constants$6.DOC_ID_ATTRIBUTE
|
|
18932
|
-
];
|
|
18933
|
-
const ALLOWED_ROOT_LEVEL_FIELDS = [
|
|
18934
|
-
...ID_FIELDS
|
|
18935
|
-
];
|
|
18936
|
-
const MORPH_TO_ALLOWED_FIELDS = [
|
|
18937
|
-
"__type"
|
|
18938
|
-
];
|
|
18939
|
-
const DYNAMIC_ZONE_ALLOWED_FIELDS = [
|
|
18940
|
-
"__component"
|
|
18941
|
-
];
|
|
18942
|
-
const RELATION_REORDERING_FIELDS = [
|
|
18943
|
-
"connect",
|
|
18944
|
-
"disconnect",
|
|
18945
|
-
"set",
|
|
18946
|
-
"options"
|
|
18947
|
-
];
|
|
18948
|
-
const throwUnrecognizedFields = ({ key, attribute, path: path2, schema: schema2, parent }) => {
|
|
19239
|
+
const throwUnrecognizedFields = ({ key, attribute, path: path2, schema: schema2, parent, allowedExtraRootKeys }, _visitorUtils) => {
|
|
18949
19240
|
if (attribute) {
|
|
18950
19241
|
return;
|
|
18951
19242
|
}
|
|
18952
19243
|
if (path2.attribute === null) {
|
|
18953
|
-
if (
|
|
19244
|
+
if (ID_FIELDS.includes(key)) {
|
|
19245
|
+
return;
|
|
19246
|
+
}
|
|
19247
|
+
if (allowedExtraRootKeys?.includes(key)) {
|
|
18954
19248
|
return;
|
|
18955
19249
|
}
|
|
18956
19250
|
return throwInvalidKey({
|
|
18957
19251
|
key,
|
|
18958
|
-
path: attribute
|
|
19252
|
+
path: path2.attribute
|
|
18959
19253
|
});
|
|
18960
19254
|
}
|
|
18961
|
-
if (isMorphToRelationalAttribute(parent?.attribute) &&
|
|
19255
|
+
if (isMorphToRelationalAttribute(parent?.attribute) && MORPH_TO_KEYS.includes(key)) {
|
|
18962
19256
|
return;
|
|
18963
19257
|
}
|
|
18964
|
-
if (isComponentSchema(schema2) && isDynamicZoneAttribute(parent?.attribute) &&
|
|
19258
|
+
if (isComponentSchema(schema2) && isDynamicZoneAttribute(parent?.attribute) && DYNAMIC_ZONE_KEYS.includes(key)) {
|
|
18965
19259
|
return;
|
|
18966
19260
|
}
|
|
18967
|
-
if (
|
|
19261
|
+
if ((isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute)) && RELATION_OPERATION_KEYS.includes(key)) {
|
|
18968
19262
|
return;
|
|
18969
19263
|
}
|
|
18970
|
-
const canUseID = isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute);
|
|
18971
|
-
if (canUseID &&
|
|
19264
|
+
const canUseID = isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute) || isComponentAttribute(parent?.attribute);
|
|
19265
|
+
if (canUseID && ID_FIELDS.includes(key)) {
|
|
18972
19266
|
return;
|
|
18973
19267
|
}
|
|
18974
19268
|
throwInvalidKey({
|
|
18975
19269
|
key,
|
|
18976
|
-
path: attribute
|
|
19270
|
+
path: path2.attribute
|
|
18977
19271
|
});
|
|
18978
19272
|
};
|
|
18979
19273
|
const index$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -19295,16 +19589,16 @@ const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
|
|
|
19295
19589
|
const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants$6;
|
|
19296
19590
|
const createAPIValidators = (opts) => {
|
|
19297
19591
|
const { getModel } = opts || {};
|
|
19298
|
-
const validateInput = async (data, schema2,
|
|
19592
|
+
const validateInput = async (data, schema2, options = {}) => {
|
|
19593
|
+
const { auth, route } = options;
|
|
19299
19594
|
if (!schema2) {
|
|
19300
19595
|
throw new Error("Missing schema in validateInput");
|
|
19301
19596
|
}
|
|
19302
19597
|
if (fp.isArray(data)) {
|
|
19303
|
-
await Promise.all(data.map((entry) => validateInput(entry, schema2,
|
|
19304
|
-
auth
|
|
19305
|
-
})));
|
|
19598
|
+
await Promise.all(data.map((entry) => validateInput(entry, schema2, options)));
|
|
19306
19599
|
return;
|
|
19307
19600
|
}
|
|
19601
|
+
const allowedExtraRootKeys = getExtraRootKeysFromRouteBody(route);
|
|
19308
19602
|
const nonWritableAttributes = getNonWritableAttributes(schema2);
|
|
19309
19603
|
const transforms = [
|
|
19310
19604
|
(data2) => {
|
|
@@ -19327,10 +19621,11 @@ const createAPIValidators = (opts) => {
|
|
|
19327
19621
|
schema: schema2,
|
|
19328
19622
|
getModel
|
|
19329
19623
|
}),
|
|
19330
|
-
// unrecognized attributes
|
|
19624
|
+
// unrecognized attributes (allowedExtraRootKeys = registered input param keys)
|
|
19331
19625
|
traverseEntity$1(throwUnrecognizedFields, {
|
|
19332
19626
|
schema: schema2,
|
|
19333
|
-
getModel
|
|
19627
|
+
getModel,
|
|
19628
|
+
allowedExtraRootKeys
|
|
19334
19629
|
})
|
|
19335
19630
|
];
|
|
19336
19631
|
if (auth) {
|
|
@@ -19342,6 +19637,28 @@ const createAPIValidators = (opts) => {
|
|
|
19342
19637
|
opts?.validators?.input?.forEach((validator) => transforms.push(validator(schema2)));
|
|
19343
19638
|
try {
|
|
19344
19639
|
await pipe$1(...transforms)(data);
|
|
19640
|
+
if (fp.isObject(data) && route?.request?.body?.["application/json"]) {
|
|
19641
|
+
const bodySchema = route.request.body["application/json"];
|
|
19642
|
+
if (typeof bodySchema === "object" && "shape" in bodySchema) {
|
|
19643
|
+
const shape = bodySchema.shape;
|
|
19644
|
+
const dataObj = data;
|
|
19645
|
+
for (const key of Object.keys(shape)) {
|
|
19646
|
+
if (key === "data" || !(key in dataObj)) continue;
|
|
19647
|
+
const zodSchema = shape[key];
|
|
19648
|
+
if (zodSchema && typeof zodSchema.parse === "function") {
|
|
19649
|
+
const result = zodSchema.safeParse(dataObj[key]);
|
|
19650
|
+
if (!result.success) {
|
|
19651
|
+
throw new ValidationError2(result.error?.message ?? "Validation failed", {
|
|
19652
|
+
key,
|
|
19653
|
+
path: null,
|
|
19654
|
+
source: "body",
|
|
19655
|
+
param: key
|
|
19656
|
+
});
|
|
19657
|
+
}
|
|
19658
|
+
}
|
|
19659
|
+
}
|
|
19660
|
+
}
|
|
19661
|
+
}
|
|
19345
19662
|
} catch (e) {
|
|
19346
19663
|
if (e instanceof ValidationError2) {
|
|
19347
19664
|
e.details.source = "body";
|
|
@@ -19349,10 +19666,52 @@ const createAPIValidators = (opts) => {
|
|
|
19349
19666
|
throw e;
|
|
19350
19667
|
}
|
|
19351
19668
|
};
|
|
19352
|
-
const validateQuery = async (query, schema2, { auth } = {}) => {
|
|
19669
|
+
const validateQuery = async (query, schema2, { auth, strictParams = false, route } = {}) => {
|
|
19353
19670
|
if (!schema2) {
|
|
19354
19671
|
throw new Error("Missing schema in validateQuery");
|
|
19355
19672
|
}
|
|
19673
|
+
if (strictParams) {
|
|
19674
|
+
const extraQueryKeys = getExtraQueryKeysFromRoute(route);
|
|
19675
|
+
const allowedKeys = [
|
|
19676
|
+
...ALLOWED_QUERY_PARAM_KEYS,
|
|
19677
|
+
...extraQueryKeys
|
|
19678
|
+
];
|
|
19679
|
+
for (const key of Object.keys(query)) {
|
|
19680
|
+
if (!allowedKeys.includes(key)) {
|
|
19681
|
+
try {
|
|
19682
|
+
throwInvalidKey({
|
|
19683
|
+
key,
|
|
19684
|
+
path: null
|
|
19685
|
+
});
|
|
19686
|
+
} catch (e) {
|
|
19687
|
+
if (e instanceof ValidationError2) {
|
|
19688
|
+
e.details.source = "query";
|
|
19689
|
+
e.details.param = key;
|
|
19690
|
+
}
|
|
19691
|
+
throw e;
|
|
19692
|
+
}
|
|
19693
|
+
}
|
|
19694
|
+
}
|
|
19695
|
+
const routeQuerySchema = route?.request?.query;
|
|
19696
|
+
if (routeQuerySchema) {
|
|
19697
|
+
for (const key of extraQueryKeys) {
|
|
19698
|
+
if (key in query) {
|
|
19699
|
+
const zodSchema = routeQuerySchema[key];
|
|
19700
|
+
if (zodSchema && typeof zodSchema.parse === "function") {
|
|
19701
|
+
const result = zodSchema.safeParse(query[key]);
|
|
19702
|
+
if (!result.success) {
|
|
19703
|
+
throw new ValidationError2(result.error?.message ?? "Invalid query param", {
|
|
19704
|
+
key,
|
|
19705
|
+
path: null,
|
|
19706
|
+
source: "query",
|
|
19707
|
+
param: key
|
|
19708
|
+
});
|
|
19709
|
+
}
|
|
19710
|
+
}
|
|
19711
|
+
}
|
|
19712
|
+
}
|
|
19713
|
+
}
|
|
19714
|
+
}
|
|
19356
19715
|
const { filters: filters2, sort: sort2, fields: fields2, populate: populate2 } = query;
|
|
19357
19716
|
if (filters2) {
|
|
19358
19717
|
await validateFilters2(filters2, schema2, {
|
|
@@ -28088,7 +28447,14 @@ var preferredPm = async function preferredPM(pkgPath) {
|
|
|
28088
28447
|
};
|
|
28089
28448
|
}
|
|
28090
28449
|
try {
|
|
28091
|
-
|
|
28450
|
+
const workspaceRoot = findYarnWorkspaceRoot(pkgPath);
|
|
28451
|
+
if (typeof workspaceRoot === "string") {
|
|
28452
|
+
if (await pathExists(path.join(workspaceRoot, "package-lock.json"))) {
|
|
28453
|
+
return {
|
|
28454
|
+
name: "npm",
|
|
28455
|
+
version: ">=7"
|
|
28456
|
+
};
|
|
28457
|
+
}
|
|
28092
28458
|
return {
|
|
28093
28459
|
name: "yarn",
|
|
28094
28460
|
version: "*"
|
|
@@ -29814,13 +30180,17 @@ const extendMiddlewareConfiguration = (middlewares2, middleware2) => {
|
|
|
29814
30180
|
};
|
|
29815
30181
|
const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
29816
30182
|
__proto__: null,
|
|
30183
|
+
ALLOWED_QUERY_PARAM_KEYS,
|
|
29817
30184
|
AbstractRouteValidator,
|
|
29818
30185
|
CSP_DEFAULTS,
|
|
30186
|
+
RESERVED_INPUT_PARAM_KEYS,
|
|
30187
|
+
SHARED_QUERY_PARAM_KEYS,
|
|
29819
30188
|
arrays,
|
|
29820
30189
|
async,
|
|
29821
30190
|
augmentSchema,
|
|
29822
30191
|
contentTypes: contentTypes$1,
|
|
29823
30192
|
createContentApiRoutesFactory,
|
|
30193
|
+
createModelCache,
|
|
29824
30194
|
dates,
|
|
29825
30195
|
env,
|
|
29826
30196
|
errors,
|
|
@@ -29866,7 +30236,8 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
|
|
|
29866
30236
|
validateYupSchema,
|
|
29867
30237
|
validateYupSchemaSync,
|
|
29868
30238
|
validateZod,
|
|
29869
|
-
yup
|
|
30239
|
+
yup,
|
|
30240
|
+
z: z$2
|
|
29870
30241
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
29871
30242
|
const require$$0 = /* @__PURE__ */ getAugmentedNamespace(dist);
|
|
29872
30243
|
const { castArray, isNil: isNil$1, pipe, every } = fp;
|
|
@@ -29936,6 +30307,40 @@ var strategies = ({ strapi: strapi2 }) => {
|
|
|
29936
30307
|
},
|
|
29937
30308
|
getRoomName: function(user) {
|
|
29938
30309
|
return `${this.name}-user-${user.id}`;
|
|
30310
|
+
},
|
|
30311
|
+
/**
|
|
30312
|
+
* Admin users have full access - verify always passes
|
|
30313
|
+
* @param {object} auth - Auth object
|
|
30314
|
+
* @param {object} config - Config with scope
|
|
30315
|
+
*/
|
|
30316
|
+
verify: function(auth, config2) {
|
|
30317
|
+
return;
|
|
30318
|
+
},
|
|
30319
|
+
/**
|
|
30320
|
+
* Returns active admin sessions for broadcast
|
|
30321
|
+
* Admin users have full access, so we return them with full_access permissions
|
|
30322
|
+
* @returns {Promise<Array>} Array of admin session objects with permissions
|
|
30323
|
+
*/
|
|
30324
|
+
getRooms: async function() {
|
|
30325
|
+
try {
|
|
30326
|
+
const presenceController = strapi2.plugin("io").controller("presence");
|
|
30327
|
+
if (!presenceController?.getActiveSessions) {
|
|
30328
|
+
return [];
|
|
30329
|
+
}
|
|
30330
|
+
const activeSessions = presenceController.getActiveSessions();
|
|
30331
|
+
return activeSessions.map((session) => ({
|
|
30332
|
+
id: session.userId,
|
|
30333
|
+
name: `admin-${session.userId}`,
|
|
30334
|
+
type: "full-access",
|
|
30335
|
+
// Grants full access to all content types
|
|
30336
|
+
permissions: [],
|
|
30337
|
+
// Empty permissions array - full-access type bypasses permission check
|
|
30338
|
+
...session
|
|
30339
|
+
}));
|
|
30340
|
+
} catch (error2) {
|
|
30341
|
+
strapi2.log.warn("[plugin-io] Admin getRooms error:", error2.message);
|
|
30342
|
+
return [];
|
|
30343
|
+
}
|
|
29939
30344
|
}
|
|
29940
30345
|
};
|
|
29941
30346
|
const role = {
|
|
@@ -30174,12 +30579,12 @@ function transformEntry(entry, type2) {
|
|
|
30174
30579
|
// meta: {},
|
|
30175
30580
|
};
|
|
30176
30581
|
}
|
|
30177
|
-
const { pluginId: pluginId$
|
|
30582
|
+
const { pluginId: pluginId$4 } = pluginId_1;
|
|
30178
30583
|
var settings$1 = ({ strapi: strapi2 }) => {
|
|
30179
30584
|
const getPluginStore = () => {
|
|
30180
30585
|
return strapi2.store({
|
|
30181
30586
|
type: "plugin",
|
|
30182
|
-
name: pluginId$
|
|
30587
|
+
name: pluginId$4
|
|
30183
30588
|
});
|
|
30184
30589
|
};
|
|
30185
30590
|
const getDefaultSettings = () => ({
|
|
@@ -30319,6 +30724,19 @@ var settings$1 = ({ strapi: strapi2 }) => {
|
|
|
30319
30724
|
// Maximum nesting depth for diff
|
|
30320
30725
|
}
|
|
30321
30726
|
});
|
|
30727
|
+
const deepMerge = (target, source) => {
|
|
30728
|
+
const result = { ...target };
|
|
30729
|
+
for (const key of Object.keys(source)) {
|
|
30730
|
+
const targetVal = target[key];
|
|
30731
|
+
const sourceVal = source[key];
|
|
30732
|
+
if (targetVal && sourceVal && typeof targetVal === "object" && !Array.isArray(targetVal) && typeof sourceVal === "object" && !Array.isArray(sourceVal)) {
|
|
30733
|
+
result[key] = deepMerge(targetVal, sourceVal);
|
|
30734
|
+
} else {
|
|
30735
|
+
result[key] = sourceVal;
|
|
30736
|
+
}
|
|
30737
|
+
}
|
|
30738
|
+
return result;
|
|
30739
|
+
};
|
|
30322
30740
|
return {
|
|
30323
30741
|
/**
|
|
30324
30742
|
* Get current settings (merged with defaults)
|
|
@@ -30341,10 +30759,7 @@ var settings$1 = ({ strapi: strapi2 }) => {
|
|
|
30341
30759
|
async setSettings(newSettings) {
|
|
30342
30760
|
const pluginStore = getPluginStore();
|
|
30343
30761
|
const currentSettings = await this.getSettings();
|
|
30344
|
-
const updatedSettings =
|
|
30345
|
-
...currentSettings,
|
|
30346
|
-
...newSettings
|
|
30347
|
-
};
|
|
30762
|
+
const updatedSettings = deepMerge(currentSettings, newSettings);
|
|
30348
30763
|
await pluginStore.set({
|
|
30349
30764
|
key: "settings",
|
|
30350
30765
|
value: updatedSettings
|
|
@@ -30357,7 +30772,7 @@ var settings$1 = ({ strapi: strapi2 }) => {
|
|
|
30357
30772
|
getDefaultSettings
|
|
30358
30773
|
};
|
|
30359
30774
|
};
|
|
30360
|
-
const { pluginId: pluginId$
|
|
30775
|
+
const { pluginId: pluginId$3 } = pluginId_1;
|
|
30361
30776
|
var monitoring$1 = ({ strapi: strapi2 }) => {
|
|
30362
30777
|
let eventLog = [];
|
|
30363
30778
|
let eventStats = {
|
|
@@ -30463,8 +30878,10 @@ var monitoring$1 = ({ strapi: strapi2 }) => {
|
|
|
30463
30878
|
*/
|
|
30464
30879
|
getEventsPerSecond() {
|
|
30465
30880
|
const now = Date.now();
|
|
30466
|
-
const
|
|
30467
|
-
|
|
30881
|
+
const windowMs = 6e4;
|
|
30882
|
+
const recentEvents = eventLog.filter((e) => now - e.timestamp < windowMs);
|
|
30883
|
+
const elapsed = Math.min((now - eventStats.lastReset) / 1e3, windowMs / 1e3);
|
|
30884
|
+
return elapsed > 0 ? Number((recentEvents.length / elapsed).toFixed(2)) : 0;
|
|
30468
30885
|
},
|
|
30469
30886
|
/**
|
|
30470
30887
|
* Reset statistics
|
|
@@ -30485,13 +30902,14 @@ var monitoring$1 = ({ strapi: strapi2 }) => {
|
|
|
30485
30902
|
if (!io2) {
|
|
30486
30903
|
throw new Error("Socket.IO not initialized");
|
|
30487
30904
|
}
|
|
30905
|
+
const safeName = `test:${eventName.replace(/[^a-zA-Z0-9:._-]/g, "")}`;
|
|
30488
30906
|
const testData = {
|
|
30489
30907
|
...data,
|
|
30490
30908
|
timestamp: Date.now(),
|
|
30491
30909
|
test: true
|
|
30492
30910
|
};
|
|
30493
|
-
io2.emit(
|
|
30494
|
-
this.logEvent("test", { eventName, data: testData });
|
|
30911
|
+
io2.emit(safeName, testData);
|
|
30912
|
+
this.logEvent("test", { eventName: safeName, data: testData });
|
|
30495
30913
|
return {
|
|
30496
30914
|
success: true,
|
|
30497
30915
|
eventName,
|
|
@@ -30501,7 +30919,7 @@ var monitoring$1 = ({ strapi: strapi2 }) => {
|
|
|
30501
30919
|
}
|
|
30502
30920
|
};
|
|
30503
30921
|
};
|
|
30504
|
-
const { pluginId: pluginId$
|
|
30922
|
+
const { pluginId: pluginId$2 } = pluginId_1;
|
|
30505
30923
|
var presence$1 = ({ strapi: strapi2 }) => {
|
|
30506
30924
|
const activeConnections = /* @__PURE__ */ new Map();
|
|
30507
30925
|
const entityEditors = /* @__PURE__ */ new Map();
|
|
@@ -30903,7 +31321,7 @@ var presence$1 = ({ strapi: strapi2 }) => {
|
|
|
30903
31321
|
}
|
|
30904
31322
|
};
|
|
30905
31323
|
};
|
|
30906
|
-
const { pluginId } = pluginId_1;
|
|
31324
|
+
const { pluginId: pluginId$1 } = pluginId_1;
|
|
30907
31325
|
var preview$1 = ({ strapi: strapi2 }) => {
|
|
30908
31326
|
const previewSubscribers = /* @__PURE__ */ new Map();
|
|
30909
31327
|
const socketState = /* @__PURE__ */ new Map();
|
|
@@ -31165,22 +31583,23 @@ var diff$1 = ({ strapi: strapi2 }) => {
|
|
|
31165
31583
|
const isPlainObject2 = (value) => {
|
|
31166
31584
|
return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
|
|
31167
31585
|
};
|
|
31168
|
-
const isEqual2 = (a, b) => {
|
|
31586
|
+
const isEqual2 = (a, b, depth2 = 0) => {
|
|
31169
31587
|
if (a === b) return true;
|
|
31170
31588
|
if (a === null || b === null) return a === b;
|
|
31171
31589
|
if (typeof a !== typeof b) return false;
|
|
31590
|
+
if (depth2 > 30) return JSON.stringify(a) === JSON.stringify(b);
|
|
31172
31591
|
if (a instanceof Date && b instanceof Date) {
|
|
31173
31592
|
return a.getTime() === b.getTime();
|
|
31174
31593
|
}
|
|
31175
31594
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
31176
31595
|
if (a.length !== b.length) return false;
|
|
31177
|
-
return a.every((item, index2) => isEqual2(item, b[index2]));
|
|
31596
|
+
return a.every((item, index2) => isEqual2(item, b[index2], depth2 + 1));
|
|
31178
31597
|
}
|
|
31179
31598
|
if (isPlainObject2(a) && isPlainObject2(b)) {
|
|
31180
31599
|
const keysA = Object.keys(a);
|
|
31181
31600
|
const keysB = Object.keys(b);
|
|
31182
31601
|
if (keysA.length !== keysB.length) return false;
|
|
31183
|
-
return keysA.every((key) => isEqual2(a[key], b[key]));
|
|
31602
|
+
return keysA.every((key) => isEqual2(a[key], b[key], depth2 + 1));
|
|
31184
31603
|
}
|
|
31185
31604
|
return false;
|
|
31186
31605
|
};
|
|
@@ -31365,6 +31784,142 @@ var diff$1 = ({ strapi: strapi2 }) => {
|
|
|
31365
31784
|
}
|
|
31366
31785
|
};
|
|
31367
31786
|
};
|
|
31787
|
+
var security = ({ strapi: strapi2 }) => {
|
|
31788
|
+
const rateLimitStore = /* @__PURE__ */ new Map();
|
|
31789
|
+
const connectionLimitStore = /* @__PURE__ */ new Map();
|
|
31790
|
+
const cleanupInterval = setInterval(() => {
|
|
31791
|
+
const now = Date.now();
|
|
31792
|
+
const maxAge = 60 * 1e3;
|
|
31793
|
+
for (const [key, value] of rateLimitStore.entries()) {
|
|
31794
|
+
if (now - value.resetTime > maxAge) {
|
|
31795
|
+
rateLimitStore.delete(key);
|
|
31796
|
+
}
|
|
31797
|
+
}
|
|
31798
|
+
for (const [key, value] of connectionLimitStore.entries()) {
|
|
31799
|
+
if (now - value.lastSeen > maxAge) {
|
|
31800
|
+
connectionLimitStore.delete(key);
|
|
31801
|
+
}
|
|
31802
|
+
}
|
|
31803
|
+
}, 60 * 1e3);
|
|
31804
|
+
return {
|
|
31805
|
+
/**
|
|
31806
|
+
* Stops the background cleanup interval (called on plugin destroy)
|
|
31807
|
+
*/
|
|
31808
|
+
stopCleanupInterval() {
|
|
31809
|
+
clearInterval(cleanupInterval);
|
|
31810
|
+
},
|
|
31811
|
+
/**
|
|
31812
|
+
* Check if request should be rate limited
|
|
31813
|
+
* @param {string} identifier - Unique identifier (IP, user ID, etc.)
|
|
31814
|
+
* @param {Object} options - Rate limit options
|
|
31815
|
+
* @param {number} options.maxRequests - Maximum requests allowed
|
|
31816
|
+
* @param {number} options.windowMs - Time window in milliseconds
|
|
31817
|
+
* @returns {Object} - { allowed: boolean, remaining: number, resetTime: number }
|
|
31818
|
+
*/
|
|
31819
|
+
checkRateLimit(identifier, options = {}) {
|
|
31820
|
+
const { maxRequests = 100, windowMs = 60 * 1e3 } = options;
|
|
31821
|
+
const now = Date.now();
|
|
31822
|
+
const key = `ratelimit_${identifier}`;
|
|
31823
|
+
let record = rateLimitStore.get(key);
|
|
31824
|
+
if (!record || now - record.resetTime > windowMs) {
|
|
31825
|
+
record = {
|
|
31826
|
+
count: 1,
|
|
31827
|
+
resetTime: now,
|
|
31828
|
+
windowMs
|
|
31829
|
+
};
|
|
31830
|
+
rateLimitStore.set(key, record);
|
|
31831
|
+
return {
|
|
31832
|
+
allowed: true,
|
|
31833
|
+
remaining: maxRequests - 1,
|
|
31834
|
+
resetTime: now + windowMs
|
|
31835
|
+
};
|
|
31836
|
+
}
|
|
31837
|
+
if (record.count >= maxRequests) {
|
|
31838
|
+
return {
|
|
31839
|
+
allowed: false,
|
|
31840
|
+
remaining: 0,
|
|
31841
|
+
resetTime: record.resetTime + windowMs,
|
|
31842
|
+
retryAfter: record.resetTime + windowMs - now
|
|
31843
|
+
};
|
|
31844
|
+
}
|
|
31845
|
+
record.count++;
|
|
31846
|
+
rateLimitStore.set(key, record);
|
|
31847
|
+
return {
|
|
31848
|
+
allowed: true,
|
|
31849
|
+
remaining: maxRequests - record.count,
|
|
31850
|
+
resetTime: record.resetTime + windowMs
|
|
31851
|
+
};
|
|
31852
|
+
},
|
|
31853
|
+
/**
|
|
31854
|
+
* Check connection limits per IP/user
|
|
31855
|
+
* @param {string} identifier - Unique identifier
|
|
31856
|
+
* @param {number} maxConnections - Maximum allowed connections
|
|
31857
|
+
* @returns {boolean} - Whether connection is allowed
|
|
31858
|
+
*/
|
|
31859
|
+
checkConnectionLimit(identifier, maxConnections = 5) {
|
|
31860
|
+
const key = `connlimit_${identifier}`;
|
|
31861
|
+
const record = connectionLimitStore.get(key);
|
|
31862
|
+
const now = Date.now();
|
|
31863
|
+
if (!record) {
|
|
31864
|
+
connectionLimitStore.set(key, {
|
|
31865
|
+
count: 1,
|
|
31866
|
+
lastSeen: now
|
|
31867
|
+
});
|
|
31868
|
+
return true;
|
|
31869
|
+
}
|
|
31870
|
+
if (record.count >= maxConnections) {
|
|
31871
|
+
strapi2.log.warn(`[Socket.IO Security] Connection limit exceeded for ${identifier}`);
|
|
31872
|
+
return false;
|
|
31873
|
+
}
|
|
31874
|
+
record.count++;
|
|
31875
|
+
record.lastSeen = now;
|
|
31876
|
+
connectionLimitStore.set(key, record);
|
|
31877
|
+
return true;
|
|
31878
|
+
},
|
|
31879
|
+
/**
|
|
31880
|
+
* Release a connection slot
|
|
31881
|
+
* @param {string} identifier - Unique identifier
|
|
31882
|
+
*/
|
|
31883
|
+
releaseConnection(identifier) {
|
|
31884
|
+
const key = `connlimit_${identifier}`;
|
|
31885
|
+
const record = connectionLimitStore.get(key);
|
|
31886
|
+
if (record) {
|
|
31887
|
+
record.count = Math.max(0, record.count - 1);
|
|
31888
|
+
if (record.count === 0) {
|
|
31889
|
+
connectionLimitStore.delete(key);
|
|
31890
|
+
} else {
|
|
31891
|
+
connectionLimitStore.set(key, record);
|
|
31892
|
+
}
|
|
31893
|
+
}
|
|
31894
|
+
},
|
|
31895
|
+
/**
|
|
31896
|
+
* Validate event name to prevent injection
|
|
31897
|
+
* @param {string} eventName - Event name to validate
|
|
31898
|
+
* @returns {boolean} - Whether event name is valid
|
|
31899
|
+
*/
|
|
31900
|
+
validateEventName(eventName) {
|
|
31901
|
+
const validPattern = /^[a-zA-Z0-9:._-]+$/;
|
|
31902
|
+
return validPattern.test(eventName) && eventName.length < 100;
|
|
31903
|
+
},
|
|
31904
|
+
/**
|
|
31905
|
+
* Get current statistics
|
|
31906
|
+
* @returns {Object} - Statistics object
|
|
31907
|
+
*/
|
|
31908
|
+
getStats() {
|
|
31909
|
+
return {
|
|
31910
|
+
rateLimitEntries: rateLimitStore.size,
|
|
31911
|
+
connectionLimitEntries: connectionLimitStore.size
|
|
31912
|
+
};
|
|
31913
|
+
},
|
|
31914
|
+
/**
|
|
31915
|
+
* Clear all rate limit data
|
|
31916
|
+
*/
|
|
31917
|
+
clear() {
|
|
31918
|
+
rateLimitStore.clear();
|
|
31919
|
+
connectionLimitStore.clear();
|
|
31920
|
+
}
|
|
31921
|
+
};
|
|
31922
|
+
};
|
|
31368
31923
|
const strategy = strategies;
|
|
31369
31924
|
const sanitize = sanitize_1;
|
|
31370
31925
|
const transform = transform$1;
|
|
@@ -31381,20 +31936,58 @@ var services$1 = {
|
|
|
31381
31936
|
monitoring,
|
|
31382
31937
|
presence,
|
|
31383
31938
|
preview,
|
|
31384
|
-
diff
|
|
31939
|
+
diff,
|
|
31940
|
+
security
|
|
31385
31941
|
};
|
|
31386
31942
|
const bootstrap = bootstrap_1;
|
|
31387
31943
|
const config = config$1;
|
|
31388
31944
|
const controllers = controllers$1;
|
|
31389
31945
|
const routes = routes$1;
|
|
31390
31946
|
const services = services$1;
|
|
31391
|
-
const
|
|
31392
|
-
};
|
|
31947
|
+
const { pluginId } = pluginId_1;
|
|
31393
31948
|
const register = async () => {
|
|
31394
31949
|
};
|
|
31395
31950
|
const contentTypes = {};
|
|
31396
31951
|
const middlewares = {};
|
|
31397
31952
|
const policies = {};
|
|
31953
|
+
const destroy = async ({ strapi: strapi2 }) => {
|
|
31954
|
+
try {
|
|
31955
|
+
const presenceService = strapi2.plugin(pluginId)?.service("presence");
|
|
31956
|
+
if (presenceService?.stopCleanupInterval) {
|
|
31957
|
+
presenceService.stopCleanupInterval();
|
|
31958
|
+
}
|
|
31959
|
+
const presenceController = strapi2.plugin(pluginId)?.controller("presence");
|
|
31960
|
+
if (presenceController?.stopTokenCleanup) {
|
|
31961
|
+
presenceController.stopTokenCleanup();
|
|
31962
|
+
}
|
|
31963
|
+
const securityService = strapi2.plugin(pluginId)?.service("security");
|
|
31964
|
+
if (securityService?.stopCleanupInterval) {
|
|
31965
|
+
securityService.stopCleanupInterval();
|
|
31966
|
+
}
|
|
31967
|
+
const io2 = strapi2.$io?.server;
|
|
31968
|
+
if (io2) {
|
|
31969
|
+
io2.disconnectSockets(true);
|
|
31970
|
+
await new Promise((resolve) => {
|
|
31971
|
+
io2.close((err) => {
|
|
31972
|
+
if (err) {
|
|
31973
|
+
strapi2.log.warn(`socket.io: Error closing server: ${err.message}`);
|
|
31974
|
+
}
|
|
31975
|
+
resolve();
|
|
31976
|
+
});
|
|
31977
|
+
});
|
|
31978
|
+
}
|
|
31979
|
+
const redisClients = strapi2.$io?._redisClients;
|
|
31980
|
+
if (redisClients) {
|
|
31981
|
+
await Promise.allSettled([
|
|
31982
|
+
redisClients.pubClient?.quit?.(),
|
|
31983
|
+
redisClients.subClient?.quit?.()
|
|
31984
|
+
]);
|
|
31985
|
+
}
|
|
31986
|
+
strapi2.log.info("socket.io: Plugin destroyed – all handles released");
|
|
31987
|
+
} catch (err) {
|
|
31988
|
+
strapi2.log.error(`socket.io: Error during destroy: ${err.message}`);
|
|
31989
|
+
}
|
|
31990
|
+
};
|
|
31398
31991
|
var server = {
|
|
31399
31992
|
register,
|
|
31400
31993
|
bootstrap,
|