@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.js
CHANGED
|
@@ -83,10 +83,10 @@ const require$$0$3 = {
|
|
|
83
83
|
strapi: strapi$1
|
|
84
84
|
};
|
|
85
85
|
const pluginPkg = require$$0$3;
|
|
86
|
-
const pluginId$
|
|
87
|
-
var pluginId_1 = { pluginId: pluginId$
|
|
88
|
-
const { pluginId: pluginId$
|
|
89
|
-
function getService$3({ name, plugin = pluginId$
|
|
86
|
+
const pluginId$a = pluginPkg.strapi.name;
|
|
87
|
+
var pluginId_1 = { pluginId: pluginId$a };
|
|
88
|
+
const { pluginId: pluginId$9 } = pluginId_1;
|
|
89
|
+
function getService$3({ name, plugin = pluginId$9, type: type2 = "plugin" }) {
|
|
90
90
|
let serviceUID = `${type2}::${plugin}`;
|
|
91
91
|
if (name && name.length) {
|
|
92
92
|
serviceUID += `.${name}`;
|
|
@@ -129,7 +129,7 @@ async function handshake$2(socket, next) {
|
|
|
129
129
|
room = strategyService["role"].getRoomName(role);
|
|
130
130
|
}
|
|
131
131
|
if (room) {
|
|
132
|
-
socket.join(room.
|
|
132
|
+
socket.join(room.replaceAll(" ", "-"));
|
|
133
133
|
} else {
|
|
134
134
|
throw new Error("No valid room found");
|
|
135
135
|
}
|
|
@@ -156,7 +156,7 @@ var constants$7 = {
|
|
|
156
156
|
const { Server } = require$$0__default.default;
|
|
157
157
|
const { handshake } = middleware;
|
|
158
158
|
const { getService: getService$1 } = getService_1;
|
|
159
|
-
const { pluginId: pluginId$
|
|
159
|
+
const { pluginId: pluginId$8 } = pluginId_1;
|
|
160
160
|
const { API_TOKEN_TYPE: API_TOKEN_TYPE$1 } = constants$7;
|
|
161
161
|
let SocketIO$2 = class SocketIO {
|
|
162
162
|
constructor(options) {
|
|
@@ -198,7 +198,7 @@ let SocketIO$2 = class SocketIO {
|
|
|
198
198
|
});
|
|
199
199
|
const roomName = strategy2.getRoomName(room);
|
|
200
200
|
const data = transformService.response({ data: sanitizedData, schema: schema2 });
|
|
201
|
-
this._socket.to(roomName.
|
|
201
|
+
this._socket.to(roomName.replaceAll(" ", "-")).emit(eventName, { ...data });
|
|
202
202
|
if (entityRoomName) {
|
|
203
203
|
this._socket.to(entityRoomName).emit(eventName, { ...data });
|
|
204
204
|
}
|
|
@@ -234,21 +234,25 @@ function requireSanitizeSensitiveFields() {
|
|
|
234
234
|
hasRequiredSanitizeSensitiveFields = 1;
|
|
235
235
|
const SENSITIVE_FIELDS = [
|
|
236
236
|
"password",
|
|
237
|
+
"passwordHash",
|
|
237
238
|
"resetPasswordToken",
|
|
238
239
|
"registrationToken",
|
|
239
240
|
"confirmationToken",
|
|
240
241
|
"privateKey",
|
|
241
242
|
"secretKey",
|
|
242
243
|
"apiKey",
|
|
243
|
-
"secret"
|
|
244
|
-
"hash"
|
|
244
|
+
"secret"
|
|
245
245
|
];
|
|
246
|
-
|
|
246
|
+
const MAX_SANITIZE_DEPTH = 20;
|
|
247
|
+
function deepSanitize(obj, depth2 = 0) {
|
|
247
248
|
if (!obj || typeof obj !== "object") {
|
|
248
249
|
return obj;
|
|
249
250
|
}
|
|
251
|
+
if (depth2 >= MAX_SANITIZE_DEPTH) {
|
|
252
|
+
return obj;
|
|
253
|
+
}
|
|
250
254
|
if (Array.isArray(obj)) {
|
|
251
|
-
return obj.map((item) => deepSanitize(item));
|
|
255
|
+
return obj.map((item) => deepSanitize(item, depth2 + 1));
|
|
252
256
|
}
|
|
253
257
|
const sanitized = {};
|
|
254
258
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -256,7 +260,7 @@ function requireSanitizeSensitiveFields() {
|
|
|
256
260
|
continue;
|
|
257
261
|
}
|
|
258
262
|
if (value && typeof value === "object") {
|
|
259
|
-
sanitized[key] = deepSanitize(value);
|
|
263
|
+
sanitized[key] = deepSanitize(value, depth2 + 1);
|
|
260
264
|
} else {
|
|
261
265
|
sanitized[key] = value;
|
|
262
266
|
}
|
|
@@ -276,11 +280,57 @@ function requireSanitizeSensitiveFields() {
|
|
|
276
280
|
return sanitizeSensitiveFields;
|
|
277
281
|
}
|
|
278
282
|
const { SocketIO: SocketIO2 } = structures;
|
|
279
|
-
const { pluginId: pluginId$
|
|
283
|
+
const { pluginId: pluginId$7 } = pluginId_1;
|
|
284
|
+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
285
|
+
const MAX_FIELD_VALUE_SIZE = 1e5;
|
|
286
|
+
function safeHandler(handler, expectsObject = true) {
|
|
287
|
+
return function(...args) {
|
|
288
|
+
try {
|
|
289
|
+
if (expectsObject) {
|
|
290
|
+
const data = args[0];
|
|
291
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
292
|
+
const callback = typeof args[args.length - 1] === "function" ? args[args.length - 1] : null;
|
|
293
|
+
if (callback) callback({ success: false, error: "Invalid payload" });
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const result = handler.apply(this, args);
|
|
298
|
+
if (result && typeof result.catch === "function") {
|
|
299
|
+
result.catch((err) => {
|
|
300
|
+
strapi.log.error(`socket.io: Unhandled error in event handler: ${err.message}`);
|
|
301
|
+
const callback = typeof args[args.length - 1] === "function" ? args[args.length - 1] : null;
|
|
302
|
+
if (callback) callback({ success: false, error: "Internal error" });
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
} catch (err) {
|
|
306
|
+
strapi.log.error(`socket.io: Error in event handler: ${err.message}`);
|
|
307
|
+
const callback = typeof args[args.length - 1] === "function" ? args[args.length - 1] : null;
|
|
308
|
+
if (callback) callback({ success: false, error: "Internal error" });
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function resolveClientIp(socket) {
|
|
313
|
+
const xff = socket.handshake.headers?.["x-forwarded-for"];
|
|
314
|
+
if (xff) {
|
|
315
|
+
return xff.split(",")[0].trim();
|
|
316
|
+
}
|
|
317
|
+
return socket.handshake.address;
|
|
318
|
+
}
|
|
319
|
+
function redactUrl(url) {
|
|
320
|
+
try {
|
|
321
|
+
const parsed = new URL(url);
|
|
322
|
+
if (parsed.password) {
|
|
323
|
+
parsed.password = "***";
|
|
324
|
+
}
|
|
325
|
+
return parsed.toString();
|
|
326
|
+
} catch {
|
|
327
|
+
return url.replace(/:([^@/]+)@/, ":***@");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
280
330
|
async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
281
|
-
const settingsService = strapi2.plugin(pluginId$
|
|
331
|
+
const settingsService = strapi2.plugin(pluginId$7).service("settings");
|
|
282
332
|
const settings2 = await settingsService.getSettings();
|
|
283
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
333
|
+
const monitoringService = strapi2.plugin(pluginId$7).service("monitoring");
|
|
284
334
|
const serverOptions = {
|
|
285
335
|
cors: {
|
|
286
336
|
origin: settings2.cors?.origins || ["http://localhost:3000"],
|
|
@@ -292,7 +342,7 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
292
342
|
connectTimeout: settings2.connection?.connectionTimeout || 45e3,
|
|
293
343
|
maxHttpBufferSize: 1e6,
|
|
294
344
|
transports: ["websocket", "polling"],
|
|
295
|
-
allowEIO3:
|
|
345
|
+
allowEIO3: settings2.connection?.allowEIO3 ?? false
|
|
296
346
|
};
|
|
297
347
|
if (settings2.redis?.enabled) {
|
|
298
348
|
try {
|
|
@@ -304,13 +354,15 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
304
354
|
const subClient = pubClient.duplicate();
|
|
305
355
|
await Promise.all([pubClient.connect(), subClient.connect()]);
|
|
306
356
|
serverOptions.adapter = createAdapter(pubClient, subClient);
|
|
307
|
-
|
|
357
|
+
serverOptions._redisClients = { pubClient, subClient };
|
|
358
|
+
strapi2.log.info(`socket.io: Redis adapter enabled (${redactUrl(settings2.redis.url)})`);
|
|
308
359
|
} catch (err) {
|
|
309
360
|
strapi2.log.error(`socket.io: Redis adapter failed: ${err.message}`);
|
|
310
361
|
}
|
|
311
362
|
}
|
|
312
363
|
const io2 = new SocketIO2(serverOptions);
|
|
313
364
|
strapi2.$io = io2;
|
|
365
|
+
strapi2.$io._redisClients = serverOptions._redisClients || null;
|
|
314
366
|
strapi2.$ioSettings = settings2;
|
|
315
367
|
const sanitizeSensitiveFields2 = requireSanitizeSensitiveFields();
|
|
316
368
|
sanitizeSensitiveFields2({ strapi: strapi2 });
|
|
@@ -336,7 +388,7 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
336
388
|
}
|
|
337
389
|
strapi2.$io.namespaces = namespaces;
|
|
338
390
|
io2.server.use(async (socket, next) => {
|
|
339
|
-
const clientIp = socket
|
|
391
|
+
const clientIp = resolveClientIp(socket);
|
|
340
392
|
if (settings2.security?.ipWhitelist?.length > 0) {
|
|
341
393
|
if (!settings2.security.ipWhitelist.includes(clientIp)) {
|
|
342
394
|
return next(new Error("IP not whitelisted"));
|
|
@@ -349,30 +401,22 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
349
401
|
if (currentConnections >= (settings2.connection?.maxConnections || 1e3)) {
|
|
350
402
|
return next(new Error("Max connections reached"));
|
|
351
403
|
}
|
|
352
|
-
const token = socket.handshake.auth?.token
|
|
353
|
-
const strategy2 = socket.handshake.auth?.strategy;
|
|
354
|
-
const isAdmin = socket.handshake.auth?.isAdmin === true;
|
|
404
|
+
const token = socket.handshake.auth?.token;
|
|
355
405
|
if (token) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
strapi2.log.info(`socket.io: Admin authenticated - ${socket.user.username} (ID: ${session.userId})`);
|
|
371
|
-
} else {
|
|
372
|
-
strapi2.log.warn(`socket.io: Admin session token invalid or expired`);
|
|
373
|
-
}
|
|
374
|
-
} catch (err) {
|
|
375
|
-
strapi2.log.warn(`socket.io: Admin session verification failed: ${err.message}`);
|
|
406
|
+
const isAdminToken = UUID_REGEX.test(token);
|
|
407
|
+
if (isAdminToken) {
|
|
408
|
+
if (socket.adminUser) {
|
|
409
|
+
const admin2 = socket.adminUser;
|
|
410
|
+
socket.user = {
|
|
411
|
+
id: admin2.id,
|
|
412
|
+
username: `${admin2.firstname || ""} ${admin2.lastname || ""}`.trim() || `Admin ${admin2.id}`,
|
|
413
|
+
email: admin2.email || `admin-${admin2.id}`,
|
|
414
|
+
role: "strapi-super-admin",
|
|
415
|
+
isAdmin: true
|
|
416
|
+
};
|
|
417
|
+
strapi2.log.info(`socket.io: Admin connected - ${socket.user.username} (ID: ${admin2.id})`);
|
|
418
|
+
} else {
|
|
419
|
+
strapi2.log.warn("socket.io: Admin token present but handshake did not authenticate");
|
|
376
420
|
}
|
|
377
421
|
} else {
|
|
378
422
|
try {
|
|
@@ -438,13 +482,13 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
438
482
|
}
|
|
439
483
|
});
|
|
440
484
|
}
|
|
441
|
-
const presenceService = strapi2.plugin(pluginId$
|
|
442
|
-
const previewService = strapi2.plugin(pluginId$
|
|
485
|
+
const presenceService = strapi2.plugin(pluginId$7).service("presence");
|
|
486
|
+
const previewService = strapi2.plugin(pluginId$7).service("preview");
|
|
443
487
|
if (settings2.presence?.enabled !== false) {
|
|
444
488
|
presenceService.startCleanupInterval();
|
|
445
489
|
}
|
|
446
490
|
io2.server.on("connection", (socket) => {
|
|
447
|
-
const clientIp = socket
|
|
491
|
+
const clientIp = resolveClientIp(socket);
|
|
448
492
|
const username = socket.user?.username || "anonymous";
|
|
449
493
|
if (settings2.monitoring?.enableConnectionLogging) {
|
|
450
494
|
strapi2.log.info(`socket.io: Client connected (id: ${socket.id}, user: ${username}, ip: ${clientIp})`);
|
|
@@ -490,19 +534,24 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
490
534
|
if (callback) callback({ success: true, room: roomName });
|
|
491
535
|
});
|
|
492
536
|
socket.on("leave-room", (roomName, callback) => {
|
|
493
|
-
if (typeof roomName
|
|
494
|
-
socket.leave(roomName);
|
|
495
|
-
strapi2.log.debug(`socket.io: Socket ${socket.id} left room: ${roomName}`);
|
|
496
|
-
if (callback) callback({ success: true, room: roomName });
|
|
497
|
-
} else {
|
|
537
|
+
if (typeof roomName !== "string" || roomName.length === 0) {
|
|
498
538
|
if (callback) callback({ success: false, error: "Invalid room name" });
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
const sanitizedRoom = roomName.replace(/[^a-zA-Z0-9\-_:]/g, "");
|
|
542
|
+
if (sanitizedRoom !== roomName) {
|
|
543
|
+
if (callback) callback({ success: false, error: "Room name contains invalid characters" });
|
|
544
|
+
return;
|
|
499
545
|
}
|
|
546
|
+
socket.leave(roomName);
|
|
547
|
+
strapi2.log.debug(`socket.io: Socket ${socket.id} left room: ${roomName}`);
|
|
548
|
+
if (callback) callback({ success: true, room: roomName });
|
|
500
549
|
});
|
|
501
550
|
socket.on("get-rooms", (callback) => {
|
|
502
551
|
const rooms = Array.from(socket.rooms).filter((r) => r !== socket.id);
|
|
503
552
|
if (callback) callback({ success: true, rooms });
|
|
504
553
|
});
|
|
505
|
-
socket.on("presence:join", async ({ uid, documentId }, callback) => {
|
|
554
|
+
socket.on("presence:join", safeHandler(async ({ uid, documentId }, callback) => {
|
|
506
555
|
if (settings2.presence?.enabled === false) {
|
|
507
556
|
if (callback) callback({ success: false, error: "Presence is disabled" });
|
|
508
557
|
return;
|
|
@@ -513,8 +562,8 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
513
562
|
}
|
|
514
563
|
const result = await presenceService.joinEntity(socket.id, uid, documentId);
|
|
515
564
|
if (callback) callback(result);
|
|
516
|
-
});
|
|
517
|
-
socket.on("presence:leave", async ({ uid, documentId }, callback) => {
|
|
565
|
+
}));
|
|
566
|
+
socket.on("presence:leave", safeHandler(async ({ uid, documentId }, callback) => {
|
|
518
567
|
if (settings2.presence?.enabled === false) {
|
|
519
568
|
if (callback) callback({ success: false, error: "Presence is disabled" });
|
|
520
569
|
return;
|
|
@@ -525,24 +574,26 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
525
574
|
}
|
|
526
575
|
const result = await presenceService.leaveEntity(socket.id, uid, documentId);
|
|
527
576
|
if (callback) callback(result);
|
|
528
|
-
});
|
|
577
|
+
}));
|
|
529
578
|
socket.on("presence:heartbeat", (callback) => {
|
|
530
579
|
const result = presenceService.heartbeat(socket.id);
|
|
531
580
|
if (callback) callback(result);
|
|
532
581
|
});
|
|
533
|
-
socket.on("presence:typing", ({ uid, documentId, fieldName }) => {
|
|
582
|
+
socket.on("presence:typing", safeHandler(({ uid, documentId, fieldName }) => {
|
|
534
583
|
if (settings2.presence?.enabled === false) return;
|
|
584
|
+
if (!socket.user) return;
|
|
585
|
+
if (typeof fieldName !== "string" || fieldName.length > 200) return;
|
|
535
586
|
presenceService.broadcastTyping(socket.id, uid, documentId, fieldName);
|
|
536
|
-
});
|
|
537
|
-
socket.on("presence:check", async ({ uid, documentId }, callback) => {
|
|
587
|
+
}));
|
|
588
|
+
socket.on("presence:check", safeHandler(async ({ uid, documentId }, callback) => {
|
|
538
589
|
if (settings2.presence?.enabled === false) {
|
|
539
590
|
if (callback) callback({ success: false, error: "Presence is disabled" });
|
|
540
591
|
return;
|
|
541
592
|
}
|
|
542
593
|
const editors = await presenceService.getEntityEditors(uid, documentId);
|
|
543
594
|
if (callback) callback({ success: true, editors, isBeingEdited: editors.length > 0 });
|
|
544
|
-
});
|
|
545
|
-
socket.on("preview:subscribe", async ({ uid, documentId }, callback) => {
|
|
595
|
+
}));
|
|
596
|
+
socket.on("preview:subscribe", safeHandler(async ({ uid, documentId }, callback) => {
|
|
546
597
|
if (settings2.livePreview?.enabled === false) {
|
|
547
598
|
if (callback) callback({ success: false, error: "Live preview is disabled" });
|
|
548
599
|
return;
|
|
@@ -551,22 +602,33 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
551
602
|
if (callback) callback({ success: false, error: "uid and documentId are required" });
|
|
552
603
|
return;
|
|
553
604
|
}
|
|
605
|
+
const userRole = socket.userRole || "public";
|
|
606
|
+
const rolePerms = (settings2.rolePermissions || {})[userRole] || {};
|
|
607
|
+
const ctPerms = rolePerms.contentTypes?.[uid];
|
|
608
|
+
if (!ctPerms && settings2.security?.requireAuthentication) {
|
|
609
|
+
if (callback) callback({ success: false, error: "Permission denied" });
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
554
612
|
const result = await previewService.subscribe(socket.id, uid, documentId);
|
|
555
613
|
if (callback) callback(result);
|
|
556
|
-
});
|
|
557
|
-
socket.on("preview:unsubscribe", ({ uid, documentId }, callback) => {
|
|
614
|
+
}));
|
|
615
|
+
socket.on("preview:unsubscribe", safeHandler(({ uid, documentId }, callback) => {
|
|
558
616
|
if (!uid || !documentId) {
|
|
559
617
|
if (callback) callback({ success: false, error: "uid and documentId are required" });
|
|
560
618
|
return;
|
|
561
619
|
}
|
|
562
620
|
const result = previewService.unsubscribe(socket.id, uid, documentId);
|
|
563
621
|
if (callback) callback(result);
|
|
564
|
-
});
|
|
565
|
-
socket.on("preview:field-change", ({ uid, documentId, fieldName, value }) => {
|
|
622
|
+
}));
|
|
623
|
+
socket.on("preview:field-change", safeHandler(({ uid, documentId, fieldName, value }) => {
|
|
566
624
|
if (settings2.livePreview?.enabled === false) return;
|
|
625
|
+
if (!socket.user) return;
|
|
626
|
+
if (typeof fieldName !== "string" || fieldName.length > 200) return;
|
|
627
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
628
|
+
if (serialized && serialized.length > MAX_FIELD_VALUE_SIZE) return;
|
|
567
629
|
previewService.emitFieldChange(socket.id, uid, documentId, fieldName, value);
|
|
568
|
-
});
|
|
569
|
-
socket.on("subscribe-entity", async ({ uid, id }, callback) => {
|
|
630
|
+
}));
|
|
631
|
+
socket.on("subscribe-entity", safeHandler(async ({ uid, id }, callback) => {
|
|
570
632
|
if (settings2.entitySubscriptions?.enabled === false) {
|
|
571
633
|
if (callback) callback({ success: false, error: "Entity subscriptions are disabled" });
|
|
572
634
|
return;
|
|
@@ -641,8 +703,8 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
641
703
|
}
|
|
642
704
|
strapi2.log.debug(`socket.io: Socket ${socket.id} subscribed to entity: ${entityRoomName}`);
|
|
643
705
|
if (callback) callback({ success: true, room: entityRoomName, uid, id });
|
|
644
|
-
});
|
|
645
|
-
socket.on("unsubscribe-entity", ({ uid, id }, callback) => {
|
|
706
|
+
}));
|
|
707
|
+
socket.on("unsubscribe-entity", safeHandler(({ uid, id }, callback) => {
|
|
646
708
|
if (settings2.entitySubscriptions?.enabled === false) {
|
|
647
709
|
if (callback) callback({ success: false, error: "Entity subscriptions are disabled" });
|
|
648
710
|
return;
|
|
@@ -663,9 +725,9 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
663
725
|
}
|
|
664
726
|
strapi2.log.debug(`socket.io: Socket ${socket.id} unsubscribed from entity: ${entityRoomName}`);
|
|
665
727
|
if (callback) callback({ success: true, room: entityRoomName, uid, id });
|
|
666
|
-
});
|
|
728
|
+
}));
|
|
667
729
|
socket.on("get-entity-subscriptions", (callback) => {
|
|
668
|
-
const rooms = Array.from(socket.rooms).filter((r) => r !== socket.id && r.
|
|
730
|
+
const rooms = Array.from(socket.rooms).filter((r) => r !== socket.id && /^(api|plugin)::/.test(r) && !r.startsWith("presence:") && !r.startsWith("preview:")).map((room) => {
|
|
669
731
|
const lastColonIndex = room.lastIndexOf(":");
|
|
670
732
|
const uid = room.substring(0, lastColonIndex);
|
|
671
733
|
const id = room.substring(lastColonIndex + 1);
|
|
@@ -673,7 +735,7 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
673
735
|
});
|
|
674
736
|
if (callback) callback({ success: true, subscriptions: rooms });
|
|
675
737
|
});
|
|
676
|
-
socket.on("private-message", ({ to, message }, callback) => {
|
|
738
|
+
socket.on("private-message", safeHandler(({ to, message }, callback) => {
|
|
677
739
|
if (settings2.rooms?.enablePrivateRooms === false) {
|
|
678
740
|
strapi2.log.warn(`socket.io: Private messages disabled for socket ${socket.id}`);
|
|
679
741
|
if (callback) callback({ success: false, error: "Private messages are disabled" });
|
|
@@ -701,7 +763,7 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
701
763
|
});
|
|
702
764
|
strapi2.log.debug(`socket.io: Private message from ${socket.id} to ${to}`);
|
|
703
765
|
if (callback) callback({ success: true });
|
|
704
|
-
});
|
|
766
|
+
}));
|
|
705
767
|
socket.on("disconnect", async (reason) => {
|
|
706
768
|
if (settings2.monitoring?.enableConnectionLogging) {
|
|
707
769
|
strapi2.log.info(`socket.io: Client disconnected (id: ${socket.id}, user: ${username}, reason: ${reason})`);
|
|
@@ -718,7 +780,7 @@ async function bootstrapIO$1({ strapi: strapi2 }) {
|
|
|
718
780
|
previewService.cleanupSocket(socket.id);
|
|
719
781
|
}
|
|
720
782
|
try {
|
|
721
|
-
const presenceController = strapi2.plugin(pluginId$
|
|
783
|
+
const presenceController = strapi2.plugin(pluginId$7).controller("presence");
|
|
722
784
|
if (presenceController?.unregisterSocket) {
|
|
723
785
|
presenceController.unregisterSocket(socket.id);
|
|
724
786
|
}
|
|
@@ -986,7 +1048,7 @@ function getTransactionCtx() {
|
|
|
986
1048
|
}
|
|
987
1049
|
return transactionCtx;
|
|
988
1050
|
}
|
|
989
|
-
const { pluginId: pluginId$
|
|
1051
|
+
const { pluginId: pluginId$6 } = pluginId_1;
|
|
990
1052
|
function scheduleAfterTransaction(callback, delay = 0) {
|
|
991
1053
|
const runner = () => setTimeout(callback, delay);
|
|
992
1054
|
const ctx = getTransactionCtx();
|
|
@@ -1096,8 +1158,8 @@ async function bootstrapLifecycles$1({ strapi: strapi2 }) {
|
|
|
1096
1158
|
const modelInfo = { singularName: event.model.singularName, uid: event.model.uid };
|
|
1097
1159
|
scheduleAfterTransaction(() => {
|
|
1098
1160
|
try {
|
|
1099
|
-
const diffService = strapi2.plugin(pluginId$
|
|
1100
|
-
const previewService = strapi2.plugin(pluginId$
|
|
1161
|
+
const diffService = strapi2.plugin(pluginId$6).service("diff");
|
|
1162
|
+
const previewService = strapi2.plugin(pluginId$6).service("preview");
|
|
1101
1163
|
const fieldLevelEnabled = strapi2.$ioSettings?.fieldLevelChanges?.enabled !== false;
|
|
1102
1164
|
let eventPayload;
|
|
1103
1165
|
if (fieldLevelEnabled && previousData && diffService) {
|
|
@@ -1214,14 +1276,14 @@ var config$1 = {
|
|
|
1214
1276
|
validator(config2) {
|
|
1215
1277
|
}
|
|
1216
1278
|
};
|
|
1217
|
-
const { pluginId: pluginId$
|
|
1279
|
+
const { pluginId: pluginId$5 } = pluginId_1;
|
|
1218
1280
|
var settings$3 = ({ strapi: strapi2 }) => ({
|
|
1219
1281
|
/**
|
|
1220
1282
|
* GET /io/settings
|
|
1221
1283
|
* Retrieve current plugin settings
|
|
1222
1284
|
*/
|
|
1223
1285
|
async getSettings(ctx) {
|
|
1224
|
-
const settingsService = strapi2.plugin(pluginId$
|
|
1286
|
+
const settingsService = strapi2.plugin(pluginId$5).service("settings");
|
|
1225
1287
|
const settings2 = await settingsService.getSettings();
|
|
1226
1288
|
ctx.body = { data: settings2 };
|
|
1227
1289
|
},
|
|
@@ -1230,8 +1292,33 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1230
1292
|
* Update plugin settings and hot-reload Socket.IO
|
|
1231
1293
|
*/
|
|
1232
1294
|
async updateSettings(ctx) {
|
|
1233
|
-
const settingsService = strapi2.plugin(pluginId$
|
|
1295
|
+
const settingsService = strapi2.plugin(pluginId$5).service("settings");
|
|
1234
1296
|
const { body } = ctx.request;
|
|
1297
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
1298
|
+
return ctx.badRequest("Request body must be a JSON object");
|
|
1299
|
+
}
|
|
1300
|
+
const ALLOWED_KEYS = [
|
|
1301
|
+
"enabled",
|
|
1302
|
+
"cors",
|
|
1303
|
+
"connection",
|
|
1304
|
+
"security",
|
|
1305
|
+
"contentTypes",
|
|
1306
|
+
"events",
|
|
1307
|
+
"rooms",
|
|
1308
|
+
"entitySubscriptions",
|
|
1309
|
+
"rolePermissions",
|
|
1310
|
+
"redis",
|
|
1311
|
+
"namespaces",
|
|
1312
|
+
"middleware",
|
|
1313
|
+
"monitoring",
|
|
1314
|
+
"presence",
|
|
1315
|
+
"livePreview",
|
|
1316
|
+
"fieldLevelChanges"
|
|
1317
|
+
];
|
|
1318
|
+
const unknownKeys = Object.keys(body).filter((k) => !ALLOWED_KEYS.includes(k));
|
|
1319
|
+
if (unknownKeys.length > 0) {
|
|
1320
|
+
return ctx.badRequest(`Unknown settings keys: ${unknownKeys.join(", ")}`);
|
|
1321
|
+
}
|
|
1235
1322
|
await settingsService.getSettings();
|
|
1236
1323
|
const updatedSettings = await settingsService.setSettings(body);
|
|
1237
1324
|
strapi2.$ioSettings = updatedSettings;
|
|
@@ -1263,7 +1350,7 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1263
1350
|
* Get connection and event statistics
|
|
1264
1351
|
*/
|
|
1265
1352
|
async getStats(ctx) {
|
|
1266
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
1353
|
+
const monitoringService = strapi2.plugin(pluginId$5).service("monitoring");
|
|
1267
1354
|
const connectionStats = monitoringService.getConnectionStats();
|
|
1268
1355
|
const eventStats = monitoringService.getEventStats();
|
|
1269
1356
|
ctx.body = {
|
|
@@ -1278,7 +1365,7 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1278
1365
|
* Get recent event log
|
|
1279
1366
|
*/
|
|
1280
1367
|
async getEventLog(ctx) {
|
|
1281
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
1368
|
+
const monitoringService = strapi2.plugin(pluginId$5).service("monitoring");
|
|
1282
1369
|
const limit = parseInt(ctx.query.limit) || 50;
|
|
1283
1370
|
const log = monitoringService.getEventLog(limit);
|
|
1284
1371
|
ctx.body = { data: log };
|
|
@@ -1288,10 +1375,11 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1288
1375
|
* Send a test event
|
|
1289
1376
|
*/
|
|
1290
1377
|
async sendTestEvent(ctx) {
|
|
1291
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
1378
|
+
const monitoringService = strapi2.plugin(pluginId$5).service("monitoring");
|
|
1292
1379
|
const { eventName, data } = ctx.request.body;
|
|
1293
1380
|
try {
|
|
1294
|
-
const
|
|
1381
|
+
const safeName = (eventName || "test").replace(/[^a-zA-Z0-9:._-]/g, "").substring(0, 50);
|
|
1382
|
+
const result = monitoringService.sendTestEvent(safeName, data || {});
|
|
1295
1383
|
ctx.body = { data: result };
|
|
1296
1384
|
} catch (error2) {
|
|
1297
1385
|
ctx.throw(500, error2.message);
|
|
@@ -1302,7 +1390,7 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1302
1390
|
* Reset monitoring statistics
|
|
1303
1391
|
*/
|
|
1304
1392
|
async resetStats(ctx) {
|
|
1305
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
1393
|
+
const monitoringService = strapi2.plugin(pluginId$5).service("monitoring");
|
|
1306
1394
|
monitoringService.resetStats();
|
|
1307
1395
|
ctx.body = { data: { success: true } };
|
|
1308
1396
|
},
|
|
@@ -1326,7 +1414,7 @@ var settings$3 = ({ strapi: strapi2 }) => ({
|
|
|
1326
1414
|
* Get lightweight stats for dashboard widget
|
|
1327
1415
|
*/
|
|
1328
1416
|
async getMonitoringStats(ctx) {
|
|
1329
|
-
const monitoringService = strapi2.plugin(pluginId$
|
|
1417
|
+
const monitoringService = strapi2.plugin(pluginId$5).service("monitoring");
|
|
1330
1418
|
const connectionStats = monitoringService.getConnectionStats();
|
|
1331
1419
|
const eventStats = monitoringService.getEventStats();
|
|
1332
1420
|
ctx.body = {
|
|
@@ -1352,10 +1440,11 @@ const refreshThrottle = /* @__PURE__ */ new Map();
|
|
|
1352
1440
|
const SESSION_TTL = 10 * 60 * 1e3;
|
|
1353
1441
|
const REFRESH_COOLDOWN = 3 * 1e3;
|
|
1354
1442
|
const CLEANUP_INTERVAL = 2 * 60 * 1e3;
|
|
1443
|
+
let tokenCleanupInterval = null;
|
|
1355
1444
|
const hashToken = (token) => {
|
|
1356
1445
|
return createHash("sha256").update(token).digest("hex");
|
|
1357
1446
|
};
|
|
1358
|
-
|
|
1447
|
+
const runTokenCleanup = () => {
|
|
1359
1448
|
const now = Date.now();
|
|
1360
1449
|
let cleaned = 0;
|
|
1361
1450
|
for (const [tokenHash, session] of sessionTokens.entries()) {
|
|
@@ -1372,8 +1461,23 @@ setInterval(() => {
|
|
|
1372
1461
|
if (cleaned > 0) {
|
|
1373
1462
|
console.log(`[plugin-io] [CLEANUP] Removed ${cleaned} expired session tokens`);
|
|
1374
1463
|
}
|
|
1375
|
-
}
|
|
1464
|
+
};
|
|
1465
|
+
const startTokenCleanup = () => {
|
|
1466
|
+
if (!tokenCleanupInterval) {
|
|
1467
|
+
tokenCleanupInterval = setInterval(runTokenCleanup, CLEANUP_INTERVAL);
|
|
1468
|
+
}
|
|
1469
|
+
};
|
|
1470
|
+
const stopTokenCleanup = () => {
|
|
1471
|
+
if (tokenCleanupInterval) {
|
|
1472
|
+
clearInterval(tokenCleanupInterval);
|
|
1473
|
+
tokenCleanupInterval = null;
|
|
1474
|
+
}
|
|
1475
|
+
};
|
|
1376
1476
|
var presence$3 = ({ strapi: strapi2 }) => ({
|
|
1477
|
+
/**
|
|
1478
|
+
* Stops the background token cleanup interval (called on plugin destroy)
|
|
1479
|
+
*/
|
|
1480
|
+
stopTokenCleanup,
|
|
1377
1481
|
/**
|
|
1378
1482
|
* Creates a session token for admin users to connect to Socket.IO
|
|
1379
1483
|
* Implements rate limiting and secure token storage
|
|
@@ -1392,6 +1496,7 @@ var presence$3 = ({ strapi: strapi2 }) => ({
|
|
|
1392
1496
|
strapi2.log.warn(`[plugin-io] Rate limit: User ${adminUser.id} must wait ${waitTime}s`);
|
|
1393
1497
|
return ctx.tooManyRequests(`Please wait ${waitTime} seconds before requesting a new session`);
|
|
1394
1498
|
}
|
|
1499
|
+
startTokenCleanup();
|
|
1395
1500
|
try {
|
|
1396
1501
|
const token = randomUUID();
|
|
1397
1502
|
const tokenHash = hashToken(token);
|
|
@@ -1492,6 +1597,26 @@ var presence$3 = ({ strapi: strapi2 }) => ({
|
|
|
1492
1597
|
strapi2.log.info(`[plugin-io] Invalidated ${invalidated} sessions for user ${userId}`);
|
|
1493
1598
|
return invalidated;
|
|
1494
1599
|
},
|
|
1600
|
+
/**
|
|
1601
|
+
* Returns all active (non-expired) admin sessions
|
|
1602
|
+
* Used by admin strategy for broadcasting to connected admin users
|
|
1603
|
+
* @returns {Array} Array of active session objects
|
|
1604
|
+
*/
|
|
1605
|
+
getActiveSessions() {
|
|
1606
|
+
const now = Date.now();
|
|
1607
|
+
const activeSessions = [];
|
|
1608
|
+
for (const session of sessionTokens.values()) {
|
|
1609
|
+
if (session.expiresAt > now) {
|
|
1610
|
+
activeSessions.push({
|
|
1611
|
+
userId: session.userId,
|
|
1612
|
+
user: session.user,
|
|
1613
|
+
createdAt: session.createdAt,
|
|
1614
|
+
expiresAt: session.expiresAt
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
return activeSessions;
|
|
1619
|
+
},
|
|
1495
1620
|
/**
|
|
1496
1621
|
* Gets session statistics (for monitoring) - internal method
|
|
1497
1622
|
* @returns {object} Session statistics
|
|
@@ -1963,7 +2088,7 @@ lodash_min.exports;
|
|
|
1963
2088
|
function Q(n2) {
|
|
1964
2089
|
return n2.match(Fr) || [];
|
|
1965
2090
|
}
|
|
1966
|
-
var X, nn = "4.17.
|
|
2091
|
+
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 = {};
|
|
1967
2092
|
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;
|
|
1968
2093
|
var Vr = {};
|
|
1969
2094
|
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;
|
|
@@ -2816,7 +2941,21 @@ lodash_min.exports;
|
|
|
2816
2941
|
return a2;
|
|
2817
2942
|
}
|
|
2818
2943
|
function yu(n2, t2) {
|
|
2819
|
-
|
|
2944
|
+
t2 = ku(t2, n2);
|
|
2945
|
+
var r2 = -1, e2 = t2.length;
|
|
2946
|
+
if (!e2) return true;
|
|
2947
|
+
for (var u2 = null == n2 || "object" != typeof n2 && "function" != typeof n2; ++r2 < e2; ) {
|
|
2948
|
+
var i2 = t2[r2];
|
|
2949
|
+
if ("string" == typeof i2) {
|
|
2950
|
+
if ("__proto__" === i2 && !bl.call(n2, "__proto__")) return false;
|
|
2951
|
+
if ("constructor" === i2 && r2 + 1 < e2 && "string" == typeof t2[r2 + 1] && "prototype" === t2[r2 + 1]) {
|
|
2952
|
+
if (u2 && 0 === r2) continue;
|
|
2953
|
+
return false;
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
var o2 = Gi(n2, t2);
|
|
2958
|
+
return null == o2 || delete o2[no(jo(t2))];
|
|
2820
2959
|
}
|
|
2821
2960
|
function du(n2, t2, r2, e2) {
|
|
2822
2961
|
return fu(n2, t2, r2(_e2(n2, t2)), e2);
|
|
@@ -5668,7 +5807,7 @@ lodash.exports;
|
|
|
5668
5807
|
(function(module2, exports$1) {
|
|
5669
5808
|
(function() {
|
|
5670
5809
|
var undefined$1;
|
|
5671
|
-
var VERSION = "4.17.
|
|
5810
|
+
var VERSION = "4.17.23";
|
|
5672
5811
|
var LARGE_ARRAY_SIZE2 = 200;
|
|
5673
5812
|
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`";
|
|
5674
5813
|
var HASH_UNDEFINED2 = "__lodash_hash_undefined__";
|
|
@@ -7596,8 +7735,28 @@ lodash.exports;
|
|
|
7596
7735
|
}
|
|
7597
7736
|
function baseUnset(object2, path2) {
|
|
7598
7737
|
path2 = castPath2(path2, object2);
|
|
7599
|
-
|
|
7600
|
-
|
|
7738
|
+
var index2 = -1, length = path2.length;
|
|
7739
|
+
if (!length) {
|
|
7740
|
+
return true;
|
|
7741
|
+
}
|
|
7742
|
+
var isRootPrimitive = object2 == null || typeof object2 !== "object" && typeof object2 !== "function";
|
|
7743
|
+
while (++index2 < length) {
|
|
7744
|
+
var key = path2[index2];
|
|
7745
|
+
if (typeof key !== "string") {
|
|
7746
|
+
continue;
|
|
7747
|
+
}
|
|
7748
|
+
if (key === "__proto__" && !hasOwnProperty2.call(object2, "__proto__")) {
|
|
7749
|
+
return false;
|
|
7750
|
+
}
|
|
7751
|
+
if (key === "constructor" && index2 + 1 < length && typeof path2[index2 + 1] === "string" && path2[index2 + 1] === "prototype") {
|
|
7752
|
+
if (isRootPrimitive && index2 === 0) {
|
|
7753
|
+
continue;
|
|
7754
|
+
}
|
|
7755
|
+
return false;
|
|
7756
|
+
}
|
|
7757
|
+
}
|
|
7758
|
+
var obj = parent(object2, path2);
|
|
7759
|
+
return obj == null || delete obj[toKey2(last(path2))];
|
|
7601
7760
|
}
|
|
7602
7761
|
function baseUpdate(object2, path2, updater, customizer) {
|
|
7603
7762
|
return baseSet(object2, path2, updater(baseGet2(object2, path2)), customizer);
|
|
@@ -11250,73 +11409,76 @@ function envFn(key, defaultValue) {
|
|
|
11250
11409
|
function getKey(key) {
|
|
11251
11410
|
return process.env[key] ?? "";
|
|
11252
11411
|
}
|
|
11253
|
-
|
|
11254
|
-
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
throw new Error(`Invalid json environment variable ${key}: ${error2.message}`);
|
|
11281
|
-
}
|
|
11282
|
-
throw error2;
|
|
11283
|
-
}
|
|
11284
|
-
},
|
|
11285
|
-
array(key, defaultValue) {
|
|
11286
|
-
if (!___default.has(process.env, key)) {
|
|
11287
|
-
return defaultValue;
|
|
11288
|
-
}
|
|
11289
|
-
let value = getKey(key);
|
|
11290
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
11291
|
-
value = value.substring(1, value.length - 1);
|
|
11292
|
-
}
|
|
11293
|
-
return value.split(",").map((v) => {
|
|
11294
|
-
return ___default.trim(___default.trim(v, " "), '"');
|
|
11295
|
-
});
|
|
11296
|
-
},
|
|
11297
|
-
date(key, defaultValue) {
|
|
11298
|
-
if (!___default.has(process.env, key)) {
|
|
11299
|
-
return defaultValue;
|
|
11300
|
-
}
|
|
11301
|
-
return new Date(getKey(key));
|
|
11302
|
-
},
|
|
11303
|
-
/**
|
|
11304
|
-
* Gets a value from env that matches oneOf provided values
|
|
11305
|
-
* @param {string} key
|
|
11306
|
-
* @param {string[]} expectedValues
|
|
11307
|
-
* @param {string|undefined} defaultValue
|
|
11308
|
-
* @returns {string|undefined}
|
|
11309
|
-
*/
|
|
11310
|
-
oneOf(key, expectedValues, defaultValue) {
|
|
11311
|
-
if (!expectedValues) {
|
|
11312
|
-
throw new Error(`env.oneOf requires expectedValues`);
|
|
11313
|
-
}
|
|
11314
|
-
if (defaultValue && !expectedValues.includes(defaultValue)) {
|
|
11315
|
-
throw new Error(`env.oneOf requires defaultValue to be included in expectedValues`);
|
|
11412
|
+
function int$1(key, defaultValue) {
|
|
11413
|
+
if (!___default.has(process.env, key)) {
|
|
11414
|
+
return defaultValue;
|
|
11415
|
+
}
|
|
11416
|
+
return parseInt(getKey(key), 10);
|
|
11417
|
+
}
|
|
11418
|
+
function float$1(key, defaultValue) {
|
|
11419
|
+
if (!___default.has(process.env, key)) {
|
|
11420
|
+
return defaultValue;
|
|
11421
|
+
}
|
|
11422
|
+
return parseFloat(getKey(key));
|
|
11423
|
+
}
|
|
11424
|
+
function bool$1(key, defaultValue) {
|
|
11425
|
+
if (!___default.has(process.env, key)) {
|
|
11426
|
+
return defaultValue;
|
|
11427
|
+
}
|
|
11428
|
+
return getKey(key) === "true";
|
|
11429
|
+
}
|
|
11430
|
+
function json$1(key, defaultValue) {
|
|
11431
|
+
if (!___default.has(process.env, key)) {
|
|
11432
|
+
return defaultValue;
|
|
11433
|
+
}
|
|
11434
|
+
try {
|
|
11435
|
+
return JSON.parse(getKey(key));
|
|
11436
|
+
} catch (error2) {
|
|
11437
|
+
if (error2 instanceof Error) {
|
|
11438
|
+
throw new Error(`Invalid json environment variable ${key}: ${error2.message}`);
|
|
11316
11439
|
}
|
|
11317
|
-
|
|
11318
|
-
|
|
11440
|
+
throw error2;
|
|
11441
|
+
}
|
|
11442
|
+
}
|
|
11443
|
+
function array$1(key, defaultValue) {
|
|
11444
|
+
if (!___default.has(process.env, key)) {
|
|
11445
|
+
return defaultValue;
|
|
11446
|
+
}
|
|
11447
|
+
let value = getKey(key);
|
|
11448
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
11449
|
+
value = value.substring(1, value.length - 1);
|
|
11450
|
+
}
|
|
11451
|
+
return value.split(",").map((v) => {
|
|
11452
|
+
return ___default.trim(___default.trim(v, " "), '"');
|
|
11453
|
+
});
|
|
11454
|
+
}
|
|
11455
|
+
function date$1(key, defaultValue) {
|
|
11456
|
+
if (!___default.has(process.env, key)) {
|
|
11457
|
+
return defaultValue;
|
|
11319
11458
|
}
|
|
11459
|
+
return new Date(getKey(key));
|
|
11460
|
+
}
|
|
11461
|
+
function oneOf(key, expectedValues, defaultValue) {
|
|
11462
|
+
if (!expectedValues) {
|
|
11463
|
+
throw new Error(`env.oneOf requires expectedValues`);
|
|
11464
|
+
}
|
|
11465
|
+
if (defaultValue && !expectedValues.includes(defaultValue)) {
|
|
11466
|
+
throw new Error(`env.oneOf requires defaultValue to be included in expectedValues`);
|
|
11467
|
+
}
|
|
11468
|
+
const rawValue = env(key, defaultValue);
|
|
11469
|
+
if (rawValue !== void 0 && expectedValues.includes(rawValue)) {
|
|
11470
|
+
return rawValue;
|
|
11471
|
+
}
|
|
11472
|
+
return defaultValue;
|
|
11473
|
+
}
|
|
11474
|
+
const utils$9 = {
|
|
11475
|
+
int: int$1,
|
|
11476
|
+
float: float$1,
|
|
11477
|
+
bool: bool$1,
|
|
11478
|
+
json: json$1,
|
|
11479
|
+
array: array$1,
|
|
11480
|
+
date: date$1,
|
|
11481
|
+
oneOf
|
|
11320
11482
|
};
|
|
11321
11483
|
const env = Object.assign(envFn, utils$9);
|
|
11322
11484
|
const SINGLE_TYPE = "singleType";
|
|
@@ -11341,6 +11503,22 @@ const constants$6 = {
|
|
|
11341
11503
|
SINGLE_TYPE,
|
|
11342
11504
|
COLLECTION_TYPE
|
|
11343
11505
|
};
|
|
11506
|
+
const ID_FIELDS = [
|
|
11507
|
+
ID_ATTRIBUTE$4,
|
|
11508
|
+
DOC_ID_ATTRIBUTE$4
|
|
11509
|
+
];
|
|
11510
|
+
const MORPH_TO_KEYS = [
|
|
11511
|
+
"__type"
|
|
11512
|
+
];
|
|
11513
|
+
const DYNAMIC_ZONE_KEYS = [
|
|
11514
|
+
"__component"
|
|
11515
|
+
];
|
|
11516
|
+
const RELATION_OPERATION_KEYS = [
|
|
11517
|
+
"connect",
|
|
11518
|
+
"disconnect",
|
|
11519
|
+
"set",
|
|
11520
|
+
"options"
|
|
11521
|
+
];
|
|
11344
11522
|
const getTimestamps = (model) => {
|
|
11345
11523
|
const attributes = [];
|
|
11346
11524
|
if (fp.has(CREATED_AT_ATTRIBUTE, model.attributes)) {
|
|
@@ -11444,10 +11622,10 @@ const HAS_RELATION_REORDERING = [
|
|
|
11444
11622
|
"oneToMany"
|
|
11445
11623
|
];
|
|
11446
11624
|
const hasRelationReordering = (attribute) => isRelationalAttribute(attribute) && HAS_RELATION_REORDERING.includes(attribute.relation);
|
|
11447
|
-
const isComponentAttribute = (attribute) => [
|
|
11625
|
+
const isComponentAttribute = (attribute) => !!attribute && [
|
|
11448
11626
|
"component",
|
|
11449
11627
|
"dynamiczone"
|
|
11450
|
-
].includes(attribute
|
|
11628
|
+
].includes(attribute.type);
|
|
11451
11629
|
const isDynamicZoneAttribute = (attribute) => !!attribute && attribute.type === "dynamiczone";
|
|
11452
11630
|
const isMorphToRelationalAttribute = (attribute) => {
|
|
11453
11631
|
return !!attribute && isRelationalAttribute(attribute) && attribute.relation?.startsWith?.("morphTo");
|
|
@@ -11484,6 +11662,10 @@ const getContentTypeRoutePrefix = (contentType) => {
|
|
|
11484
11662
|
};
|
|
11485
11663
|
const contentTypes$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
11486
11664
|
__proto__: null,
|
|
11665
|
+
DYNAMIC_ZONE_KEYS,
|
|
11666
|
+
ID_FIELDS,
|
|
11667
|
+
MORPH_TO_KEYS,
|
|
11668
|
+
RELATION_OPERATION_KEYS,
|
|
11487
11669
|
constants: constants$6,
|
|
11488
11670
|
getComponentAttributes,
|
|
11489
11671
|
getContentTypeRoutePrefix,
|
|
@@ -11669,12 +11851,22 @@ const providerFactory = (options = {}) => {
|
|
|
11669
11851
|
}
|
|
11670
11852
|
};
|
|
11671
11853
|
};
|
|
11854
|
+
const parallelWithOrderedErrors = async (promises) => {
|
|
11855
|
+
const results = await Promise.allSettled(promises);
|
|
11856
|
+
for (let i = 0; i < results.length; i += 1) {
|
|
11857
|
+
const result = results[i];
|
|
11858
|
+
if (result.status === "rejected") {
|
|
11859
|
+
throw result.reason;
|
|
11860
|
+
}
|
|
11861
|
+
}
|
|
11862
|
+
return results.map((r) => r.value);
|
|
11863
|
+
};
|
|
11672
11864
|
const traverseEntity = async (visitor2, options, entity) => {
|
|
11673
11865
|
const { path: path2 = {
|
|
11674
11866
|
raw: null,
|
|
11675
11867
|
attribute: null,
|
|
11676
11868
|
rawWithIndices: null
|
|
11677
|
-
}, schema: schema2, getModel } = options;
|
|
11869
|
+
}, schema: schema2, getModel, allowedExtraRootKeys } = options;
|
|
11678
11870
|
let parent = options.parent;
|
|
11679
11871
|
const traverseMorphRelationTarget = async (visitor3, path3, entry) => {
|
|
11680
11872
|
const targetSchema = getModel(entry.__type);
|
|
@@ -11682,7 +11874,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11682
11874
|
schema: targetSchema,
|
|
11683
11875
|
path: path3,
|
|
11684
11876
|
getModel,
|
|
11685
|
-
parent
|
|
11877
|
+
parent,
|
|
11878
|
+
allowedExtraRootKeys
|
|
11686
11879
|
};
|
|
11687
11880
|
return traverseEntity(visitor3, traverseOptions, entry);
|
|
11688
11881
|
};
|
|
@@ -11691,7 +11884,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11691
11884
|
schema: schema3,
|
|
11692
11885
|
path: path3,
|
|
11693
11886
|
getModel,
|
|
11694
|
-
parent
|
|
11887
|
+
parent,
|
|
11888
|
+
allowedExtraRootKeys
|
|
11695
11889
|
};
|
|
11696
11890
|
return traverseEntity(visitor3, traverseOptions, entry);
|
|
11697
11891
|
};
|
|
@@ -11702,7 +11896,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11702
11896
|
schema: targetSchema,
|
|
11703
11897
|
path: path3,
|
|
11704
11898
|
getModel,
|
|
11705
|
-
parent
|
|
11899
|
+
parent,
|
|
11900
|
+
allowedExtraRootKeys
|
|
11706
11901
|
};
|
|
11707
11902
|
return traverseEntity(visitor3, traverseOptions, entry);
|
|
11708
11903
|
};
|
|
@@ -11711,7 +11906,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11711
11906
|
schema: schema3,
|
|
11712
11907
|
path: path3,
|
|
11713
11908
|
getModel,
|
|
11714
|
-
parent
|
|
11909
|
+
parent,
|
|
11910
|
+
allowedExtraRootKeys
|
|
11715
11911
|
};
|
|
11716
11912
|
return traverseEntity(visitor3, traverseOptions, entry);
|
|
11717
11913
|
};
|
|
@@ -11721,7 +11917,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11721
11917
|
schema: targetSchema,
|
|
11722
11918
|
path: path3,
|
|
11723
11919
|
getModel,
|
|
11724
|
-
parent
|
|
11920
|
+
parent,
|
|
11921
|
+
allowedExtraRootKeys
|
|
11725
11922
|
};
|
|
11726
11923
|
return traverseEntity(visitor3, traverseOptions, entry);
|
|
11727
11924
|
};
|
|
@@ -11752,7 +11949,8 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11752
11949
|
attribute,
|
|
11753
11950
|
path: newPath,
|
|
11754
11951
|
getModel,
|
|
11755
|
-
parent
|
|
11952
|
+
parent,
|
|
11953
|
+
allowedExtraRootKeys
|
|
11756
11954
|
};
|
|
11757
11955
|
await visitor2(visitorOptions, visitorUtils);
|
|
11758
11956
|
const value = copy[key];
|
|
@@ -11769,15 +11967,13 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11769
11967
|
const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
|
|
11770
11968
|
const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
|
|
11771
11969
|
if (fp.isArray(value)) {
|
|
11772
|
-
|
|
11773
|
-
for (let i2 = 0; i2 < value.length; i2 += 1) {
|
|
11970
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i2) => {
|
|
11774
11971
|
const arrayPath = {
|
|
11775
11972
|
...newPath,
|
|
11776
11973
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i2}` : `${newPath.rawWithIndices}.${i2}`
|
|
11777
11974
|
};
|
|
11778
|
-
|
|
11779
|
-
}
|
|
11780
|
-
copy[key] = res;
|
|
11975
|
+
return method(visitor2, arrayPath, item);
|
|
11976
|
+
}));
|
|
11781
11977
|
} else {
|
|
11782
11978
|
copy[key] = await method(visitor2, newPath, value);
|
|
11783
11979
|
}
|
|
@@ -11791,15 +11987,13 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11791
11987
|
path: newPath
|
|
11792
11988
|
};
|
|
11793
11989
|
if (fp.isArray(value)) {
|
|
11794
|
-
|
|
11795
|
-
for (let i2 = 0; i2 < value.length; i2 += 1) {
|
|
11990
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i2) => {
|
|
11796
11991
|
const arrayPath = {
|
|
11797
11992
|
...newPath,
|
|
11798
11993
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i2}` : `${newPath.rawWithIndices}.${i2}`
|
|
11799
11994
|
};
|
|
11800
|
-
|
|
11801
|
-
}
|
|
11802
|
-
copy[key] = res;
|
|
11995
|
+
return traverseMediaTarget(visitor2, arrayPath, item);
|
|
11996
|
+
}));
|
|
11803
11997
|
} else {
|
|
11804
11998
|
copy[key] = await traverseMediaTarget(visitor2, newPath, value);
|
|
11805
11999
|
}
|
|
@@ -11814,15 +12008,13 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11814
12008
|
};
|
|
11815
12009
|
const targetSchema = getModel(attribute.component);
|
|
11816
12010
|
if (fp.isArray(value)) {
|
|
11817
|
-
|
|
11818
|
-
for (let i2 = 0; i2 < value.length; i2 += 1) {
|
|
12011
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i2) => {
|
|
11819
12012
|
const arrayPath = {
|
|
11820
12013
|
...newPath,
|
|
11821
12014
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i2}` : `${newPath.rawWithIndices}.${i2}`
|
|
11822
12015
|
};
|
|
11823
|
-
|
|
11824
|
-
}
|
|
11825
|
-
copy[key] = res;
|
|
12016
|
+
return traverseComponent(visitor2, arrayPath, targetSchema, item);
|
|
12017
|
+
}));
|
|
11826
12018
|
} else {
|
|
11827
12019
|
copy[key] = await traverseComponent(visitor2, newPath, targetSchema, value);
|
|
11828
12020
|
}
|
|
@@ -11835,15 +12027,13 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
11835
12027
|
attribute,
|
|
11836
12028
|
path: newPath
|
|
11837
12029
|
};
|
|
11838
|
-
|
|
11839
|
-
for (let i2 = 0; i2 < value.length; i2 += 1) {
|
|
12030
|
+
copy[key] = await parallelWithOrderedErrors(value.map((item, i2) => {
|
|
11840
12031
|
const arrayPath = {
|
|
11841
12032
|
...newPath,
|
|
11842
12033
|
rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i2}` : `${newPath.rawWithIndices}.${i2}`
|
|
11843
12034
|
};
|
|
11844
|
-
|
|
11845
|
-
}
|
|
11846
|
-
copy[key] = res;
|
|
12035
|
+
return visitDynamicZoneEntry(visitor2, arrayPath, item);
|
|
12036
|
+
}));
|
|
11847
12037
|
continue;
|
|
11848
12038
|
}
|
|
11849
12039
|
}
|
|
@@ -12589,6 +12779,23 @@ const generateInstallId = (projectId, installId) => {
|
|
|
12589
12779
|
return require$$1__default.default.randomUUID();
|
|
12590
12780
|
}
|
|
12591
12781
|
};
|
|
12782
|
+
const createModelCache = (getModelFn) => {
|
|
12783
|
+
const cache = /* @__PURE__ */ new Map();
|
|
12784
|
+
return {
|
|
12785
|
+
getModel(uid) {
|
|
12786
|
+
const cached = cache.get(uid);
|
|
12787
|
+
if (cached) {
|
|
12788
|
+
return cached;
|
|
12789
|
+
}
|
|
12790
|
+
const model = getModelFn(uid);
|
|
12791
|
+
cache.set(uid, model);
|
|
12792
|
+
return model;
|
|
12793
|
+
},
|
|
12794
|
+
clear() {
|
|
12795
|
+
cache.clear();
|
|
12796
|
+
}
|
|
12797
|
+
};
|
|
12798
|
+
};
|
|
12592
12799
|
var map$2;
|
|
12593
12800
|
try {
|
|
12594
12801
|
map$2 = Map;
|
|
@@ -14088,27 +14295,11 @@ Cache.prototype.set = function(key, value) {
|
|
|
14088
14295
|
return this._values[key] = value;
|
|
14089
14296
|
};
|
|
14090
14297
|
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;
|
|
14091
|
-
var pathCache = new Cache(MAX_CACHE_SIZE)
|
|
14298
|
+
var pathCache = new Cache(MAX_CACHE_SIZE);
|
|
14299
|
+
new Cache(MAX_CACHE_SIZE);
|
|
14300
|
+
var getCache = new Cache(MAX_CACHE_SIZE);
|
|
14092
14301
|
var propertyExpr = {
|
|
14093
|
-
Cache,
|
|
14094
14302
|
split,
|
|
14095
|
-
normalizePath,
|
|
14096
|
-
setter: function(path2) {
|
|
14097
|
-
var parts = normalizePath(path2);
|
|
14098
|
-
return setCache.get(path2) || setCache.set(path2, function setter(obj, value) {
|
|
14099
|
-
var index2 = 0;
|
|
14100
|
-
var len = parts.length;
|
|
14101
|
-
var data = obj;
|
|
14102
|
-
while (index2 < len - 1) {
|
|
14103
|
-
var part = parts[index2];
|
|
14104
|
-
if (part === "__proto__" || part === "constructor" || part === "prototype") {
|
|
14105
|
-
return obj;
|
|
14106
|
-
}
|
|
14107
|
-
data = data[parts[index2++]];
|
|
14108
|
-
}
|
|
14109
|
-
data[parts[index2]] = value;
|
|
14110
|
-
});
|
|
14111
|
-
},
|
|
14112
14303
|
getter: function(path2, safe) {
|
|
14113
14304
|
var parts = normalizePath(path2);
|
|
14114
14305
|
return getCache.get(path2) || getCache.set(path2, function getter(data) {
|
|
@@ -14120,11 +14311,6 @@ var propertyExpr = {
|
|
|
14120
14311
|
return data;
|
|
14121
14312
|
});
|
|
14122
14313
|
},
|
|
14123
|
-
join: function(segments) {
|
|
14124
|
-
return segments.reduce(function(path2, part) {
|
|
14125
|
-
return path2 + (isQuoted(part) || DIGIT_REGEX.test(part) ? "[" + part + "]" : (path2 ? "." : "") + part);
|
|
14126
|
-
}, "");
|
|
14127
|
-
},
|
|
14128
14314
|
forEach: function(path2, cb, thisArg) {
|
|
14129
14315
|
forEach(Array.isArray(path2) ? path2 : split(path2), cb, thisArg);
|
|
14130
14316
|
}
|
|
@@ -16954,10 +17140,10 @@ const createTransformer = ({ getModel }) => {
|
|
|
16954
17140
|
}
|
|
16955
17141
|
return pageVal;
|
|
16956
17142
|
};
|
|
16957
|
-
const convertPageSizeQueryParams = (pageSize,
|
|
17143
|
+
const convertPageSizeQueryParams = (pageSize, _page) => {
|
|
16958
17144
|
const pageSizeVal = fp.toNumber(pageSize);
|
|
16959
17145
|
if (!fp.isInteger(pageSizeVal) || pageSizeVal <= 0) {
|
|
16960
|
-
throw new PaginationError(`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${
|
|
17146
|
+
throw new PaginationError(`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${pageSize}`);
|
|
16961
17147
|
}
|
|
16962
17148
|
return pageSizeVal;
|
|
16963
17149
|
};
|
|
@@ -17132,7 +17318,7 @@ const createTransformer = ({ getModel }) => {
|
|
|
17132
17318
|
query.page = convertPageQueryParams(page);
|
|
17133
17319
|
}
|
|
17134
17320
|
if (!fp.isNil(pageSize)) {
|
|
17135
|
-
query.pageSize = convertPageSizeQueryParams(pageSize
|
|
17321
|
+
query.pageSize = convertPageSizeQueryParams(pageSize);
|
|
17136
17322
|
}
|
|
17137
17323
|
if (!fp.isNil(start)) {
|
|
17138
17324
|
query.offset = convertStartQueryParams(start);
|
|
@@ -17280,7 +17466,7 @@ const createTransformer = ({ getModel }) => {
|
|
|
17280
17466
|
query.page = convertPageQueryParams(page);
|
|
17281
17467
|
}
|
|
17282
17468
|
if (!fp.isNil(pageSize)) {
|
|
17283
|
-
query.pageSize = convertPageSizeQueryParams(pageSize
|
|
17469
|
+
query.pageSize = convertPageSizeQueryParams(pageSize);
|
|
17284
17470
|
}
|
|
17285
17471
|
if (!fp.isNil(start)) {
|
|
17286
17472
|
query.offset = convertStartQueryParams(start);
|
|
@@ -17307,6 +17493,43 @@ const convertQueryParams = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
|
|
|
17307
17493
|
__proto__: null,
|
|
17308
17494
|
createTransformer
|
|
17309
17495
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
17496
|
+
const SHARED_QUERY_PARAM_KEYS = [
|
|
17497
|
+
"filters",
|
|
17498
|
+
"sort",
|
|
17499
|
+
"fields",
|
|
17500
|
+
"populate",
|
|
17501
|
+
"status",
|
|
17502
|
+
"locale",
|
|
17503
|
+
"page",
|
|
17504
|
+
"pageSize",
|
|
17505
|
+
"start",
|
|
17506
|
+
"limit",
|
|
17507
|
+
"_q",
|
|
17508
|
+
"hasPublishedVersion"
|
|
17509
|
+
];
|
|
17510
|
+
const ALLOWED_QUERY_PARAM_KEYS = [
|
|
17511
|
+
...SHARED_QUERY_PARAM_KEYS,
|
|
17512
|
+
"pagination",
|
|
17513
|
+
"count",
|
|
17514
|
+
"ordering"
|
|
17515
|
+
];
|
|
17516
|
+
const RESERVED_INPUT_PARAM_KEYS = [
|
|
17517
|
+
constants$6.ID_ATTRIBUTE,
|
|
17518
|
+
constants$6.DOC_ID_ATTRIBUTE
|
|
17519
|
+
];
|
|
17520
|
+
function getExtraQueryKeysFromRoute(route) {
|
|
17521
|
+
if (!route?.request?.query) return [];
|
|
17522
|
+
const coreKeys = new Set(ALLOWED_QUERY_PARAM_KEYS);
|
|
17523
|
+
return Object.keys(route.request.query).filter((key) => !coreKeys.has(key));
|
|
17524
|
+
}
|
|
17525
|
+
function getExtraRootKeysFromRouteBody(route) {
|
|
17526
|
+
const bodySchema = route?.request?.body?.["application/json"];
|
|
17527
|
+
if (!bodySchema || typeof bodySchema !== "object") return [];
|
|
17528
|
+
if ("shape" in bodySchema && typeof bodySchema.shape === "object") {
|
|
17529
|
+
return Object.keys(bodySchema.shape);
|
|
17530
|
+
}
|
|
17531
|
+
return [];
|
|
17532
|
+
}
|
|
17310
17533
|
var indentString$2 = (string2, count = 1, options) => {
|
|
17311
17534
|
options = {
|
|
17312
17535
|
indent: " ",
|
|
@@ -17694,6 +17917,35 @@ var removeRestrictedFields = (restrictedFields = null) => ({ key, path: { attrib
|
|
|
17694
17917
|
remove(key);
|
|
17695
17918
|
}
|
|
17696
17919
|
};
|
|
17920
|
+
const removeUnrecognizedFields = ({ key, attribute, path: path2, schema: schema2, parent, allowedExtraRootKeys }, { remove }) => {
|
|
17921
|
+
if (attribute) {
|
|
17922
|
+
return;
|
|
17923
|
+
}
|
|
17924
|
+
if (path2.attribute === null) {
|
|
17925
|
+
if (ID_FIELDS.includes(key)) {
|
|
17926
|
+
return;
|
|
17927
|
+
}
|
|
17928
|
+
if (allowedExtraRootKeys?.includes(key)) {
|
|
17929
|
+
return;
|
|
17930
|
+
}
|
|
17931
|
+
remove(key);
|
|
17932
|
+
return;
|
|
17933
|
+
}
|
|
17934
|
+
if (isMorphToRelationalAttribute(parent?.attribute) && MORPH_TO_KEYS.includes(key)) {
|
|
17935
|
+
return;
|
|
17936
|
+
}
|
|
17937
|
+
if (isComponentSchema(schema2) && isDynamicZoneAttribute(parent?.attribute) && DYNAMIC_ZONE_KEYS.includes(key)) {
|
|
17938
|
+
return;
|
|
17939
|
+
}
|
|
17940
|
+
if ((isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute)) && RELATION_OPERATION_KEYS.includes(key)) {
|
|
17941
|
+
return;
|
|
17942
|
+
}
|
|
17943
|
+
const canUseID = isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute) || isComponentAttribute(parent?.attribute);
|
|
17944
|
+
if (canUseID && ID_FIELDS.includes(key)) {
|
|
17945
|
+
return;
|
|
17946
|
+
}
|
|
17947
|
+
remove(key);
|
|
17948
|
+
};
|
|
17697
17949
|
const visitor$4 = ({ schema: schema2, key, value }, { set: set2 }) => {
|
|
17698
17950
|
if (key === "" && value === "*") {
|
|
17699
17951
|
const { attributes } = schema2;
|
|
@@ -17718,7 +17970,8 @@ const index$5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
17718
17970
|
removePassword: visitor$8,
|
|
17719
17971
|
removePrivate: visitor$7,
|
|
17720
17972
|
removeRestrictedFields,
|
|
17721
|
-
removeRestrictedRelations
|
|
17973
|
+
removeRestrictedRelations,
|
|
17974
|
+
removeUnrecognizedFields
|
|
17722
17975
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
17723
17976
|
const DEFAULT_PATH = {
|
|
17724
17977
|
raw: null,
|
|
@@ -18569,15 +18822,18 @@ const sanitizers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
|
|
|
18569
18822
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
18570
18823
|
const createAPISanitizers = (opts) => {
|
|
18571
18824
|
const { getModel } = opts;
|
|
18572
|
-
const sanitizeInput = (data, schema2, { auth } = {}) => {
|
|
18825
|
+
const sanitizeInput = (data, schema2, { auth, strictParams = false, route } = {}) => {
|
|
18573
18826
|
if (!schema2) {
|
|
18574
18827
|
throw new Error("Missing schema in sanitizeInput");
|
|
18575
18828
|
}
|
|
18576
18829
|
if (fp.isArray(data)) {
|
|
18577
18830
|
return Promise.all(data.map((entry) => sanitizeInput(entry, schema2, {
|
|
18578
|
-
auth
|
|
18831
|
+
auth,
|
|
18832
|
+
strictParams,
|
|
18833
|
+
route
|
|
18579
18834
|
})));
|
|
18580
18835
|
}
|
|
18836
|
+
const allowedExtraRootKeys = getExtraRootKeysFromRouteBody(route);
|
|
18581
18837
|
const nonWritableAttributes = getNonWritableAttributes(schema2);
|
|
18582
18838
|
const transforms = [
|
|
18583
18839
|
// Remove first level ID in inputs
|
|
@@ -18589,6 +18845,13 @@ const createAPISanitizers = (opts) => {
|
|
|
18589
18845
|
getModel
|
|
18590
18846
|
})
|
|
18591
18847
|
];
|
|
18848
|
+
if (strictParams) {
|
|
18849
|
+
transforms.push(traverseEntity$1(removeUnrecognizedFields, {
|
|
18850
|
+
schema: schema2,
|
|
18851
|
+
getModel,
|
|
18852
|
+
allowedExtraRootKeys
|
|
18853
|
+
}));
|
|
18854
|
+
}
|
|
18592
18855
|
if (auth) {
|
|
18593
18856
|
transforms.push(traverseEntity$1(removeRestrictedRelations(auth), {
|
|
18594
18857
|
schema: schema2,
|
|
@@ -18596,6 +18859,28 @@ const createAPISanitizers = (opts) => {
|
|
|
18596
18859
|
}));
|
|
18597
18860
|
}
|
|
18598
18861
|
opts?.sanitizers?.input?.forEach((sanitizer) => transforms.push(sanitizer(schema2)));
|
|
18862
|
+
const routeBodySanitizeTransform = async (data2) => {
|
|
18863
|
+
if (!data2 || typeof data2 !== "object" || Array.isArray(data2)) return data2;
|
|
18864
|
+
const obj = data2;
|
|
18865
|
+
const bodySchema = route?.request?.body?.["application/json"];
|
|
18866
|
+
if (bodySchema && typeof bodySchema === "object" && "shape" in bodySchema) {
|
|
18867
|
+
const shape = bodySchema.shape;
|
|
18868
|
+
for (const key of Object.keys(shape)) {
|
|
18869
|
+
if (key === "data" || !(key in obj)) continue;
|
|
18870
|
+
const zodSchema = shape[key];
|
|
18871
|
+
if (zodSchema && typeof zodSchema.safeParse === "function") {
|
|
18872
|
+
const result = zodSchema.safeParse(obj[key]);
|
|
18873
|
+
if (result.success) {
|
|
18874
|
+
obj[key] = result.data;
|
|
18875
|
+
} else {
|
|
18876
|
+
delete obj[key];
|
|
18877
|
+
}
|
|
18878
|
+
}
|
|
18879
|
+
}
|
|
18880
|
+
}
|
|
18881
|
+
return data2;
|
|
18882
|
+
};
|
|
18883
|
+
transforms.push(routeBodySanitizeTransform);
|
|
18599
18884
|
return pipe$1(...transforms)(data);
|
|
18600
18885
|
};
|
|
18601
18886
|
const sanitizeOutput = async (data, schema2, { auth } = {}) => {
|
|
@@ -18626,7 +18911,7 @@ const createAPISanitizers = (opts) => {
|
|
|
18626
18911
|
opts?.sanitizers?.output?.forEach((sanitizer) => transforms.push(sanitizer(schema2)));
|
|
18627
18912
|
return pipe$1(...transforms)(data);
|
|
18628
18913
|
};
|
|
18629
|
-
const sanitizeQuery = async (query, schema2, { auth } = {}) => {
|
|
18914
|
+
const sanitizeQuery = async (query, schema2, { auth, strictParams = false, route } = {}) => {
|
|
18630
18915
|
if (!schema2) {
|
|
18631
18916
|
throw new Error("Missing schema in sanitizeQuery");
|
|
18632
18917
|
}
|
|
@@ -18656,6 +18941,30 @@ const createAPISanitizers = (opts) => {
|
|
|
18656
18941
|
populate: await sanitizePopulate(populate2, schema2)
|
|
18657
18942
|
});
|
|
18658
18943
|
}
|
|
18944
|
+
const extraQueryKeys = getExtraQueryKeysFromRoute(route);
|
|
18945
|
+
const routeQuerySchema = route?.request?.query;
|
|
18946
|
+
if (routeQuerySchema) {
|
|
18947
|
+
for (const key of extraQueryKeys) {
|
|
18948
|
+
if (key in query) {
|
|
18949
|
+
const zodSchema = routeQuerySchema[key];
|
|
18950
|
+
if (zodSchema && typeof zodSchema.safeParse === "function") {
|
|
18951
|
+
const result = zodSchema.safeParse(query[key]);
|
|
18952
|
+
if (result.success) {
|
|
18953
|
+
sanitizedQuery[key] = result.data;
|
|
18954
|
+
} else {
|
|
18955
|
+
delete sanitizedQuery[key];
|
|
18956
|
+
}
|
|
18957
|
+
}
|
|
18958
|
+
}
|
|
18959
|
+
}
|
|
18960
|
+
}
|
|
18961
|
+
if (strictParams) {
|
|
18962
|
+
const allowedKeys = [
|
|
18963
|
+
...ALLOWED_QUERY_PARAM_KEYS,
|
|
18964
|
+
...extraQueryKeys
|
|
18965
|
+
];
|
|
18966
|
+
return fp.pick(allowedKeys, sanitizedQuery);
|
|
18967
|
+
}
|
|
18659
18968
|
return sanitizedQuery;
|
|
18660
18969
|
};
|
|
18661
18970
|
const sanitizeFilters = (filters2, schema2, { auth } = {}) => {
|
|
@@ -18958,54 +19267,38 @@ var throwRestrictedFields = (restrictedFields = null) => ({ key, path: { attribu
|
|
|
18958
19267
|
});
|
|
18959
19268
|
}
|
|
18960
19269
|
};
|
|
18961
|
-
const
|
|
18962
|
-
constants$6.DOC_ID_ATTRIBUTE,
|
|
18963
|
-
constants$6.DOC_ID_ATTRIBUTE
|
|
18964
|
-
];
|
|
18965
|
-
const ALLOWED_ROOT_LEVEL_FIELDS = [
|
|
18966
|
-
...ID_FIELDS
|
|
18967
|
-
];
|
|
18968
|
-
const MORPH_TO_ALLOWED_FIELDS = [
|
|
18969
|
-
"__type"
|
|
18970
|
-
];
|
|
18971
|
-
const DYNAMIC_ZONE_ALLOWED_FIELDS = [
|
|
18972
|
-
"__component"
|
|
18973
|
-
];
|
|
18974
|
-
const RELATION_REORDERING_FIELDS = [
|
|
18975
|
-
"connect",
|
|
18976
|
-
"disconnect",
|
|
18977
|
-
"set",
|
|
18978
|
-
"options"
|
|
18979
|
-
];
|
|
18980
|
-
const throwUnrecognizedFields = ({ key, attribute, path: path2, schema: schema2, parent }) => {
|
|
19270
|
+
const throwUnrecognizedFields = ({ key, attribute, path: path2, schema: schema2, parent, allowedExtraRootKeys }, _visitorUtils) => {
|
|
18981
19271
|
if (attribute) {
|
|
18982
19272
|
return;
|
|
18983
19273
|
}
|
|
18984
19274
|
if (path2.attribute === null) {
|
|
18985
|
-
if (
|
|
19275
|
+
if (ID_FIELDS.includes(key)) {
|
|
19276
|
+
return;
|
|
19277
|
+
}
|
|
19278
|
+
if (allowedExtraRootKeys?.includes(key)) {
|
|
18986
19279
|
return;
|
|
18987
19280
|
}
|
|
18988
19281
|
return throwInvalidKey({
|
|
18989
19282
|
key,
|
|
18990
|
-
path: attribute
|
|
19283
|
+
path: path2.attribute
|
|
18991
19284
|
});
|
|
18992
19285
|
}
|
|
18993
|
-
if (isMorphToRelationalAttribute(parent?.attribute) &&
|
|
19286
|
+
if (isMorphToRelationalAttribute(parent?.attribute) && MORPH_TO_KEYS.includes(key)) {
|
|
18994
19287
|
return;
|
|
18995
19288
|
}
|
|
18996
|
-
if (isComponentSchema(schema2) && isDynamicZoneAttribute(parent?.attribute) &&
|
|
19289
|
+
if (isComponentSchema(schema2) && isDynamicZoneAttribute(parent?.attribute) && DYNAMIC_ZONE_KEYS.includes(key)) {
|
|
18997
19290
|
return;
|
|
18998
19291
|
}
|
|
18999
|
-
if (
|
|
19292
|
+
if ((isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute)) && RELATION_OPERATION_KEYS.includes(key)) {
|
|
19000
19293
|
return;
|
|
19001
19294
|
}
|
|
19002
|
-
const canUseID = isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute);
|
|
19003
|
-
if (canUseID &&
|
|
19295
|
+
const canUseID = isRelationalAttribute(parent?.attribute) || isMediaAttribute(parent?.attribute) || isComponentAttribute(parent?.attribute);
|
|
19296
|
+
if (canUseID && ID_FIELDS.includes(key)) {
|
|
19004
19297
|
return;
|
|
19005
19298
|
}
|
|
19006
19299
|
throwInvalidKey({
|
|
19007
19300
|
key,
|
|
19008
|
-
path: attribute
|
|
19301
|
+
path: path2.attribute
|
|
19009
19302
|
});
|
|
19010
19303
|
};
|
|
19011
19304
|
const index$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -19327,16 +19620,16 @@ const validators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
|
|
|
19327
19620
|
const { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants$6;
|
|
19328
19621
|
const createAPIValidators = (opts) => {
|
|
19329
19622
|
const { getModel } = opts || {};
|
|
19330
|
-
const validateInput = async (data, schema2,
|
|
19623
|
+
const validateInput = async (data, schema2, options = {}) => {
|
|
19624
|
+
const { auth, route } = options;
|
|
19331
19625
|
if (!schema2) {
|
|
19332
19626
|
throw new Error("Missing schema in validateInput");
|
|
19333
19627
|
}
|
|
19334
19628
|
if (fp.isArray(data)) {
|
|
19335
|
-
await Promise.all(data.map((entry) => validateInput(entry, schema2,
|
|
19336
|
-
auth
|
|
19337
|
-
})));
|
|
19629
|
+
await Promise.all(data.map((entry) => validateInput(entry, schema2, options)));
|
|
19338
19630
|
return;
|
|
19339
19631
|
}
|
|
19632
|
+
const allowedExtraRootKeys = getExtraRootKeysFromRouteBody(route);
|
|
19340
19633
|
const nonWritableAttributes = getNonWritableAttributes(schema2);
|
|
19341
19634
|
const transforms = [
|
|
19342
19635
|
(data2) => {
|
|
@@ -19359,10 +19652,11 @@ const createAPIValidators = (opts) => {
|
|
|
19359
19652
|
schema: schema2,
|
|
19360
19653
|
getModel
|
|
19361
19654
|
}),
|
|
19362
|
-
// unrecognized attributes
|
|
19655
|
+
// unrecognized attributes (allowedExtraRootKeys = registered input param keys)
|
|
19363
19656
|
traverseEntity$1(throwUnrecognizedFields, {
|
|
19364
19657
|
schema: schema2,
|
|
19365
|
-
getModel
|
|
19658
|
+
getModel,
|
|
19659
|
+
allowedExtraRootKeys
|
|
19366
19660
|
})
|
|
19367
19661
|
];
|
|
19368
19662
|
if (auth) {
|
|
@@ -19374,6 +19668,28 @@ const createAPIValidators = (opts) => {
|
|
|
19374
19668
|
opts?.validators?.input?.forEach((validator) => transforms.push(validator(schema2)));
|
|
19375
19669
|
try {
|
|
19376
19670
|
await pipe$1(...transforms)(data);
|
|
19671
|
+
if (fp.isObject(data) && route?.request?.body?.["application/json"]) {
|
|
19672
|
+
const bodySchema = route.request.body["application/json"];
|
|
19673
|
+
if (typeof bodySchema === "object" && "shape" in bodySchema) {
|
|
19674
|
+
const shape = bodySchema.shape;
|
|
19675
|
+
const dataObj = data;
|
|
19676
|
+
for (const key of Object.keys(shape)) {
|
|
19677
|
+
if (key === "data" || !(key in dataObj)) continue;
|
|
19678
|
+
const zodSchema = shape[key];
|
|
19679
|
+
if (zodSchema && typeof zodSchema.parse === "function") {
|
|
19680
|
+
const result = zodSchema.safeParse(dataObj[key]);
|
|
19681
|
+
if (!result.success) {
|
|
19682
|
+
throw new ValidationError2(result.error?.message ?? "Validation failed", {
|
|
19683
|
+
key,
|
|
19684
|
+
path: null,
|
|
19685
|
+
source: "body",
|
|
19686
|
+
param: key
|
|
19687
|
+
});
|
|
19688
|
+
}
|
|
19689
|
+
}
|
|
19690
|
+
}
|
|
19691
|
+
}
|
|
19692
|
+
}
|
|
19377
19693
|
} catch (e) {
|
|
19378
19694
|
if (e instanceof ValidationError2) {
|
|
19379
19695
|
e.details.source = "body";
|
|
@@ -19381,10 +19697,52 @@ const createAPIValidators = (opts) => {
|
|
|
19381
19697
|
throw e;
|
|
19382
19698
|
}
|
|
19383
19699
|
};
|
|
19384
|
-
const validateQuery = async (query, schema2, { auth } = {}) => {
|
|
19700
|
+
const validateQuery = async (query, schema2, { auth, strictParams = false, route } = {}) => {
|
|
19385
19701
|
if (!schema2) {
|
|
19386
19702
|
throw new Error("Missing schema in validateQuery");
|
|
19387
19703
|
}
|
|
19704
|
+
if (strictParams) {
|
|
19705
|
+
const extraQueryKeys = getExtraQueryKeysFromRoute(route);
|
|
19706
|
+
const allowedKeys = [
|
|
19707
|
+
...ALLOWED_QUERY_PARAM_KEYS,
|
|
19708
|
+
...extraQueryKeys
|
|
19709
|
+
];
|
|
19710
|
+
for (const key of Object.keys(query)) {
|
|
19711
|
+
if (!allowedKeys.includes(key)) {
|
|
19712
|
+
try {
|
|
19713
|
+
throwInvalidKey({
|
|
19714
|
+
key,
|
|
19715
|
+
path: null
|
|
19716
|
+
});
|
|
19717
|
+
} catch (e) {
|
|
19718
|
+
if (e instanceof ValidationError2) {
|
|
19719
|
+
e.details.source = "query";
|
|
19720
|
+
e.details.param = key;
|
|
19721
|
+
}
|
|
19722
|
+
throw e;
|
|
19723
|
+
}
|
|
19724
|
+
}
|
|
19725
|
+
}
|
|
19726
|
+
const routeQuerySchema = route?.request?.query;
|
|
19727
|
+
if (routeQuerySchema) {
|
|
19728
|
+
for (const key of extraQueryKeys) {
|
|
19729
|
+
if (key in query) {
|
|
19730
|
+
const zodSchema = routeQuerySchema[key];
|
|
19731
|
+
if (zodSchema && typeof zodSchema.parse === "function") {
|
|
19732
|
+
const result = zodSchema.safeParse(query[key]);
|
|
19733
|
+
if (!result.success) {
|
|
19734
|
+
throw new ValidationError2(result.error?.message ?? "Invalid query param", {
|
|
19735
|
+
key,
|
|
19736
|
+
path: null,
|
|
19737
|
+
source: "query",
|
|
19738
|
+
param: key
|
|
19739
|
+
});
|
|
19740
|
+
}
|
|
19741
|
+
}
|
|
19742
|
+
}
|
|
19743
|
+
}
|
|
19744
|
+
}
|
|
19745
|
+
}
|
|
19388
19746
|
const { filters: filters2, sort: sort2, fields: fields2, populate: populate2 } = query;
|
|
19389
19747
|
if (filters2) {
|
|
19390
19748
|
await validateFilters2(filters2, schema2, {
|
|
@@ -28120,7 +28478,14 @@ var preferredPm = async function preferredPM(pkgPath) {
|
|
|
28120
28478
|
};
|
|
28121
28479
|
}
|
|
28122
28480
|
try {
|
|
28123
|
-
|
|
28481
|
+
const workspaceRoot = findYarnWorkspaceRoot(pkgPath);
|
|
28482
|
+
if (typeof workspaceRoot === "string") {
|
|
28483
|
+
if (await pathExists(path.join(workspaceRoot, "package-lock.json"))) {
|
|
28484
|
+
return {
|
|
28485
|
+
name: "npm",
|
|
28486
|
+
version: ">=7"
|
|
28487
|
+
};
|
|
28488
|
+
}
|
|
28124
28489
|
return {
|
|
28125
28490
|
name: "yarn",
|
|
28126
28491
|
version: "*"
|
|
@@ -29846,13 +30211,17 @@ const extendMiddlewareConfiguration = (middlewares2, middleware2) => {
|
|
|
29846
30211
|
};
|
|
29847
30212
|
const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
29848
30213
|
__proto__: null,
|
|
30214
|
+
ALLOWED_QUERY_PARAM_KEYS,
|
|
29849
30215
|
AbstractRouteValidator,
|
|
29850
30216
|
CSP_DEFAULTS,
|
|
30217
|
+
RESERVED_INPUT_PARAM_KEYS,
|
|
30218
|
+
SHARED_QUERY_PARAM_KEYS,
|
|
29851
30219
|
arrays,
|
|
29852
30220
|
async,
|
|
29853
30221
|
augmentSchema,
|
|
29854
30222
|
contentTypes: contentTypes$1,
|
|
29855
30223
|
createContentApiRoutesFactory,
|
|
30224
|
+
createModelCache,
|
|
29856
30225
|
dates,
|
|
29857
30226
|
env,
|
|
29858
30227
|
errors,
|
|
@@ -29898,7 +30267,8 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
|
|
|
29898
30267
|
validateYupSchema,
|
|
29899
30268
|
validateYupSchemaSync,
|
|
29900
30269
|
validateZod,
|
|
29901
|
-
yup
|
|
30270
|
+
yup,
|
|
30271
|
+
z: z.z
|
|
29902
30272
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
29903
30273
|
const require$$0 = /* @__PURE__ */ getAugmentedNamespace(dist);
|
|
29904
30274
|
const { castArray, isNil: isNil$1, pipe, every } = fp;
|
|
@@ -29968,6 +30338,40 @@ var strategies = ({ strapi: strapi2 }) => {
|
|
|
29968
30338
|
},
|
|
29969
30339
|
getRoomName: function(user) {
|
|
29970
30340
|
return `${this.name}-user-${user.id}`;
|
|
30341
|
+
},
|
|
30342
|
+
/**
|
|
30343
|
+
* Admin users have full access - verify always passes
|
|
30344
|
+
* @param {object} auth - Auth object
|
|
30345
|
+
* @param {object} config - Config with scope
|
|
30346
|
+
*/
|
|
30347
|
+
verify: function(auth, config2) {
|
|
30348
|
+
return;
|
|
30349
|
+
},
|
|
30350
|
+
/**
|
|
30351
|
+
* Returns active admin sessions for broadcast
|
|
30352
|
+
* Admin users have full access, so we return them with full_access permissions
|
|
30353
|
+
* @returns {Promise<Array>} Array of admin session objects with permissions
|
|
30354
|
+
*/
|
|
30355
|
+
getRooms: async function() {
|
|
30356
|
+
try {
|
|
30357
|
+
const presenceController = strapi2.plugin("io").controller("presence");
|
|
30358
|
+
if (!presenceController?.getActiveSessions) {
|
|
30359
|
+
return [];
|
|
30360
|
+
}
|
|
30361
|
+
const activeSessions = presenceController.getActiveSessions();
|
|
30362
|
+
return activeSessions.map((session) => ({
|
|
30363
|
+
id: session.userId,
|
|
30364
|
+
name: `admin-${session.userId}`,
|
|
30365
|
+
type: "full-access",
|
|
30366
|
+
// Grants full access to all content types
|
|
30367
|
+
permissions: [],
|
|
30368
|
+
// Empty permissions array - full-access type bypasses permission check
|
|
30369
|
+
...session
|
|
30370
|
+
}));
|
|
30371
|
+
} catch (error2) {
|
|
30372
|
+
strapi2.log.warn("[plugin-io] Admin getRooms error:", error2.message);
|
|
30373
|
+
return [];
|
|
30374
|
+
}
|
|
29971
30375
|
}
|
|
29972
30376
|
};
|
|
29973
30377
|
const role = {
|
|
@@ -30206,12 +30610,12 @@ function transformEntry(entry, type2) {
|
|
|
30206
30610
|
// meta: {},
|
|
30207
30611
|
};
|
|
30208
30612
|
}
|
|
30209
|
-
const { pluginId: pluginId$
|
|
30613
|
+
const { pluginId: pluginId$4 } = pluginId_1;
|
|
30210
30614
|
var settings$1 = ({ strapi: strapi2 }) => {
|
|
30211
30615
|
const getPluginStore = () => {
|
|
30212
30616
|
return strapi2.store({
|
|
30213
30617
|
type: "plugin",
|
|
30214
|
-
name: pluginId$
|
|
30618
|
+
name: pluginId$4
|
|
30215
30619
|
});
|
|
30216
30620
|
};
|
|
30217
30621
|
const getDefaultSettings = () => ({
|
|
@@ -30351,6 +30755,19 @@ var settings$1 = ({ strapi: strapi2 }) => {
|
|
|
30351
30755
|
// Maximum nesting depth for diff
|
|
30352
30756
|
}
|
|
30353
30757
|
});
|
|
30758
|
+
const deepMerge = (target, source) => {
|
|
30759
|
+
const result = { ...target };
|
|
30760
|
+
for (const key of Object.keys(source)) {
|
|
30761
|
+
const targetVal = target[key];
|
|
30762
|
+
const sourceVal = source[key];
|
|
30763
|
+
if (targetVal && sourceVal && typeof targetVal === "object" && !Array.isArray(targetVal) && typeof sourceVal === "object" && !Array.isArray(sourceVal)) {
|
|
30764
|
+
result[key] = deepMerge(targetVal, sourceVal);
|
|
30765
|
+
} else {
|
|
30766
|
+
result[key] = sourceVal;
|
|
30767
|
+
}
|
|
30768
|
+
}
|
|
30769
|
+
return result;
|
|
30770
|
+
};
|
|
30354
30771
|
return {
|
|
30355
30772
|
/**
|
|
30356
30773
|
* Get current settings (merged with defaults)
|
|
@@ -30373,10 +30790,7 @@ var settings$1 = ({ strapi: strapi2 }) => {
|
|
|
30373
30790
|
async setSettings(newSettings) {
|
|
30374
30791
|
const pluginStore = getPluginStore();
|
|
30375
30792
|
const currentSettings = await this.getSettings();
|
|
30376
|
-
const updatedSettings =
|
|
30377
|
-
...currentSettings,
|
|
30378
|
-
...newSettings
|
|
30379
|
-
};
|
|
30793
|
+
const updatedSettings = deepMerge(currentSettings, newSettings);
|
|
30380
30794
|
await pluginStore.set({
|
|
30381
30795
|
key: "settings",
|
|
30382
30796
|
value: updatedSettings
|
|
@@ -30389,7 +30803,7 @@ var settings$1 = ({ strapi: strapi2 }) => {
|
|
|
30389
30803
|
getDefaultSettings
|
|
30390
30804
|
};
|
|
30391
30805
|
};
|
|
30392
|
-
const { pluginId: pluginId$
|
|
30806
|
+
const { pluginId: pluginId$3 } = pluginId_1;
|
|
30393
30807
|
var monitoring$1 = ({ strapi: strapi2 }) => {
|
|
30394
30808
|
let eventLog = [];
|
|
30395
30809
|
let eventStats = {
|
|
@@ -30495,8 +30909,10 @@ var monitoring$1 = ({ strapi: strapi2 }) => {
|
|
|
30495
30909
|
*/
|
|
30496
30910
|
getEventsPerSecond() {
|
|
30497
30911
|
const now = Date.now();
|
|
30498
|
-
const
|
|
30499
|
-
|
|
30912
|
+
const windowMs = 6e4;
|
|
30913
|
+
const recentEvents = eventLog.filter((e) => now - e.timestamp < windowMs);
|
|
30914
|
+
const elapsed = Math.min((now - eventStats.lastReset) / 1e3, windowMs / 1e3);
|
|
30915
|
+
return elapsed > 0 ? Number((recentEvents.length / elapsed).toFixed(2)) : 0;
|
|
30500
30916
|
},
|
|
30501
30917
|
/**
|
|
30502
30918
|
* Reset statistics
|
|
@@ -30517,13 +30933,14 @@ var monitoring$1 = ({ strapi: strapi2 }) => {
|
|
|
30517
30933
|
if (!io2) {
|
|
30518
30934
|
throw new Error("Socket.IO not initialized");
|
|
30519
30935
|
}
|
|
30936
|
+
const safeName = `test:${eventName.replace(/[^a-zA-Z0-9:._-]/g, "")}`;
|
|
30520
30937
|
const testData = {
|
|
30521
30938
|
...data,
|
|
30522
30939
|
timestamp: Date.now(),
|
|
30523
30940
|
test: true
|
|
30524
30941
|
};
|
|
30525
|
-
io2.emit(
|
|
30526
|
-
this.logEvent("test", { eventName, data: testData });
|
|
30942
|
+
io2.emit(safeName, testData);
|
|
30943
|
+
this.logEvent("test", { eventName: safeName, data: testData });
|
|
30527
30944
|
return {
|
|
30528
30945
|
success: true,
|
|
30529
30946
|
eventName,
|
|
@@ -30533,7 +30950,7 @@ var monitoring$1 = ({ strapi: strapi2 }) => {
|
|
|
30533
30950
|
}
|
|
30534
30951
|
};
|
|
30535
30952
|
};
|
|
30536
|
-
const { pluginId: pluginId$
|
|
30953
|
+
const { pluginId: pluginId$2 } = pluginId_1;
|
|
30537
30954
|
var presence$1 = ({ strapi: strapi2 }) => {
|
|
30538
30955
|
const activeConnections = /* @__PURE__ */ new Map();
|
|
30539
30956
|
const entityEditors = /* @__PURE__ */ new Map();
|
|
@@ -30935,7 +31352,7 @@ var presence$1 = ({ strapi: strapi2 }) => {
|
|
|
30935
31352
|
}
|
|
30936
31353
|
};
|
|
30937
31354
|
};
|
|
30938
|
-
const { pluginId } = pluginId_1;
|
|
31355
|
+
const { pluginId: pluginId$1 } = pluginId_1;
|
|
30939
31356
|
var preview$1 = ({ strapi: strapi2 }) => {
|
|
30940
31357
|
const previewSubscribers = /* @__PURE__ */ new Map();
|
|
30941
31358
|
const socketState = /* @__PURE__ */ new Map();
|
|
@@ -31197,22 +31614,23 @@ var diff$1 = ({ strapi: strapi2 }) => {
|
|
|
31197
31614
|
const isPlainObject2 = (value) => {
|
|
31198
31615
|
return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
|
|
31199
31616
|
};
|
|
31200
|
-
const isEqual2 = (a, b) => {
|
|
31617
|
+
const isEqual2 = (a, b, depth2 = 0) => {
|
|
31201
31618
|
if (a === b) return true;
|
|
31202
31619
|
if (a === null || b === null) return a === b;
|
|
31203
31620
|
if (typeof a !== typeof b) return false;
|
|
31621
|
+
if (depth2 > 30) return JSON.stringify(a) === JSON.stringify(b);
|
|
31204
31622
|
if (a instanceof Date && b instanceof Date) {
|
|
31205
31623
|
return a.getTime() === b.getTime();
|
|
31206
31624
|
}
|
|
31207
31625
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
31208
31626
|
if (a.length !== b.length) return false;
|
|
31209
|
-
return a.every((item, index2) => isEqual2(item, b[index2]));
|
|
31627
|
+
return a.every((item, index2) => isEqual2(item, b[index2], depth2 + 1));
|
|
31210
31628
|
}
|
|
31211
31629
|
if (isPlainObject2(a) && isPlainObject2(b)) {
|
|
31212
31630
|
const keysA = Object.keys(a);
|
|
31213
31631
|
const keysB = Object.keys(b);
|
|
31214
31632
|
if (keysA.length !== keysB.length) return false;
|
|
31215
|
-
return keysA.every((key) => isEqual2(a[key], b[key]));
|
|
31633
|
+
return keysA.every((key) => isEqual2(a[key], b[key], depth2 + 1));
|
|
31216
31634
|
}
|
|
31217
31635
|
return false;
|
|
31218
31636
|
};
|
|
@@ -31397,6 +31815,142 @@ var diff$1 = ({ strapi: strapi2 }) => {
|
|
|
31397
31815
|
}
|
|
31398
31816
|
};
|
|
31399
31817
|
};
|
|
31818
|
+
var security = ({ strapi: strapi2 }) => {
|
|
31819
|
+
const rateLimitStore = /* @__PURE__ */ new Map();
|
|
31820
|
+
const connectionLimitStore = /* @__PURE__ */ new Map();
|
|
31821
|
+
const cleanupInterval = setInterval(() => {
|
|
31822
|
+
const now = Date.now();
|
|
31823
|
+
const maxAge = 60 * 1e3;
|
|
31824
|
+
for (const [key, value] of rateLimitStore.entries()) {
|
|
31825
|
+
if (now - value.resetTime > maxAge) {
|
|
31826
|
+
rateLimitStore.delete(key);
|
|
31827
|
+
}
|
|
31828
|
+
}
|
|
31829
|
+
for (const [key, value] of connectionLimitStore.entries()) {
|
|
31830
|
+
if (now - value.lastSeen > maxAge) {
|
|
31831
|
+
connectionLimitStore.delete(key);
|
|
31832
|
+
}
|
|
31833
|
+
}
|
|
31834
|
+
}, 60 * 1e3);
|
|
31835
|
+
return {
|
|
31836
|
+
/**
|
|
31837
|
+
* Stops the background cleanup interval (called on plugin destroy)
|
|
31838
|
+
*/
|
|
31839
|
+
stopCleanupInterval() {
|
|
31840
|
+
clearInterval(cleanupInterval);
|
|
31841
|
+
},
|
|
31842
|
+
/**
|
|
31843
|
+
* Check if request should be rate limited
|
|
31844
|
+
* @param {string} identifier - Unique identifier (IP, user ID, etc.)
|
|
31845
|
+
* @param {Object} options - Rate limit options
|
|
31846
|
+
* @param {number} options.maxRequests - Maximum requests allowed
|
|
31847
|
+
* @param {number} options.windowMs - Time window in milliseconds
|
|
31848
|
+
* @returns {Object} - { allowed: boolean, remaining: number, resetTime: number }
|
|
31849
|
+
*/
|
|
31850
|
+
checkRateLimit(identifier, options = {}) {
|
|
31851
|
+
const { maxRequests = 100, windowMs = 60 * 1e3 } = options;
|
|
31852
|
+
const now = Date.now();
|
|
31853
|
+
const key = `ratelimit_${identifier}`;
|
|
31854
|
+
let record = rateLimitStore.get(key);
|
|
31855
|
+
if (!record || now - record.resetTime > windowMs) {
|
|
31856
|
+
record = {
|
|
31857
|
+
count: 1,
|
|
31858
|
+
resetTime: now,
|
|
31859
|
+
windowMs
|
|
31860
|
+
};
|
|
31861
|
+
rateLimitStore.set(key, record);
|
|
31862
|
+
return {
|
|
31863
|
+
allowed: true,
|
|
31864
|
+
remaining: maxRequests - 1,
|
|
31865
|
+
resetTime: now + windowMs
|
|
31866
|
+
};
|
|
31867
|
+
}
|
|
31868
|
+
if (record.count >= maxRequests) {
|
|
31869
|
+
return {
|
|
31870
|
+
allowed: false,
|
|
31871
|
+
remaining: 0,
|
|
31872
|
+
resetTime: record.resetTime + windowMs,
|
|
31873
|
+
retryAfter: record.resetTime + windowMs - now
|
|
31874
|
+
};
|
|
31875
|
+
}
|
|
31876
|
+
record.count++;
|
|
31877
|
+
rateLimitStore.set(key, record);
|
|
31878
|
+
return {
|
|
31879
|
+
allowed: true,
|
|
31880
|
+
remaining: maxRequests - record.count,
|
|
31881
|
+
resetTime: record.resetTime + windowMs
|
|
31882
|
+
};
|
|
31883
|
+
},
|
|
31884
|
+
/**
|
|
31885
|
+
* Check connection limits per IP/user
|
|
31886
|
+
* @param {string} identifier - Unique identifier
|
|
31887
|
+
* @param {number} maxConnections - Maximum allowed connections
|
|
31888
|
+
* @returns {boolean} - Whether connection is allowed
|
|
31889
|
+
*/
|
|
31890
|
+
checkConnectionLimit(identifier, maxConnections = 5) {
|
|
31891
|
+
const key = `connlimit_${identifier}`;
|
|
31892
|
+
const record = connectionLimitStore.get(key);
|
|
31893
|
+
const now = Date.now();
|
|
31894
|
+
if (!record) {
|
|
31895
|
+
connectionLimitStore.set(key, {
|
|
31896
|
+
count: 1,
|
|
31897
|
+
lastSeen: now
|
|
31898
|
+
});
|
|
31899
|
+
return true;
|
|
31900
|
+
}
|
|
31901
|
+
if (record.count >= maxConnections) {
|
|
31902
|
+
strapi2.log.warn(`[Socket.IO Security] Connection limit exceeded for ${identifier}`);
|
|
31903
|
+
return false;
|
|
31904
|
+
}
|
|
31905
|
+
record.count++;
|
|
31906
|
+
record.lastSeen = now;
|
|
31907
|
+
connectionLimitStore.set(key, record);
|
|
31908
|
+
return true;
|
|
31909
|
+
},
|
|
31910
|
+
/**
|
|
31911
|
+
* Release a connection slot
|
|
31912
|
+
* @param {string} identifier - Unique identifier
|
|
31913
|
+
*/
|
|
31914
|
+
releaseConnection(identifier) {
|
|
31915
|
+
const key = `connlimit_${identifier}`;
|
|
31916
|
+
const record = connectionLimitStore.get(key);
|
|
31917
|
+
if (record) {
|
|
31918
|
+
record.count = Math.max(0, record.count - 1);
|
|
31919
|
+
if (record.count === 0) {
|
|
31920
|
+
connectionLimitStore.delete(key);
|
|
31921
|
+
} else {
|
|
31922
|
+
connectionLimitStore.set(key, record);
|
|
31923
|
+
}
|
|
31924
|
+
}
|
|
31925
|
+
},
|
|
31926
|
+
/**
|
|
31927
|
+
* Validate event name to prevent injection
|
|
31928
|
+
* @param {string} eventName - Event name to validate
|
|
31929
|
+
* @returns {boolean} - Whether event name is valid
|
|
31930
|
+
*/
|
|
31931
|
+
validateEventName(eventName) {
|
|
31932
|
+
const validPattern = /^[a-zA-Z0-9:._-]+$/;
|
|
31933
|
+
return validPattern.test(eventName) && eventName.length < 100;
|
|
31934
|
+
},
|
|
31935
|
+
/**
|
|
31936
|
+
* Get current statistics
|
|
31937
|
+
* @returns {Object} - Statistics object
|
|
31938
|
+
*/
|
|
31939
|
+
getStats() {
|
|
31940
|
+
return {
|
|
31941
|
+
rateLimitEntries: rateLimitStore.size,
|
|
31942
|
+
connectionLimitEntries: connectionLimitStore.size
|
|
31943
|
+
};
|
|
31944
|
+
},
|
|
31945
|
+
/**
|
|
31946
|
+
* Clear all rate limit data
|
|
31947
|
+
*/
|
|
31948
|
+
clear() {
|
|
31949
|
+
rateLimitStore.clear();
|
|
31950
|
+
connectionLimitStore.clear();
|
|
31951
|
+
}
|
|
31952
|
+
};
|
|
31953
|
+
};
|
|
31400
31954
|
const strategy = strategies;
|
|
31401
31955
|
const sanitize = sanitize_1;
|
|
31402
31956
|
const transform = transform$1;
|
|
@@ -31413,20 +31967,58 @@ var services$1 = {
|
|
|
31413
31967
|
monitoring,
|
|
31414
31968
|
presence,
|
|
31415
31969
|
preview,
|
|
31416
|
-
diff
|
|
31970
|
+
diff,
|
|
31971
|
+
security
|
|
31417
31972
|
};
|
|
31418
31973
|
const bootstrap = bootstrap_1;
|
|
31419
31974
|
const config = config$1;
|
|
31420
31975
|
const controllers = controllers$1;
|
|
31421
31976
|
const routes = routes$1;
|
|
31422
31977
|
const services = services$1;
|
|
31423
|
-
const
|
|
31424
|
-
};
|
|
31978
|
+
const { pluginId } = pluginId_1;
|
|
31425
31979
|
const register = async () => {
|
|
31426
31980
|
};
|
|
31427
31981
|
const contentTypes = {};
|
|
31428
31982
|
const middlewares = {};
|
|
31429
31983
|
const policies = {};
|
|
31984
|
+
const destroy = async ({ strapi: strapi2 }) => {
|
|
31985
|
+
try {
|
|
31986
|
+
const presenceService = strapi2.plugin(pluginId)?.service("presence");
|
|
31987
|
+
if (presenceService?.stopCleanupInterval) {
|
|
31988
|
+
presenceService.stopCleanupInterval();
|
|
31989
|
+
}
|
|
31990
|
+
const presenceController = strapi2.plugin(pluginId)?.controller("presence");
|
|
31991
|
+
if (presenceController?.stopTokenCleanup) {
|
|
31992
|
+
presenceController.stopTokenCleanup();
|
|
31993
|
+
}
|
|
31994
|
+
const securityService = strapi2.plugin(pluginId)?.service("security");
|
|
31995
|
+
if (securityService?.stopCleanupInterval) {
|
|
31996
|
+
securityService.stopCleanupInterval();
|
|
31997
|
+
}
|
|
31998
|
+
const io2 = strapi2.$io?.server;
|
|
31999
|
+
if (io2) {
|
|
32000
|
+
io2.disconnectSockets(true);
|
|
32001
|
+
await new Promise((resolve) => {
|
|
32002
|
+
io2.close((err) => {
|
|
32003
|
+
if (err) {
|
|
32004
|
+
strapi2.log.warn(`socket.io: Error closing server: ${err.message}`);
|
|
32005
|
+
}
|
|
32006
|
+
resolve();
|
|
32007
|
+
});
|
|
32008
|
+
});
|
|
32009
|
+
}
|
|
32010
|
+
const redisClients = strapi2.$io?._redisClients;
|
|
32011
|
+
if (redisClients) {
|
|
32012
|
+
await Promise.allSettled([
|
|
32013
|
+
redisClients.pubClient?.quit?.(),
|
|
32014
|
+
redisClients.subClient?.quit?.()
|
|
32015
|
+
]);
|
|
32016
|
+
}
|
|
32017
|
+
strapi2.log.info("socket.io: Plugin destroyed – all handles released");
|
|
32018
|
+
} catch (err) {
|
|
32019
|
+
strapi2.log.error(`socket.io: Error during destroy: ${err.message}`);
|
|
32020
|
+
}
|
|
32021
|
+
};
|
|
31430
32022
|
var server = {
|
|
31431
32023
|
register,
|
|
31432
32024
|
bootstrap,
|