strapi-plugin-magic-mark 3.0.0 → 3.0.2

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.
Files changed (51) hide show
  1. package/README.md +1 -1
  2. package/dist/_chunks/{App-C5UU0yUr.js → App-B6x0aSMN.js} +97 -55
  3. package/dist/_chunks/{App-Dt-v39BQ.mjs → App-BCliVBSB.mjs} +98 -56
  4. package/dist/_chunks/UpgradePage-Bm0SkuCi.js +353 -0
  5. package/dist/_chunks/UpgradePage-GoocQ4av.mjs +351 -0
  6. package/dist/_chunks/de-Cs9dd3Mr.js +138 -0
  7. package/dist/_chunks/de-DOVki5VS.mjs +138 -0
  8. package/dist/_chunks/en-CE3r46Y2.js +138 -0
  9. package/dist/_chunks/en-Cf5-O03L.mjs +138 -0
  10. package/dist/_chunks/es-Ba6JcPIm.mjs +138 -0
  11. package/dist/_chunks/es-D4AOyJYJ.js +138 -0
  12. package/dist/_chunks/fr-CWSfoA8i.js +138 -0
  13. package/dist/_chunks/fr-CrMBXR3c.mjs +138 -0
  14. package/dist/_chunks/{index-B-Cc7QNW.mjs → index-B_EiWnCU.mjs} +13 -4
  15. package/dist/_chunks/index-D5-84IjV.js +3365 -0
  16. package/dist/_chunks/{index-B11QBtag.js → index-DA7Jswi4.js} +12 -3
  17. package/dist/_chunks/index-DdTUt6EH.mjs +3361 -0
  18. package/dist/_chunks/pt-BXxZ1Zym.mjs +138 -0
  19. package/dist/_chunks/pt-DW_6r_mP.js +138 -0
  20. package/dist/admin/index.js +1 -1
  21. package/dist/admin/index.mjs +1 -1
  22. package/dist/admin/src/components/QueryBuilder.d.ts +12 -1
  23. package/dist/admin/src/components/RelationFieldSelector.d.ts +24 -0
  24. package/dist/admin/src/components/SimpleAdvancedFilterModal.d.ts +2 -0
  25. package/dist/admin/src/components/UpgradePrompt.d.ts +22 -0
  26. package/dist/admin/src/hooks/useFeatureGate.d.ts +88 -0
  27. package/dist/admin/src/hooks/useRelationSchema.d.ts +27 -0
  28. package/dist/admin/src/pages/UpgradePage.d.ts +6 -0
  29. package/dist/admin/src/utils/queryGenerator.d.ts +4 -0
  30. package/dist/admin/src/utils/queryToStructure.d.ts +8 -1
  31. package/dist/admin/src/utils/theme.d.ts +95 -0
  32. package/dist/server/index.js +212 -9
  33. package/dist/server/index.mjs +212 -9
  34. package/dist/server/src/controllers/index.d.ts +1 -0
  35. package/dist/server/src/controllers/license.d.ts +4 -0
  36. package/dist/server/src/index.d.ts +24 -1
  37. package/dist/server/src/services/index.d.ts +23 -1
  38. package/dist/server/src/services/license-guard.d.ts +48 -2
  39. package/package.json +1 -1
  40. package/dist/_chunks/de-Bag-366k.mjs +0 -49
  41. package/dist/_chunks/de-Dic_hhjg.js +0 -49
  42. package/dist/_chunks/en-C5BvHqNo.js +0 -54
  43. package/dist/_chunks/en-zokEerzt.mjs +0 -54
  44. package/dist/_chunks/es-BlSQpU1z.js +0 -54
  45. package/dist/_chunks/es-Br1ucP3h.mjs +0 -54
  46. package/dist/_chunks/fr-BHciYPYG.js +0 -54
  47. package/dist/_chunks/fr-Dzo3kt_q.mjs +0 -54
  48. package/dist/_chunks/index-BAmZV8aX.mjs +0 -2020
  49. package/dist/_chunks/index-RuDV4dTy.js +0 -2024
  50. package/dist/_chunks/pt-DQoGyzyD.mjs +0 -54
  51. package/dist/_chunks/pt-Dawo5aUA.js +0 -54
@@ -228,6 +228,17 @@ const bookmarkController = ({ strapi }) => ({
228
228
  return ctx.throw(400, "Path is required");
229
229
  }
230
230
  const userId = user.documentId || String(user.id);
231
+ const licenseGuard = strapi.plugin("magic-mark").service("license-guard");
232
+ const limitCheck = await licenseGuard.canCreateBookmark(userId);
233
+ if (!limitCheck.canCreate) {
234
+ return ctx.throw(403, {
235
+ error: "BOOKMARK_LIMIT_REACHED",
236
+ message: limitCheck.message || `Bookmark limit reached (${limitCheck.current}/${limitCheck.max}). Upgrade to Premium or Advanced to create more bookmarks.`,
237
+ current: limitCheck.current,
238
+ max: limitCheck.max,
239
+ upgradeUrl: "/admin/settings/magic-mark/upgrade"
240
+ });
241
+ }
231
242
  const service = strapi.plugin("magic-mark").service("bookmarks");
232
243
  const bookmark = await service.create(name, path2, query, emoji, description, userId, sharedWithRoles, sharedWithUsers, isPublic);
233
244
  ctx.body = {
@@ -620,6 +631,27 @@ const license = ({ strapi }) => ({
620
631
  strapi.log.error("Error storing license key:", error);
621
632
  return ctx.badRequest("Error validating license key");
622
633
  }
634
+ },
635
+ /**
636
+ * Get license limits and feature flags for current user
637
+ */
638
+ async getLimits(ctx) {
639
+ try {
640
+ const user = ctx.state.user;
641
+ if (!user) {
642
+ return ctx.unauthorized("User not authenticated");
643
+ }
644
+ const userId = user.documentId || String(user.id);
645
+ const licenseGuard = strapi.plugin("magic-mark").service("license-guard");
646
+ const limits = await licenseGuard.getLicenseLimits(userId);
647
+ return ctx.send({
648
+ success: true,
649
+ data: limits
650
+ });
651
+ } catch (error) {
652
+ strapi.log.error("Error getting license limits:", error);
653
+ return ctx.badRequest("Error getting license limits");
654
+ }
623
655
  }
624
656
  });
625
657
  const controllers = {
@@ -741,6 +773,14 @@ const admin = {
741
773
  config: {
742
774
  policies: []
743
775
  }
776
+ },
777
+ {
778
+ method: "GET",
779
+ path: "/license/limits",
780
+ handler: "license.getLimits",
781
+ config: {
782
+ policies: []
783
+ }
744
784
  }
745
785
  ]
746
786
  };
@@ -1239,19 +1279,23 @@ const licenseGuardService = ({ strapi }) => ({
1239
1279
  }
1240
1280
  },
1241
1281
  /**
1242
- * Get online statistics
1282
+ * Get current license data from store (fetches fresh from server)
1283
+ * This is the correct way to get license data with all feature flags
1243
1284
  */
1244
- async getOnlineStats() {
1285
+ async getCurrentLicense() {
1245
1286
  try {
1246
- const licenseServerUrl = this.getLicenseServerUrl();
1247
- const response = await fetch(`${licenseServerUrl}/api/licenses/stats/online`);
1248
- const data = await response.json();
1249
- if (data.success) {
1250
- return data.data;
1287
+ const pluginStore = strapi.store({
1288
+ type: "plugin",
1289
+ name: "magic-mark"
1290
+ });
1291
+ const licenseKey = await pluginStore.get({ key: "licenseKey" });
1292
+ if (!licenseKey) {
1293
+ return null;
1251
1294
  }
1252
- return null;
1295
+ const license2 = await this.getLicenseByKey(licenseKey);
1296
+ return license2;
1253
1297
  } catch (error) {
1254
- strapi.log.error("[ERROR] Error fetching online stats:", error);
1298
+ strapi.log.error("[LICENSE] Error loading current license:", error);
1255
1299
  return null;
1256
1300
  }
1257
1301
  },
@@ -1360,6 +1404,165 @@ const licenseGuardService = ({ strapi }) => ({
1360
1404
  return false;
1361
1405
  }
1362
1406
  },
1407
+ /**
1408
+ * Get bookmark limit based on license tier
1409
+ * @returns Bookmark limit: 10 (free), 50 (premium), -1 (advanced/unlimited)
1410
+ */
1411
+ async getBookmarkLimit() {
1412
+ try {
1413
+ const licenseGuard = strapi.licenseGuard;
1414
+ const licenseData = licenseGuard?.data;
1415
+ if (licenseData?.featureAdvanced) {
1416
+ return -1;
1417
+ }
1418
+ if (licenseData?.featurePremium) {
1419
+ return 50;
1420
+ }
1421
+ return 10;
1422
+ } catch (error) {
1423
+ strapi.log.debug("[LICENSE] Error getting bookmark limit, using free tier");
1424
+ return 10;
1425
+ }
1426
+ },
1427
+ /**
1428
+ * Check if user can create more bookmarks
1429
+ * @param userId - User's documentId
1430
+ * @returns Object with canCreate boolean and current/max counts
1431
+ */
1432
+ async canCreateBookmark(userId) {
1433
+ try {
1434
+ const limit = await this.getBookmarkLimit();
1435
+ if (limit === -1) {
1436
+ return { canCreate: true, current: 0, max: -1 };
1437
+ }
1438
+ const BOOKMARK_UID2 = "plugin::magic-mark.bookmark";
1439
+ const bookmarks = await strapi.documents(BOOKMARK_UID2).findMany({
1440
+ filters: { creatorId: userId }
1441
+ });
1442
+ const currentCount = bookmarks?.length || 0;
1443
+ if (currentCount >= limit) {
1444
+ return {
1445
+ canCreate: false,
1446
+ current: currentCount,
1447
+ max: limit,
1448
+ message: `Bookmark limit reached (${currentCount}/${limit}). Upgrade to create more bookmarks.`
1449
+ };
1450
+ }
1451
+ return { canCreate: true, current: currentCount, max: limit };
1452
+ } catch (error) {
1453
+ strapi.log.error("[LICENSE] Error checking bookmark limit:", error);
1454
+ return { canCreate: true, current: 0, max: 10 };
1455
+ }
1456
+ },
1457
+ /**
1458
+ * Get current license limits and feature flags
1459
+ * @param userId - User's documentId for bookmark count
1460
+ * @returns License limits object
1461
+ */
1462
+ async getLicenseLimits(userId) {
1463
+ try {
1464
+ const license2 = await this.getCurrentLicense();
1465
+ strapi.log.info("[LICENSE] getLicenseLimits - license exists:", !!license2);
1466
+ if (license2) {
1467
+ strapi.log.info("[LICENSE] getLicenseLimits - featurePremium:", license2.featurePremium);
1468
+ strapi.log.info("[LICENSE] getLicenseLimits - featureAdvanced:", license2.featureAdvanced);
1469
+ }
1470
+ let tier = "free";
1471
+ if (license2?.featureEnterprise === true) tier = "enterprise";
1472
+ else if (license2?.featureAdvanced === true) tier = "advanced";
1473
+ else if (license2?.featurePremium === true) tier = "premium";
1474
+ const isPremium = tier === "premium" || tier === "advanced" || tier === "enterprise";
1475
+ const isAdvanced = tier === "advanced" || tier === "enterprise";
1476
+ strapi.log.info("[LICENSE] getLicenseLimits - detected tier:", tier);
1477
+ const bookmarkCheck = await this.canCreateBookmark(userId);
1478
+ return {
1479
+ maxBookmarks: bookmarkCheck.max,
1480
+ currentBookmarks: bookmarkCheck.current,
1481
+ canCreate: bookmarkCheck.canCreate,
1482
+ tier,
1483
+ features: {
1484
+ queryHistory: isPremium || isAdvanced,
1485
+ export: isPremium || isAdvanced,
1486
+ analytics: isAdvanced,
1487
+ bulkOperations: isAdvanced,
1488
+ customIntegrations: isAdvanced
1489
+ }
1490
+ };
1491
+ } catch (error) {
1492
+ strapi.log.error("[LICENSE] Error getting license limits:", error);
1493
+ return {
1494
+ maxBookmarks: 10,
1495
+ currentBookmarks: 0,
1496
+ canCreate: true,
1497
+ tier: "free",
1498
+ features: {
1499
+ queryHistory: false,
1500
+ export: false,
1501
+ analytics: false,
1502
+ bulkOperations: false,
1503
+ customIntegrations: false
1504
+ }
1505
+ };
1506
+ }
1507
+ },
1508
+ /**
1509
+ * Check if a specific feature is available based on license
1510
+ * @param feature - Feature key to check
1511
+ * @returns Boolean indicating if feature is available
1512
+ */
1513
+ hasFeature(feature) {
1514
+ try {
1515
+ const licenseGuard = strapi.licenseGuard;
1516
+ const licenseData = licenseGuard?.data;
1517
+ const isPremium = licenseData?.featurePremium || false;
1518
+ const isAdvanced = licenseData?.featureAdvanced || false;
1519
+ const featureRequirements = {
1520
+ // Free tier
1521
+ basicBookmarks: "free",
1522
+ basicFilters: "free",
1523
+ // Premium tier
1524
+ extendedBookmarks: "premium",
1525
+ queryHistory: "premium",
1526
+ exportBookmarks: "premium",
1527
+ sharedBookmarks: "premium",
1528
+ // Advanced tier
1529
+ unlimitedBookmarks: "advanced",
1530
+ advancedFilters: "advanced",
1531
+ subGroups: "advanced",
1532
+ bulkOperations: "advanced",
1533
+ analytics: "advanced",
1534
+ customIntegrations: "advanced"
1535
+ };
1536
+ const requiredTier = featureRequirements[feature] || "free";
1537
+ let currentTierLevel = 0;
1538
+ if (isAdvanced) currentTierLevel = 2;
1539
+ else if (isPremium) currentTierLevel = 1;
1540
+ const tierLevels = {
1541
+ free: 0,
1542
+ premium: 1,
1543
+ advanced: 2
1544
+ };
1545
+ return currentTierLevel >= tierLevels[requiredTier];
1546
+ } catch (error) {
1547
+ strapi.log.debug("[LICENSE] Error checking feature:", feature);
1548
+ return false;
1549
+ }
1550
+ },
1551
+ /**
1552
+ * Get current tier name
1553
+ * @returns 'free' | 'premium' | 'advanced'
1554
+ */
1555
+ getCurrentTier() {
1556
+ try {
1557
+ const licenseGuard = strapi.licenseGuard;
1558
+ const licenseData = licenseGuard?.data;
1559
+ if (licenseData?.featureAdvanced) return "advanced";
1560
+ if (licenseData?.featurePremium) return "premium";
1561
+ return "free";
1562
+ } catch (error) {
1563
+ return "free";
1564
+ }
1565
+ },
1363
1566
  /**
1364
1567
  * Cleanup on plugin destroy
1365
1568
  */
@@ -224,6 +224,17 @@ const bookmarkController = ({ strapi }) => ({
224
224
  return ctx.throw(400, "Path is required");
225
225
  }
226
226
  const userId = user.documentId || String(user.id);
227
+ const licenseGuard = strapi.plugin("magic-mark").service("license-guard");
228
+ const limitCheck = await licenseGuard.canCreateBookmark(userId);
229
+ if (!limitCheck.canCreate) {
230
+ return ctx.throw(403, {
231
+ error: "BOOKMARK_LIMIT_REACHED",
232
+ message: limitCheck.message || `Bookmark limit reached (${limitCheck.current}/${limitCheck.max}). Upgrade to Premium or Advanced to create more bookmarks.`,
233
+ current: limitCheck.current,
234
+ max: limitCheck.max,
235
+ upgradeUrl: "/admin/settings/magic-mark/upgrade"
236
+ });
237
+ }
227
238
  const service = strapi.plugin("magic-mark").service("bookmarks");
228
239
  const bookmark = await service.create(name, path, query, emoji, description, userId, sharedWithRoles, sharedWithUsers, isPublic);
229
240
  ctx.body = {
@@ -616,6 +627,27 @@ const license = ({ strapi }) => ({
616
627
  strapi.log.error("Error storing license key:", error);
617
628
  return ctx.badRequest("Error validating license key");
618
629
  }
630
+ },
631
+ /**
632
+ * Get license limits and feature flags for current user
633
+ */
634
+ async getLimits(ctx) {
635
+ try {
636
+ const user = ctx.state.user;
637
+ if (!user) {
638
+ return ctx.unauthorized("User not authenticated");
639
+ }
640
+ const userId = user.documentId || String(user.id);
641
+ const licenseGuard = strapi.plugin("magic-mark").service("license-guard");
642
+ const limits = await licenseGuard.getLicenseLimits(userId);
643
+ return ctx.send({
644
+ success: true,
645
+ data: limits
646
+ });
647
+ } catch (error) {
648
+ strapi.log.error("Error getting license limits:", error);
649
+ return ctx.badRequest("Error getting license limits");
650
+ }
619
651
  }
620
652
  });
621
653
  const controllers = {
@@ -737,6 +769,14 @@ const admin = {
737
769
  config: {
738
770
  policies: []
739
771
  }
772
+ },
773
+ {
774
+ method: "GET",
775
+ path: "/license/limits",
776
+ handler: "license.getLimits",
777
+ config: {
778
+ policies: []
779
+ }
740
780
  }
741
781
  ]
742
782
  };
@@ -1235,19 +1275,23 @@ const licenseGuardService = ({ strapi }) => ({
1235
1275
  }
1236
1276
  },
1237
1277
  /**
1238
- * Get online statistics
1278
+ * Get current license data from store (fetches fresh from server)
1279
+ * This is the correct way to get license data with all feature flags
1239
1280
  */
1240
- async getOnlineStats() {
1281
+ async getCurrentLicense() {
1241
1282
  try {
1242
- const licenseServerUrl = this.getLicenseServerUrl();
1243
- const response = await fetch(`${licenseServerUrl}/api/licenses/stats/online`);
1244
- const data = await response.json();
1245
- if (data.success) {
1246
- return data.data;
1283
+ const pluginStore = strapi.store({
1284
+ type: "plugin",
1285
+ name: "magic-mark"
1286
+ });
1287
+ const licenseKey = await pluginStore.get({ key: "licenseKey" });
1288
+ if (!licenseKey) {
1289
+ return null;
1247
1290
  }
1248
- return null;
1291
+ const license2 = await this.getLicenseByKey(licenseKey);
1292
+ return license2;
1249
1293
  } catch (error) {
1250
- strapi.log.error("[ERROR] Error fetching online stats:", error);
1294
+ strapi.log.error("[LICENSE] Error loading current license:", error);
1251
1295
  return null;
1252
1296
  }
1253
1297
  },
@@ -1356,6 +1400,165 @@ const licenseGuardService = ({ strapi }) => ({
1356
1400
  return false;
1357
1401
  }
1358
1402
  },
1403
+ /**
1404
+ * Get bookmark limit based on license tier
1405
+ * @returns Bookmark limit: 10 (free), 50 (premium), -1 (advanced/unlimited)
1406
+ */
1407
+ async getBookmarkLimit() {
1408
+ try {
1409
+ const licenseGuard = strapi.licenseGuard;
1410
+ const licenseData = licenseGuard?.data;
1411
+ if (licenseData?.featureAdvanced) {
1412
+ return -1;
1413
+ }
1414
+ if (licenseData?.featurePremium) {
1415
+ return 50;
1416
+ }
1417
+ return 10;
1418
+ } catch (error) {
1419
+ strapi.log.debug("[LICENSE] Error getting bookmark limit, using free tier");
1420
+ return 10;
1421
+ }
1422
+ },
1423
+ /**
1424
+ * Check if user can create more bookmarks
1425
+ * @param userId - User's documentId
1426
+ * @returns Object with canCreate boolean and current/max counts
1427
+ */
1428
+ async canCreateBookmark(userId) {
1429
+ try {
1430
+ const limit = await this.getBookmarkLimit();
1431
+ if (limit === -1) {
1432
+ return { canCreate: true, current: 0, max: -1 };
1433
+ }
1434
+ const BOOKMARK_UID2 = "plugin::magic-mark.bookmark";
1435
+ const bookmarks = await strapi.documents(BOOKMARK_UID2).findMany({
1436
+ filters: { creatorId: userId }
1437
+ });
1438
+ const currentCount = bookmarks?.length || 0;
1439
+ if (currentCount >= limit) {
1440
+ return {
1441
+ canCreate: false,
1442
+ current: currentCount,
1443
+ max: limit,
1444
+ message: `Bookmark limit reached (${currentCount}/${limit}). Upgrade to create more bookmarks.`
1445
+ };
1446
+ }
1447
+ return { canCreate: true, current: currentCount, max: limit };
1448
+ } catch (error) {
1449
+ strapi.log.error("[LICENSE] Error checking bookmark limit:", error);
1450
+ return { canCreate: true, current: 0, max: 10 };
1451
+ }
1452
+ },
1453
+ /**
1454
+ * Get current license limits and feature flags
1455
+ * @param userId - User's documentId for bookmark count
1456
+ * @returns License limits object
1457
+ */
1458
+ async getLicenseLimits(userId) {
1459
+ try {
1460
+ const license2 = await this.getCurrentLicense();
1461
+ strapi.log.info("[LICENSE] getLicenseLimits - license exists:", !!license2);
1462
+ if (license2) {
1463
+ strapi.log.info("[LICENSE] getLicenseLimits - featurePremium:", license2.featurePremium);
1464
+ strapi.log.info("[LICENSE] getLicenseLimits - featureAdvanced:", license2.featureAdvanced);
1465
+ }
1466
+ let tier = "free";
1467
+ if (license2?.featureEnterprise === true) tier = "enterprise";
1468
+ else if (license2?.featureAdvanced === true) tier = "advanced";
1469
+ else if (license2?.featurePremium === true) tier = "premium";
1470
+ const isPremium = tier === "premium" || tier === "advanced" || tier === "enterprise";
1471
+ const isAdvanced = tier === "advanced" || tier === "enterprise";
1472
+ strapi.log.info("[LICENSE] getLicenseLimits - detected tier:", tier);
1473
+ const bookmarkCheck = await this.canCreateBookmark(userId);
1474
+ return {
1475
+ maxBookmarks: bookmarkCheck.max,
1476
+ currentBookmarks: bookmarkCheck.current,
1477
+ canCreate: bookmarkCheck.canCreate,
1478
+ tier,
1479
+ features: {
1480
+ queryHistory: isPremium || isAdvanced,
1481
+ export: isPremium || isAdvanced,
1482
+ analytics: isAdvanced,
1483
+ bulkOperations: isAdvanced,
1484
+ customIntegrations: isAdvanced
1485
+ }
1486
+ };
1487
+ } catch (error) {
1488
+ strapi.log.error("[LICENSE] Error getting license limits:", error);
1489
+ return {
1490
+ maxBookmarks: 10,
1491
+ currentBookmarks: 0,
1492
+ canCreate: true,
1493
+ tier: "free",
1494
+ features: {
1495
+ queryHistory: false,
1496
+ export: false,
1497
+ analytics: false,
1498
+ bulkOperations: false,
1499
+ customIntegrations: false
1500
+ }
1501
+ };
1502
+ }
1503
+ },
1504
+ /**
1505
+ * Check if a specific feature is available based on license
1506
+ * @param feature - Feature key to check
1507
+ * @returns Boolean indicating if feature is available
1508
+ */
1509
+ hasFeature(feature) {
1510
+ try {
1511
+ const licenseGuard = strapi.licenseGuard;
1512
+ const licenseData = licenseGuard?.data;
1513
+ const isPremium = licenseData?.featurePremium || false;
1514
+ const isAdvanced = licenseData?.featureAdvanced || false;
1515
+ const featureRequirements = {
1516
+ // Free tier
1517
+ basicBookmarks: "free",
1518
+ basicFilters: "free",
1519
+ // Premium tier
1520
+ extendedBookmarks: "premium",
1521
+ queryHistory: "premium",
1522
+ exportBookmarks: "premium",
1523
+ sharedBookmarks: "premium",
1524
+ // Advanced tier
1525
+ unlimitedBookmarks: "advanced",
1526
+ advancedFilters: "advanced",
1527
+ subGroups: "advanced",
1528
+ bulkOperations: "advanced",
1529
+ analytics: "advanced",
1530
+ customIntegrations: "advanced"
1531
+ };
1532
+ const requiredTier = featureRequirements[feature] || "free";
1533
+ let currentTierLevel = 0;
1534
+ if (isAdvanced) currentTierLevel = 2;
1535
+ else if (isPremium) currentTierLevel = 1;
1536
+ const tierLevels = {
1537
+ free: 0,
1538
+ premium: 1,
1539
+ advanced: 2
1540
+ };
1541
+ return currentTierLevel >= tierLevels[requiredTier];
1542
+ } catch (error) {
1543
+ strapi.log.debug("[LICENSE] Error checking feature:", feature);
1544
+ return false;
1545
+ }
1546
+ },
1547
+ /**
1548
+ * Get current tier name
1549
+ * @returns 'free' | 'premium' | 'advanced'
1550
+ */
1551
+ getCurrentTier() {
1552
+ try {
1553
+ const licenseGuard = strapi.licenseGuard;
1554
+ const licenseData = licenseGuard?.data;
1555
+ if (licenseData?.featureAdvanced) return "advanced";
1556
+ if (licenseData?.featurePremium) return "premium";
1557
+ return "free";
1558
+ } catch (error) {
1559
+ return "free";
1560
+ }
1561
+ },
1359
1562
  /**
1360
1563
  * Cleanup on plugin destroy
1361
1564
  */
@@ -15,6 +15,7 @@ declare const _default: {
15
15
  createAndActivate(ctx: any): Promise<any>;
16
16
  ping(ctx: any): Promise<any>;
17
17
  storeKey(ctx: any): Promise<any>;
18
+ getLimits(ctx: any): Promise<any>;
18
19
  };
19
20
  };
20
21
  export default _default;
@@ -23,5 +23,9 @@ declare const _default: ({ strapi }: any) => {
23
23
  * Store and validate an existing license key
24
24
  */
25
25
  storeKey(ctx: any): Promise<any>;
26
+ /**
27
+ * Get license limits and feature flags for current user
28
+ */
29
+ getLimits(ctx: any): Promise<any>;
26
30
  };
27
31
  export default _default;
@@ -30,6 +30,7 @@ declare const _default: {
30
30
  createAndActivate(ctx: any): Promise<any>;
31
31
  ping(ctx: any): Promise<any>;
32
32
  storeKey(ctx: any): Promise<any>;
33
+ getLimits(ctx: any): Promise<any>;
33
34
  };
34
35
  };
35
36
  routes: {
@@ -85,10 +86,32 @@ declare const _default: {
85
86
  verifyLicense(licenseKey: string, allowGracePeriod?: boolean): Promise<import("./services/license-guard").VerificationResult>;
86
87
  pingLicense(licenseKey: string): Promise<any>;
87
88
  getLicenseByKey(licenseKey: string): Promise<import("./services/license-guard").LicenseData>;
88
- getOnlineStats(): Promise<any>;
89
+ getCurrentLicense(): Promise<import("./services/license-guard").LicenseData>;
89
90
  startPinging(licenseKey: string, intervalMinutes?: number): NodeJS.Timeout;
90
91
  initialize(): Promise<import("./services/license-guard").LicenseStatus>;
91
92
  storeLicenseKey(licenseKey: string): Promise<boolean>;
93
+ getBookmarkLimit(): Promise<number>;
94
+ canCreateBookmark(userId: string): Promise<{
95
+ canCreate: boolean;
96
+ current: number;
97
+ max: number;
98
+ message?: string;
99
+ }>;
100
+ getLicenseLimits(userId: string): Promise<{
101
+ maxBookmarks: number;
102
+ currentBookmarks: number;
103
+ canCreate: boolean;
104
+ tier: string;
105
+ features: {
106
+ queryHistory: boolean;
107
+ export: boolean;
108
+ analytics: boolean;
109
+ bulkOperations: boolean;
110
+ customIntegrations: boolean;
111
+ };
112
+ }>;
113
+ hasFeature(feature: string): boolean;
114
+ getCurrentTier(): "free" | "premium" | "advanced";
92
115
  cleanup(): void;
93
116
  };
94
117
  };
@@ -35,10 +35,32 @@ declare const _default: {
35
35
  verifyLicense(licenseKey: string, allowGracePeriod?: boolean): Promise<import("./license-guard").VerificationResult>;
36
36
  pingLicense(licenseKey: string): Promise<any>;
37
37
  getLicenseByKey(licenseKey: string): Promise<import("./license-guard").LicenseData>;
38
- getOnlineStats(): Promise<any>;
38
+ getCurrentLicense(): Promise<import("./license-guard").LicenseData>;
39
39
  startPinging(licenseKey: string, intervalMinutes?: number): NodeJS.Timeout;
40
40
  initialize(): Promise<import("./license-guard").LicenseStatus>;
41
41
  storeLicenseKey(licenseKey: string): Promise<boolean>;
42
+ getBookmarkLimit(): Promise<number>;
43
+ canCreateBookmark(userId: string): Promise<{
44
+ canCreate: boolean;
45
+ current: number;
46
+ max: number;
47
+ message?: string;
48
+ }>;
49
+ getLicenseLimits(userId: string): Promise<{
50
+ maxBookmarks: number;
51
+ currentBookmarks: number;
52
+ canCreate: boolean;
53
+ tier: string;
54
+ features: {
55
+ queryHistory: boolean;
56
+ export: boolean;
57
+ analytics: boolean;
58
+ bulkOperations: boolean;
59
+ customIntegrations: boolean;
60
+ };
61
+ }>;
62
+ hasFeature(feature: string): boolean;
63
+ getCurrentTier(): "free" | "premium" | "advanced";
42
64
  cleanup(): void;
43
65
  };
44
66
  };
@@ -79,9 +79,10 @@ declare const licenseGuardService: ({ strapi }: {
79
79
  */
80
80
  getLicenseByKey(licenseKey: string): Promise<LicenseData | null>;
81
81
  /**
82
- * Get online statistics
82
+ * Get current license data from store (fetches fresh from server)
83
+ * This is the correct way to get license data with all feature flags
83
84
  */
84
- getOnlineStats(): Promise<any>;
85
+ getCurrentLicense(): Promise<LicenseData | null>;
85
86
  /**
86
87
  * Start periodic pinging for a license
87
88
  */
@@ -95,6 +96,51 @@ declare const licenseGuardService: ({ strapi }: {
95
96
  * Store license key after creation
96
97
  */
97
98
  storeLicenseKey(licenseKey: string): Promise<boolean>;
99
+ /**
100
+ * Get bookmark limit based on license tier
101
+ * @returns Bookmark limit: 10 (free), 50 (premium), -1 (advanced/unlimited)
102
+ */
103
+ getBookmarkLimit(): Promise<number>;
104
+ /**
105
+ * Check if user can create more bookmarks
106
+ * @param userId - User's documentId
107
+ * @returns Object with canCreate boolean and current/max counts
108
+ */
109
+ canCreateBookmark(userId: string): Promise<{
110
+ canCreate: boolean;
111
+ current: number;
112
+ max: number;
113
+ message?: string;
114
+ }>;
115
+ /**
116
+ * Get current license limits and feature flags
117
+ * @param userId - User's documentId for bookmark count
118
+ * @returns License limits object
119
+ */
120
+ getLicenseLimits(userId: string): Promise<{
121
+ maxBookmarks: number;
122
+ currentBookmarks: number;
123
+ canCreate: boolean;
124
+ tier: string;
125
+ features: {
126
+ queryHistory: boolean;
127
+ export: boolean;
128
+ analytics: boolean;
129
+ bulkOperations: boolean;
130
+ customIntegrations: boolean;
131
+ };
132
+ }>;
133
+ /**
134
+ * Check if a specific feature is available based on license
135
+ * @param feature - Feature key to check
136
+ * @returns Boolean indicating if feature is available
137
+ */
138
+ hasFeature(feature: string): boolean;
139
+ /**
140
+ * Get current tier name
141
+ * @returns 'free' | 'premium' | 'advanced'
142
+ */
143
+ getCurrentTier(): 'free' | 'premium' | 'advanced';
98
144
  /**
99
145
  * Cleanup on plugin destroy
100
146
  */
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.0.0",
2
+ "version": "3.0.2",
3
3
  "keywords": [
4
4
  "strapi",
5
5
  "strapi-plugin",