strapi-plugin-magic-sessionmanager 4.3.1 → 4.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.
@@ -319,6 +319,8 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
319
319
  userDocId2 = await getDocumentIdFromNumericId(strapi2, ctx.state.user.id);
320
320
  }
321
321
  if (userDocId2) {
322
+ const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
323
+ const strictMode = config2.strictSessionEnforcement === true;
322
324
  const activeSessions = await strapi2.documents(SESSION_UID$4).findMany({
323
325
  filters: {
324
326
  user: { documentId: userDocId2 },
@@ -327,8 +329,17 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
327
329
  limit: 1
328
330
  });
329
331
  if (!activeSessions || activeSessions.length === 0) {
330
- strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Request blocked - session terminated or invalid (user: ${userDocId2.substring(0, 8)}...)`);
331
- return ctx.unauthorized("All sessions have been terminated. Please login again.");
332
+ const allSessions = await strapi2.documents(SESSION_UID$4).findMany({
333
+ filters: { user: { documentId: userDocId2 } },
334
+ limit: 1,
335
+ fields: ["isActive"]
336
+ });
337
+ const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
338
+ if (strictMode && hasInactiveSessions) {
339
+ strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Session terminated (user: ${userDocId2.substring(0, 8)}...)`);
340
+ return ctx.unauthorized("Session has been terminated. Please login again.");
341
+ }
342
+ strapi2.log.debug(`[magic-sessionmanager] [WARN] No active session for user ${userDocId2.substring(0, 8)}... (allowing)`);
332
343
  }
333
344
  ctx.state.userDocumentId = userDocId2;
334
345
  }
@@ -516,9 +527,20 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
516
527
  }
517
528
  let userDocId = user.documentId;
518
529
  if (!userDocId && user.id) {
519
- const fullUser = await strapi2.entityService.findOne(USER_UID$2, user.id);
520
- userDocId = fullUser?.documentId || user.id;
530
+ const fullUser = await strapi2.entityService.findOne(USER_UID$2, user.id, {
531
+ fields: ["documentId"]
532
+ });
533
+ userDocId = fullUser?.documentId;
534
+ if (!userDocId) {
535
+ log.error(`[ERROR] Could not get documentId for user ${user.id} - session NOT created!`);
536
+ return;
537
+ }
521
538
  }
539
+ if (!userDocId) {
540
+ log.error("[ERROR] No user documentId available - cannot create session");
541
+ return;
542
+ }
543
+ log.debug(`[SESSION] Creating session for user documentId: ${userDocId}`);
522
544
  const newSession = await sessionService.createSession({
523
545
  userId: userDocId,
524
546
  ip,
@@ -530,7 +552,11 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
530
552
  geoData
531
553
  // Store geolocation data if available
532
554
  });
533
- log.info(`[SUCCESS] Session created for user ${userDocId} (IP: ${ip})`);
555
+ if (newSession?.documentId) {
556
+ log.info(`[SUCCESS] Session ${newSession.documentId} created for user ${userDocId} (IP: ${ip})`);
557
+ } else {
558
+ log.error(`[ERROR] Session creation returned no documentId for user ${userDocId}`);
559
+ }
534
560
  if (geoData && (config2.enableEmailAlerts || config2.enableWebhooks)) {
535
561
  try {
536
562
  const notificationService = strapi2.plugin("magic-sessionmanager").service("notifications");
@@ -760,6 +786,8 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
760
786
  if (!decoded || !decoded.id) {
761
787
  return decoded;
762
788
  }
789
+ const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
790
+ const strictMode = config2.strictSessionEnforcement === true;
763
791
  try {
764
792
  let userDocId = null;
765
793
  const user = await strapi2.entityService.findOne(
@@ -769,6 +797,7 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
769
797
  );
770
798
  userDocId = user?.documentId;
771
799
  if (!userDocId) {
800
+ strapi2.log.debug("[magic-sessionmanager] [JWT] No documentId found, allowing through");
772
801
  return decoded;
773
802
  }
774
803
  const activeSessions = await strapi2.documents(SESSION_UID$3).findMany({
@@ -778,15 +807,46 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
778
807
  },
779
808
  limit: 1
780
809
  });
781
- if (!activeSessions || activeSessions.length === 0) {
810
+ if (activeSessions && activeSessions.length > 0) {
811
+ return decoded;
812
+ }
813
+ const allSessions = await strapi2.documents(SESSION_UID$3).findMany({
814
+ filters: { user: { documentId: userDocId } },
815
+ limit: 5,
816
+ fields: ["isActive", "lastActive"]
817
+ });
818
+ const totalSessions = allSessions?.length || 0;
819
+ const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
820
+ if (!strictMode) {
821
+ if (totalSessions === 0) {
822
+ strapi2.log.warn(
823
+ `[magic-sessionmanager] [JWT-WARN] No session found for user ${userDocId.substring(0, 8)}... (allowing - session may not have been created)`
824
+ );
825
+ } else if (hasInactiveSessions) {
826
+ strapi2.log.warn(
827
+ `[magic-sessionmanager] [JWT-WARN] User ${userDocId.substring(0, 8)}... has ${totalSessions} inactive sessions but no active ones (allowing - strictMode off)`
828
+ );
829
+ }
830
+ return decoded;
831
+ }
832
+ if (totalSessions === 0) {
833
+ strapi2.log.warn(
834
+ `[magic-sessionmanager] [JWT-ALLOW] No sessions exist for user ${userDocId.substring(0, 8)}... (allowing - possible race condition)`
835
+ );
836
+ return decoded;
837
+ }
838
+ if (hasInactiveSessions) {
782
839
  strapi2.log.info(
783
- `[magic-sessionmanager] [JWT-BLOCKED] Valid JWT but no active session (user: ${userDocId.substring(0, 8)}...)`
840
+ `[magic-sessionmanager] [JWT-BLOCKED] User ${userDocId.substring(0, 8)}... was logged out (${totalSessions} inactive sessions)`
784
841
  );
785
842
  return null;
786
843
  }
844
+ strapi2.log.warn(
845
+ `[magic-sessionmanager] [JWT-ALLOW] Unexpected session state for user ${userDocId.substring(0, 8)}... (allowing)`
846
+ );
787
847
  return decoded;
788
848
  } catch (err) {
789
- strapi2.log.debug("[magic-sessionmanager] [AUTH] Session check error:", err.message);
849
+ strapi2.log.warn("[magic-sessionmanager] [JWT] Session check error (allowing):", err.message);
790
850
  return decoded;
791
851
  }
792
852
  };
@@ -2585,7 +2645,7 @@ var session$1 = ({ strapi: strapi2 }) => {
2585
2645
  }
2586
2646
  };
2587
2647
  };
2588
- const version$1 = "4.3.0";
2648
+ const version$1 = "4.3.2";
2589
2649
  const require$$2 = {
2590
2650
  version: version$1
2591
2651
  };
@@ -17213,6 +17273,16 @@ const providerFactory = (options2 = {}) => {
17213
17273
  }
17214
17274
  };
17215
17275
  };
17276
+ const parallelWithOrderedErrors = async (promises) => {
17277
+ const results = await Promise.allSettled(promises);
17278
+ for (let i2 = 0; i2 < results.length; i2 += 1) {
17279
+ const result = results[i2];
17280
+ if (result.status === "rejected") {
17281
+ throw result.reason;
17282
+ }
17283
+ }
17284
+ return results.map((r) => r.value);
17285
+ };
17216
17286
  const traverseEntity = async (visitor2, options2, entity) => {
17217
17287
  const { path: path2 = {
17218
17288
  raw: null,
@@ -17313,15 +17383,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
17313
17383
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
17314
17384
  const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
17315
17385
  if (fp.isArray(value)) {
17316
- const res = new Array(value.length);
17317
- for (let i3 = 0; i3 < value.length; i3 += 1) {
17386
+ copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
17318
17387
  const arrayPath = {
17319
17388
  ...newPath,
17320
17389
  rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
17321
17390
  };
17322
- res[i3] = await method(visitor2, arrayPath, value[i3]);
17323
- }
17324
- copy[key] = res;
17391
+ return method(visitor2, arrayPath, item);
17392
+ }));
17325
17393
  } else {
17326
17394
  copy[key] = await method(visitor2, newPath, value);
17327
17395
  }
@@ -17335,15 +17403,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
17335
17403
  path: newPath
17336
17404
  };
17337
17405
  if (fp.isArray(value)) {
17338
- const res = new Array(value.length);
17339
- for (let i3 = 0; i3 < value.length; i3 += 1) {
17406
+ copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
17340
17407
  const arrayPath = {
17341
17408
  ...newPath,
17342
17409
  rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
17343
17410
  };
17344
- res[i3] = await traverseMediaTarget(visitor2, arrayPath, value[i3]);
17345
- }
17346
- copy[key] = res;
17411
+ return traverseMediaTarget(visitor2, arrayPath, item);
17412
+ }));
17347
17413
  } else {
17348
17414
  copy[key] = await traverseMediaTarget(visitor2, newPath, value);
17349
17415
  }
@@ -17358,15 +17424,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
17358
17424
  };
17359
17425
  const targetSchema = getModel(attribute.component);
17360
17426
  if (fp.isArray(value)) {
17361
- const res = new Array(value.length);
17362
- for (let i3 = 0; i3 < value.length; i3 += 1) {
17427
+ copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
17363
17428
  const arrayPath = {
17364
17429
  ...newPath,
17365
17430
  rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
17366
17431
  };
17367
- res[i3] = await traverseComponent(visitor2, arrayPath, targetSchema, value[i3]);
17368
- }
17369
- copy[key] = res;
17432
+ return traverseComponent(visitor2, arrayPath, targetSchema, item);
17433
+ }));
17370
17434
  } else {
17371
17435
  copy[key] = await traverseComponent(visitor2, newPath, targetSchema, value);
17372
17436
  }
@@ -17379,15 +17443,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
17379
17443
  attribute,
17380
17444
  path: newPath
17381
17445
  };
17382
- const res = new Array(value.length);
17383
- for (let i3 = 0; i3 < value.length; i3 += 1) {
17446
+ copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
17384
17447
  const arrayPath = {
17385
17448
  ...newPath,
17386
17449
  rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
17387
17450
  };
17388
- res[i3] = await visitDynamicZoneEntry(visitor2, arrayPath, value[i3]);
17389
- }
17390
- copy[key] = res;
17451
+ return visitDynamicZoneEntry(visitor2, arrayPath, item);
17452
+ }));
17391
17453
  continue;
17392
17454
  }
17393
17455
  }
@@ -18133,6 +18195,23 @@ const generateInstallId = (projectId, installId) => {
18133
18195
  return require$$1__default.default.randomUUID();
18134
18196
  }
18135
18197
  };
18198
+ const createModelCache = (getModelFn) => {
18199
+ const cache = /* @__PURE__ */ new Map();
18200
+ return {
18201
+ getModel(uid) {
18202
+ const cached2 = cache.get(uid);
18203
+ if (cached2) {
18204
+ return cached2;
18205
+ }
18206
+ const model = getModelFn(uid);
18207
+ cache.set(uid, model);
18208
+ return model;
18209
+ },
18210
+ clear() {
18211
+ cache.clear();
18212
+ }
18213
+ };
18214
+ };
18136
18215
  var map$2;
18137
18216
  try {
18138
18217
  map$2 = Map;
@@ -38821,6 +38900,7 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
38821
38900
  augmentSchema,
38822
38901
  contentTypes: contentTypes$1,
38823
38902
  createContentApiRoutesFactory,
38903
+ createModelCache,
38824
38904
  dates,
38825
38905
  env,
38826
38906
  errors: errors$1,
@@ -38889,6 +38969,8 @@ var sessionRequired$1 = async (policyContext, config2, { strapi: strapi2 }) => {
38889
38969
  if (!userDocId) {
38890
38970
  return true;
38891
38971
  }
38972
+ const config3 = strapi2.config.get("plugin::magic-sessionmanager") || {};
38973
+ const strictMode = config3.strictSessionEnforcement === true;
38892
38974
  const activeSessions = await strapi2.documents(SESSION_UID).findMany({
38893
38975
  filters: {
38894
38976
  user: { documentId: userDocId },
@@ -38896,12 +38978,24 @@ var sessionRequired$1 = async (policyContext, config2, { strapi: strapi2 }) => {
38896
38978
  },
38897
38979
  limit: 1
38898
38980
  });
38899
- if (!activeSessions || activeSessions.length === 0) {
38981
+ if (activeSessions && activeSessions.length > 0) {
38982
+ return true;
38983
+ }
38984
+ const allSessions = await strapi2.documents(SESSION_UID).findMany({
38985
+ filters: { user: { documentId: userDocId } },
38986
+ limit: 1,
38987
+ fields: ["isActive"]
38988
+ });
38989
+ const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
38990
+ if (strictMode && hasInactiveSessions) {
38900
38991
  strapi2.log.info(
38901
- `[magic-sessionmanager] [POLICY-BLOCKED] JWT valid but no active session (user: ${userDocId.substring(0, 8)}...)`
38992
+ `[magic-sessionmanager] [POLICY-BLOCKED] Session terminated (user: ${userDocId.substring(0, 8)}...)`
38902
38993
  );
38903
38994
  throw new errors.UnauthorizedError("Session terminated. Please login again.");
38904
38995
  }
38996
+ strapi2.log.debug(
38997
+ `[magic-sessionmanager] [POLICY-WARN] No active session for user ${userDocId.substring(0, 8)}... (allowing)`
38998
+ );
38905
38999
  return true;
38906
39000
  } catch (err) {
38907
39001
  if (err instanceof errors.UnauthorizedError) {
@@ -306,6 +306,8 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
306
306
  userDocId2 = await getDocumentIdFromNumericId(strapi2, ctx.state.user.id);
307
307
  }
308
308
  if (userDocId2) {
309
+ const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
310
+ const strictMode = config2.strictSessionEnforcement === true;
309
311
  const activeSessions = await strapi2.documents(SESSION_UID$4).findMany({
310
312
  filters: {
311
313
  user: { documentId: userDocId2 },
@@ -314,8 +316,17 @@ var lastSeen = ({ strapi: strapi2, sessionService }) => {
314
316
  limit: 1
315
317
  });
316
318
  if (!activeSessions || activeSessions.length === 0) {
317
- strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Request blocked - session terminated or invalid (user: ${userDocId2.substring(0, 8)}...)`);
318
- return ctx.unauthorized("All sessions have been terminated. Please login again.");
319
+ const allSessions = await strapi2.documents(SESSION_UID$4).findMany({
320
+ filters: { user: { documentId: userDocId2 } },
321
+ limit: 1,
322
+ fields: ["isActive"]
323
+ });
324
+ const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
325
+ if (strictMode && hasInactiveSessions) {
326
+ strapi2.log.info(`[magic-sessionmanager] [BLOCKED] Session terminated (user: ${userDocId2.substring(0, 8)}...)`);
327
+ return ctx.unauthorized("Session has been terminated. Please login again.");
328
+ }
329
+ strapi2.log.debug(`[magic-sessionmanager] [WARN] No active session for user ${userDocId2.substring(0, 8)}... (allowing)`);
319
330
  }
320
331
  ctx.state.userDocumentId = userDocId2;
321
332
  }
@@ -503,9 +514,20 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
503
514
  }
504
515
  let userDocId = user.documentId;
505
516
  if (!userDocId && user.id) {
506
- const fullUser = await strapi2.entityService.findOne(USER_UID$2, user.id);
507
- userDocId = fullUser?.documentId || user.id;
517
+ const fullUser = await strapi2.entityService.findOne(USER_UID$2, user.id, {
518
+ fields: ["documentId"]
519
+ });
520
+ userDocId = fullUser?.documentId;
521
+ if (!userDocId) {
522
+ log.error(`[ERROR] Could not get documentId for user ${user.id} - session NOT created!`);
523
+ return;
524
+ }
508
525
  }
526
+ if (!userDocId) {
527
+ log.error("[ERROR] No user documentId available - cannot create session");
528
+ return;
529
+ }
530
+ log.debug(`[SESSION] Creating session for user documentId: ${userDocId}`);
509
531
  const newSession = await sessionService.createSession({
510
532
  userId: userDocId,
511
533
  ip,
@@ -517,7 +539,11 @@ var bootstrap$1 = async ({ strapi: strapi2 }) => {
517
539
  geoData
518
540
  // Store geolocation data if available
519
541
  });
520
- log.info(`[SUCCESS] Session created for user ${userDocId} (IP: ${ip})`);
542
+ if (newSession?.documentId) {
543
+ log.info(`[SUCCESS] Session ${newSession.documentId} created for user ${userDocId} (IP: ${ip})`);
544
+ } else {
545
+ log.error(`[ERROR] Session creation returned no documentId for user ${userDocId}`);
546
+ }
521
547
  if (geoData && (config2.enableEmailAlerts || config2.enableWebhooks)) {
522
548
  try {
523
549
  const notificationService = strapi2.plugin("magic-sessionmanager").service("notifications");
@@ -747,6 +773,8 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
747
773
  if (!decoded || !decoded.id) {
748
774
  return decoded;
749
775
  }
776
+ const config2 = strapi2.config.get("plugin::magic-sessionmanager") || {};
777
+ const strictMode = config2.strictSessionEnforcement === true;
750
778
  try {
751
779
  let userDocId = null;
752
780
  const user = await strapi2.entityService.findOne(
@@ -756,6 +784,7 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
756
784
  );
757
785
  userDocId = user?.documentId;
758
786
  if (!userDocId) {
787
+ strapi2.log.debug("[magic-sessionmanager] [JWT] No documentId found, allowing through");
759
788
  return decoded;
760
789
  }
761
790
  const activeSessions = await strapi2.documents(SESSION_UID$3).findMany({
@@ -765,15 +794,46 @@ async function registerSessionAwareAuthStrategy(strapi2, log) {
765
794
  },
766
795
  limit: 1
767
796
  });
768
- if (!activeSessions || activeSessions.length === 0) {
797
+ if (activeSessions && activeSessions.length > 0) {
798
+ return decoded;
799
+ }
800
+ const allSessions = await strapi2.documents(SESSION_UID$3).findMany({
801
+ filters: { user: { documentId: userDocId } },
802
+ limit: 5,
803
+ fields: ["isActive", "lastActive"]
804
+ });
805
+ const totalSessions = allSessions?.length || 0;
806
+ const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
807
+ if (!strictMode) {
808
+ if (totalSessions === 0) {
809
+ strapi2.log.warn(
810
+ `[magic-sessionmanager] [JWT-WARN] No session found for user ${userDocId.substring(0, 8)}... (allowing - session may not have been created)`
811
+ );
812
+ } else if (hasInactiveSessions) {
813
+ strapi2.log.warn(
814
+ `[magic-sessionmanager] [JWT-WARN] User ${userDocId.substring(0, 8)}... has ${totalSessions} inactive sessions but no active ones (allowing - strictMode off)`
815
+ );
816
+ }
817
+ return decoded;
818
+ }
819
+ if (totalSessions === 0) {
820
+ strapi2.log.warn(
821
+ `[magic-sessionmanager] [JWT-ALLOW] No sessions exist for user ${userDocId.substring(0, 8)}... (allowing - possible race condition)`
822
+ );
823
+ return decoded;
824
+ }
825
+ if (hasInactiveSessions) {
769
826
  strapi2.log.info(
770
- `[magic-sessionmanager] [JWT-BLOCKED] Valid JWT but no active session (user: ${userDocId.substring(0, 8)}...)`
827
+ `[magic-sessionmanager] [JWT-BLOCKED] User ${userDocId.substring(0, 8)}... was logged out (${totalSessions} inactive sessions)`
771
828
  );
772
829
  return null;
773
830
  }
831
+ strapi2.log.warn(
832
+ `[magic-sessionmanager] [JWT-ALLOW] Unexpected session state for user ${userDocId.substring(0, 8)}... (allowing)`
833
+ );
774
834
  return decoded;
775
835
  } catch (err) {
776
- strapi2.log.debug("[magic-sessionmanager] [AUTH] Session check error:", err.message);
836
+ strapi2.log.warn("[magic-sessionmanager] [JWT] Session check error (allowing):", err.message);
777
837
  return decoded;
778
838
  }
779
839
  };
@@ -2572,7 +2632,7 @@ var session$1 = ({ strapi: strapi2 }) => {
2572
2632
  }
2573
2633
  };
2574
2634
  };
2575
- const version$1 = "4.3.0";
2635
+ const version$1 = "4.3.2";
2576
2636
  const require$$2 = {
2577
2637
  version: version$1
2578
2638
  };
@@ -17200,6 +17260,16 @@ const providerFactory = (options2 = {}) => {
17200
17260
  }
17201
17261
  };
17202
17262
  };
17263
+ const parallelWithOrderedErrors = async (promises) => {
17264
+ const results = await Promise.allSettled(promises);
17265
+ for (let i2 = 0; i2 < results.length; i2 += 1) {
17266
+ const result = results[i2];
17267
+ if (result.status === "rejected") {
17268
+ throw result.reason;
17269
+ }
17270
+ }
17271
+ return results.map((r) => r.value);
17272
+ };
17203
17273
  const traverseEntity = async (visitor2, options2, entity) => {
17204
17274
  const { path: path2 = {
17205
17275
  raw: null,
@@ -17300,15 +17370,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
17300
17370
  const isMorphRelation = attribute.relation.toLowerCase().startsWith("morph");
17301
17371
  const method = isMorphRelation ? traverseMorphRelationTarget : traverseRelationTarget(getModel(attribute.target));
17302
17372
  if (fp.isArray(value)) {
17303
- const res = new Array(value.length);
17304
- for (let i3 = 0; i3 < value.length; i3 += 1) {
17373
+ copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
17305
17374
  const arrayPath = {
17306
17375
  ...newPath,
17307
17376
  rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
17308
17377
  };
17309
- res[i3] = await method(visitor2, arrayPath, value[i3]);
17310
- }
17311
- copy[key] = res;
17378
+ return method(visitor2, arrayPath, item);
17379
+ }));
17312
17380
  } else {
17313
17381
  copy[key] = await method(visitor2, newPath, value);
17314
17382
  }
@@ -17322,15 +17390,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
17322
17390
  path: newPath
17323
17391
  };
17324
17392
  if (fp.isArray(value)) {
17325
- const res = new Array(value.length);
17326
- for (let i3 = 0; i3 < value.length; i3 += 1) {
17393
+ copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
17327
17394
  const arrayPath = {
17328
17395
  ...newPath,
17329
17396
  rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
17330
17397
  };
17331
- res[i3] = await traverseMediaTarget(visitor2, arrayPath, value[i3]);
17332
- }
17333
- copy[key] = res;
17398
+ return traverseMediaTarget(visitor2, arrayPath, item);
17399
+ }));
17334
17400
  } else {
17335
17401
  copy[key] = await traverseMediaTarget(visitor2, newPath, value);
17336
17402
  }
@@ -17345,15 +17411,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
17345
17411
  };
17346
17412
  const targetSchema = getModel(attribute.component);
17347
17413
  if (fp.isArray(value)) {
17348
- const res = new Array(value.length);
17349
- for (let i3 = 0; i3 < value.length; i3 += 1) {
17414
+ copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
17350
17415
  const arrayPath = {
17351
17416
  ...newPath,
17352
17417
  rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
17353
17418
  };
17354
- res[i3] = await traverseComponent(visitor2, arrayPath, targetSchema, value[i3]);
17355
- }
17356
- copy[key] = res;
17419
+ return traverseComponent(visitor2, arrayPath, targetSchema, item);
17420
+ }));
17357
17421
  } else {
17358
17422
  copy[key] = await traverseComponent(visitor2, newPath, targetSchema, value);
17359
17423
  }
@@ -17366,15 +17430,13 @@ const traverseEntity = async (visitor2, options2, entity) => {
17366
17430
  attribute,
17367
17431
  path: newPath
17368
17432
  };
17369
- const res = new Array(value.length);
17370
- for (let i3 = 0; i3 < value.length; i3 += 1) {
17433
+ copy[key] = await parallelWithOrderedErrors(value.map((item, i3) => {
17371
17434
  const arrayPath = {
17372
17435
  ...newPath,
17373
17436
  rawWithIndices: fp.isNil(newPath.rawWithIndices) ? `${i3}` : `${newPath.rawWithIndices}.${i3}`
17374
17437
  };
17375
- res[i3] = await visitDynamicZoneEntry(visitor2, arrayPath, value[i3]);
17376
- }
17377
- copy[key] = res;
17438
+ return visitDynamicZoneEntry(visitor2, arrayPath, item);
17439
+ }));
17378
17440
  continue;
17379
17441
  }
17380
17442
  }
@@ -18120,6 +18182,23 @@ const generateInstallId = (projectId, installId) => {
18120
18182
  return require$$1.randomUUID();
18121
18183
  }
18122
18184
  };
18185
+ const createModelCache = (getModelFn) => {
18186
+ const cache = /* @__PURE__ */ new Map();
18187
+ return {
18188
+ getModel(uid) {
18189
+ const cached2 = cache.get(uid);
18190
+ if (cached2) {
18191
+ return cached2;
18192
+ }
18193
+ const model = getModelFn(uid);
18194
+ cache.set(uid, model);
18195
+ return model;
18196
+ },
18197
+ clear() {
18198
+ cache.clear();
18199
+ }
18200
+ };
18201
+ };
18123
18202
  var map$2;
18124
18203
  try {
18125
18204
  map$2 = Map;
@@ -38808,6 +38887,7 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
38808
38887
  augmentSchema,
38809
38888
  contentTypes: contentTypes$1,
38810
38889
  createContentApiRoutesFactory,
38890
+ createModelCache,
38811
38891
  dates,
38812
38892
  env,
38813
38893
  errors: errors$1,
@@ -38876,6 +38956,8 @@ var sessionRequired$1 = async (policyContext, config2, { strapi: strapi2 }) => {
38876
38956
  if (!userDocId) {
38877
38957
  return true;
38878
38958
  }
38959
+ const config3 = strapi2.config.get("plugin::magic-sessionmanager") || {};
38960
+ const strictMode = config3.strictSessionEnforcement === true;
38879
38961
  const activeSessions = await strapi2.documents(SESSION_UID).findMany({
38880
38962
  filters: {
38881
38963
  user: { documentId: userDocId },
@@ -38883,12 +38965,24 @@ var sessionRequired$1 = async (policyContext, config2, { strapi: strapi2 }) => {
38883
38965
  },
38884
38966
  limit: 1
38885
38967
  });
38886
- if (!activeSessions || activeSessions.length === 0) {
38968
+ if (activeSessions && activeSessions.length > 0) {
38969
+ return true;
38970
+ }
38971
+ const allSessions = await strapi2.documents(SESSION_UID).findMany({
38972
+ filters: { user: { documentId: userDocId } },
38973
+ limit: 1,
38974
+ fields: ["isActive"]
38975
+ });
38976
+ const hasInactiveSessions = allSessions?.some((s3) => s3.isActive === false);
38977
+ if (strictMode && hasInactiveSessions) {
38887
38978
  strapi2.log.info(
38888
- `[magic-sessionmanager] [POLICY-BLOCKED] JWT valid but no active session (user: ${userDocId.substring(0, 8)}...)`
38979
+ `[magic-sessionmanager] [POLICY-BLOCKED] Session terminated (user: ${userDocId.substring(0, 8)}...)`
38889
38980
  );
38890
38981
  throw new errors.UnauthorizedError("Session terminated. Please login again.");
38891
38982
  }
38983
+ strapi2.log.debug(
38984
+ `[magic-sessionmanager] [POLICY-WARN] No active session for user ${userDocId.substring(0, 8)}... (allowing)`
38985
+ );
38892
38986
  return true;
38893
38987
  } catch (err) {
38894
38988
  if (err instanceof errors.UnauthorizedError) {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.3.1",
2
+ "version": "4.3.3",
3
3
  "keywords": [
4
4
  "strapi",
5
5
  "strapi-plugin",