@mdguggenbichler/slugbase-core 0.0.16 → 0.0.18

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 (71) hide show
  1. package/backend/dist/app-factory.d.ts +1 -1
  2. package/backend/dist/app-factory.d.ts.map +1 -1
  3. package/backend/dist/app-factory.js +2 -13
  4. package/backend/dist/app-factory.js.map +1 -1
  5. package/backend/dist/index.js +1 -1
  6. package/backend/dist/index.js.map +1 -1
  7. package/backend/dist/routes/admin/settings.d.ts.map +1 -1
  8. package/backend/dist/routes/admin/settings.js +0 -281
  9. package/backend/dist/routes/admin/settings.js.map +1 -1
  10. package/backend/dist/routes/admin/stats.d.ts.map +1 -1
  11. package/backend/dist/routes/admin/stats.js +0 -39
  12. package/backend/dist/routes/admin/stats.js.map +1 -1
  13. package/backend/dist/routes/admin/teams.d.ts.map +1 -1
  14. package/backend/dist/routes/admin/teams.js +0 -344
  15. package/backend/dist/routes/admin/teams.js.map +1 -1
  16. package/backend/dist/routes/admin/users.d.ts.map +1 -1
  17. package/backend/dist/routes/admin/users.js +0 -317
  18. package/backend/dist/routes/admin/users.js.map +1 -1
  19. package/backend/dist/routes/auth.d.ts.map +1 -1
  20. package/backend/dist/routes/auth.js +0 -284
  21. package/backend/dist/routes/auth.js.map +1 -1
  22. package/backend/dist/routes/bookmarks.d.ts.map +1 -1
  23. package/backend/dist/routes/bookmarks.js +4 -525
  24. package/backend/dist/routes/bookmarks.js.map +1 -1
  25. package/backend/dist/routes/config.d.ts.map +1 -1
  26. package/backend/dist/routes/config.js +4 -29
  27. package/backend/dist/routes/config.js.map +1 -1
  28. package/backend/dist/routes/csrf.d.ts.map +1 -1
  29. package/backend/dist/routes/csrf.js +0 -24
  30. package/backend/dist/routes/csrf.js.map +1 -1
  31. package/backend/dist/routes/dashboard.d.ts.map +1 -1
  32. package/backend/dist/routes/dashboard.js +0 -35
  33. package/backend/dist/routes/dashboard.js.map +1 -1
  34. package/backend/dist/routes/email-verification.d.ts.map +1 -1
  35. package/backend/dist/routes/email-verification.js +0 -53
  36. package/backend/dist/routes/email-verification.js.map +1 -1
  37. package/backend/dist/routes/folders.d.ts.map +1 -1
  38. package/backend/dist/routes/folders.js +0 -217
  39. package/backend/dist/routes/folders.js.map +1 -1
  40. package/backend/dist/routes/go.d.ts.map +1 -1
  41. package/backend/dist/routes/go.js +0 -95
  42. package/backend/dist/routes/go.js.map +1 -1
  43. package/backend/dist/routes/health.d.ts.map +1 -1
  44. package/backend/dist/routes/health.js +0 -45
  45. package/backend/dist/routes/health.js.map +1 -1
  46. package/backend/dist/routes/oidc-providers.d.ts.map +1 -1
  47. package/backend/dist/routes/oidc-providers.js +0 -221
  48. package/backend/dist/routes/oidc-providers.js.map +1 -1
  49. package/backend/dist/routes/password-reset.d.ts.map +1 -1
  50. package/backend/dist/routes/password-reset.js +0 -67
  51. package/backend/dist/routes/password-reset.js.map +1 -1
  52. package/backend/dist/routes/tags.d.ts.map +1 -1
  53. package/backend/dist/routes/tags.js +0 -174
  54. package/backend/dist/routes/tags.js.map +1 -1
  55. package/backend/dist/routes/teams.d.ts.map +1 -1
  56. package/backend/dist/routes/teams.js +0 -36
  57. package/backend/dist/routes/teams.js.map +1 -1
  58. package/backend/dist/routes/tokens.d.ts.map +1 -1
  59. package/backend/dist/routes/tokens.js +0 -108
  60. package/backend/dist/routes/tokens.js.map +1 -1
  61. package/backend/dist/routes/users.d.ts.map +1 -1
  62. package/backend/dist/routes/users.js +0 -81
  63. package/backend/dist/routes/users.js.map +1 -1
  64. package/backend/dist/utils/ai-feature.d.ts +9 -7
  65. package/backend/dist/utils/ai-feature.d.ts.map +1 -1
  66. package/backend/dist/utils/ai-feature.js +29 -13
  67. package/backend/dist/utils/ai-feature.js.map +1 -1
  68. package/frontend/src/App.tsx +4 -2
  69. package/frontend/src/components/admin/AdminAI.tsx +68 -58
  70. package/frontend/src/contexts/AppConfigContext.tsx +7 -0
  71. package/package.json +1 -1
@@ -25,103 +25,6 @@ async function recordAiSuggestionUsage(userId, used) {
25
25
  // Table may not exist yet; do not fail the bookmark request
26
26
  }
27
27
  }
28
- /**
29
- * @swagger
30
- * /api/bookmarks:
31
- * get:
32
- * summary: Get all bookmarks
33
- * description: Returns all bookmarks for the authenticated user, including own bookmarks and bookmarks shared via teams or users. Supports filtering by folder and tag.
34
- * tags: [Bookmarks]
35
- * security:
36
- * - cookieAuth: []
37
- * - bearerAuth: []
38
- * parameters:
39
- * - in: query
40
- * name: folder_id
41
- * schema:
42
- * type: string
43
- * description: Filter bookmarks by folder ID
44
- * example: "123e4567-e89b-12d3-a456-426614174000"
45
- * - in: query
46
- * name: tag_id
47
- * schema:
48
- * type: string
49
- * description: Filter bookmarks by tag ID
50
- * example: "123e4567-e89b-12d3-a456-426614174000"
51
- * - in: query
52
- * name: limit
53
- * schema:
54
- * type: integer
55
- * default: 50
56
- * description: Max items per page (1-100)
57
- * - in: query
58
- * name: offset
59
- * schema:
60
- * type: integer
61
- * default: 0
62
- * description: Number of items to skip
63
- * responses:
64
- * 200:
65
- * description: List of bookmarks
66
- * content:
67
- * application/json:
68
- * schema:
69
- * type: array
70
- * items:
71
- * type: object
72
- * properties:
73
- * id:
74
- * type: string
75
- * example: "123e4567-e89b-12d3-a456-426614174000"
76
- * title:
77
- * type: string
78
- * example: "Example Bookmark"
79
- * url:
80
- * type: string
81
- * example: "https://example.com"
82
- * slug:
83
- * type: string
84
- * nullable: true
85
- * example: "example-slug"
86
- * forwarding_enabled:
87
- * type: boolean
88
- * example: true
89
- * bookmark_type:
90
- * type: string
91
- * enum: [own, shared]
92
- * example: "own"
93
- * folders:
94
- * type: array
95
- * items:
96
- * type: object
97
- * properties:
98
- * id:
99
- * type: string
100
- * name:
101
- * type: string
102
- * icon:
103
- * type: string
104
- * nullable: true
105
- * tags:
106
- * type: array
107
- * items:
108
- * type: object
109
- * properties:
110
- * id:
111
- * type: string
112
- * name:
113
- * type: string
114
- * shared_teams:
115
- * type: array
116
- * items:
117
- * type: object
118
- * shared_users:
119
- * type: array
120
- * items:
121
- * type: object
122
- * 401:
123
- * description: Unauthorized
124
- */
125
28
  // Get all bookmarks for user (including shared bookmarks)
126
29
  router.get('/', async (req, res) => {
127
30
  const authReq = req;
@@ -445,79 +348,6 @@ router.get('/', async (req, res) => {
445
348
  res.status(500).json({ error: error.message });
446
349
  }
447
350
  });
448
- /**
449
- * @swagger
450
- * /api/bookmarks/{id}:
451
- * get:
452
- * summary: Get bookmark by ID
453
- * description: Returns a single bookmark by ID. User must own the bookmark or have access via sharing.
454
- * tags: [Bookmarks]
455
- * security:
456
- * - cookieAuth: []
457
- * - bearerAuth: []
458
- * parameters:
459
- * - in: path
460
- * name: id
461
- * required: true
462
- * schema:
463
- * type: string
464
- * description: Bookmark ID
465
- * example: "123e4567-e89b-12d3-a456-426614174000"
466
- * responses:
467
- * 200:
468
- * description: Bookmark details
469
- * content:
470
- * application/json:
471
- * schema:
472
- * type: object
473
- * properties:
474
- * id:
475
- * type: string
476
- * title:
477
- * type: string
478
- * url:
479
- * type: string
480
- * slug:
481
- * type: string
482
- * nullable: true
483
- * forwarding_enabled:
484
- * type: boolean
485
- * folders:
486
- * type: array
487
- * tags:
488
- * type: array
489
- * shared_teams:
490
- * type: array
491
- * shared_users:
492
- * type: array
493
- * 404:
494
- * description: Bookmark not found
495
- * 401:
496
- * description: Unauthorized
497
- */
498
- /**
499
- * @swagger
500
- * /api/bookmarks/search:
501
- * get:
502
- * summary: Search bookmarks, folders, and tags
503
- * description: Global search across bookmarks, folders, and tags
504
- * tags: [Bookmarks]
505
- * security:
506
- * - cookieAuth: []
507
- * - bearerAuth: []
508
- * parameters:
509
- * - in: query
510
- * name: q
511
- * required: true
512
- * schema:
513
- * type: string
514
- * description: Search query
515
- * responses:
516
- * 200:
517
- * description: Search results
518
- * 401:
519
- * description: Unauthorized
520
- */
521
351
  // Search endpoint (must be before /:id route)
522
352
  router.get('/search', async (req, res) => {
523
353
  const authReq = req;
@@ -611,26 +441,6 @@ router.get('/search', async (req, res) => {
611
441
  res.status(500).json({ error: 'Search failed' });
612
442
  }
613
443
  });
614
- /**
615
- * @swagger
616
- * /api/bookmarks/export:
617
- * get:
618
- * summary: Export bookmarks as JSON
619
- * description: Export all user's bookmarks as JSON
620
- * tags: [Bookmarks]
621
- * security:
622
- * - cookieAuth: []
623
- * - bearerAuth: []
624
- * responses:
625
- * 200:
626
- * description: JSON export of bookmarks
627
- * content:
628
- * application/json:
629
- * schema:
630
- * type: array
631
- * 401:
632
- * description: Unauthorized
633
- */
634
444
  // Export bookmarks as JSON (must be before /:id route)
635
445
  router.get('/export', async (req, res) => {
636
446
  const authReq = req;
@@ -793,51 +603,6 @@ router.get('/ids', async (req, res) => {
793
603
  res.status(500).json({ error: 'Failed to fetch bookmark IDs' });
794
604
  }
795
605
  });
796
- /**
797
- * @swagger
798
- * /api/bookmarks/ai-suggest:
799
- * post:
800
- * summary: Get AI suggestions for bookmark metadata
801
- * description: Returns suggested title, slug, and tags for a URL. Requires AI feature enabled. Non-blocking; bookmark creation never depends on this.
802
- * tags: [Bookmarks]
803
- * security:
804
- * - cookieAuth: []
805
- * - bearerAuth: []
806
- * requestBody:
807
- * required: true
808
- * content:
809
- * application/json:
810
- * schema:
811
- * type: object
812
- * required: [url]
813
- * properties:
814
- * url:
815
- * type: string
816
- * format: uri
817
- * page_title:
818
- * type: string
819
- * responses:
820
- * 200:
821
- * description: AI suggestions
822
- * content:
823
- * application/json:
824
- * schema:
825
- * type: object
826
- * properties:
827
- * title: { type: string }
828
- * slug: { type: string }
829
- * tags: { type: array, items: { type: string } }
830
- * language: { type: string }
831
- * confidence: { type: number }
832
- * 400:
833
- * description: Invalid URL
834
- * 403:
835
- * description: AI feature disabled or not available for plan
836
- * 408:
837
- * description: AI request timeout
838
- * 503:
839
- * description: AI not configured
840
- */
841
606
  router.post('/ai-suggest', async (req, res) => {
842
607
  const authReq = req;
843
608
  try {
@@ -850,11 +615,12 @@ router.post('/ai-suggest', async (req, res) => {
850
615
  if (!urlValidation.valid) {
851
616
  return res.status(400).json({ error: urlValidation.error });
852
617
  }
853
- const enabled = await isAISuggestionsEnabled(userId);
618
+ const tenantId = getTenantId(req);
619
+ const enabled = await isAISuggestionsEnabled(userId, tenantId);
854
620
  if (!enabled) {
855
621
  return res.status(403).json({ error: 'AI suggestions are not available' });
856
622
  }
857
- const apiKey = await getAIApiKey();
623
+ const apiKey = await getAIApiKey(tenantId);
858
624
  if (!apiKey) {
859
625
  return res.status(503).json({ error: 'AI is not configured' });
860
626
  }
@@ -889,7 +655,7 @@ router.post('/ai-suggest', async (req, res) => {
889
655
  const pageTitleToUse = typeof pageTitle === 'string' && pageTitle.trim()
890
656
  ? pageTitle.trim()
891
657
  : fetchedTitle;
892
- const model = await getAIModel();
658
+ const model = await getAIModel(tenantId);
893
659
  const result = await callAIProvider(sanitizedUrl, pageTitleToUse, fetchedDescription, apiKey, model, 10000, userLanguage, siteName);
894
660
  if (!result) {
895
661
  return res.status(503).json({ error: 'AI suggestion failed' });
@@ -976,31 +742,6 @@ router.get('/:id', async (req, res) => {
976
742
  res.status(500).json({ error: error.message });
977
743
  }
978
744
  });
979
- /**
980
- * @swagger
981
- * /api/bookmarks/{id}/track-access:
982
- * post:
983
- * summary: Track bookmark access
984
- * description: Increments access_count and updates last_accessed_at for a bookmark when it is opened
985
- * tags: [Bookmarks]
986
- * security:
987
- * - cookieAuth: []
988
- * - bearerAuth: []
989
- * parameters:
990
- * - in: path
991
- * name: id
992
- * required: true
993
- * schema:
994
- * type: string
995
- * description: Bookmark ID
996
- * responses:
997
- * 200:
998
- * description: Access tracked successfully
999
- * 404:
1000
- * description: Bookmark not found
1001
- * 401:
1002
- * description: Unauthorized
1003
- */
1004
745
  // Track bookmark access (must be before PUT /:id)
1005
746
  router.post('/:id/track-access', async (req, res) => {
1006
747
  const authReq = req;
@@ -1024,97 +765,6 @@ router.post('/:id/track-access', async (req, res) => {
1024
765
  res.status(500).json({ error: error.message });
1025
766
  }
1026
767
  });
1027
- /**
1028
- * @swagger
1029
- * /api/bookmarks:
1030
- * post:
1031
- * summary: Create a new bookmark
1032
- * description: Creates a new bookmark. Slug is required only if forwarding is enabled. Can assign to multiple folders, tags, and share with users/teams.
1033
- * tags: [Bookmarks]
1034
- * security:
1035
- * - cookieAuth: []
1036
- * - bearerAuth: []
1037
- * requestBody:
1038
- * required: true
1039
- * content:
1040
- * application/json:
1041
- * schema:
1042
- * type: object
1043
- * required:
1044
- * - title
1045
- * - url
1046
- * properties:
1047
- * title:
1048
- * type: string
1049
- * example: "Example Bookmark"
1050
- * url:
1051
- * type: string
1052
- * format: uri
1053
- * example: "https://example.com"
1054
- * slug:
1055
- * type: string
1056
- * nullable: true
1057
- * description: Required if forwarding_enabled is true, optional otherwise
1058
- * example: "example-slug"
1059
- * forwarding_enabled:
1060
- * type: boolean
1061
- * default: false
1062
- * example: true
1063
- * folder_ids:
1064
- * type: array
1065
- * items:
1066
- * type: string
1067
- * description: Array of folder IDs to assign bookmark to
1068
- * example: ["123e4567-e89b-12d3-a456-426614174000"]
1069
- * tag_ids:
1070
- * type: array
1071
- * items:
1072
- * type: string
1073
- * description: Array of tag IDs to assign to bookmark
1074
- * example: ["123e4567-e89b-12d3-a456-426614174000"]
1075
- * team_ids:
1076
- * type: array
1077
- * items:
1078
- * type: string
1079
- * description: Array of team IDs to share bookmark with
1080
- * example: ["123e4567-e89b-12d3-a456-426614174000"]
1081
- * user_ids:
1082
- * type: array
1083
- * items:
1084
- * type: string
1085
- * description: Array of user IDs to share bookmark with
1086
- * example: ["123e4567-e89b-12d3-a456-426614174000"]
1087
- * share_all_teams:
1088
- * type: boolean
1089
- * default: false
1090
- * description: Share bookmark with all teams user is a member of
1091
- * example: false
1092
- * responses:
1093
- * 201:
1094
- * description: Bookmark created successfully
1095
- * content:
1096
- * application/json:
1097
- * schema:
1098
- * type: object
1099
- * properties:
1100
- * id:
1101
- * type: string
1102
- * title:
1103
- * type: string
1104
- * url:
1105
- * type: string
1106
- * slug:
1107
- * type: string
1108
- * nullable: true
1109
- * forwarding_enabled:
1110
- * type: boolean
1111
- * 400:
1112
- * description: Missing required fields, slug required when forwarding enabled, or slug already exists
1113
- * 401:
1114
- * description: Unauthorized
1115
- * 403:
1116
- * description: User does not own folder or is not member of team
1117
- */
1118
768
  // Create bookmark
1119
769
  router.post('/', async (req, res) => {
1120
770
  const authReq = req;
@@ -1223,81 +873,6 @@ router.post('/', async (req, res) => {
1223
873
  res.status(500).json({ error: error.message });
1224
874
  }
1225
875
  });
1226
- /**
1227
- * @swagger
1228
- * /api/bookmarks/{id}:
1229
- * put:
1230
- * summary: Update bookmark
1231
- * description: Updates an existing bookmark. User must own the bookmark. All fields are optional.
1232
- * tags: [Bookmarks]
1233
- * security:
1234
- * - cookieAuth: []
1235
- * - bearerAuth: []
1236
- * parameters:
1237
- * - in: path
1238
- * name: id
1239
- * required: true
1240
- * schema:
1241
- * type: string
1242
- * description: Bookmark ID
1243
- * example: "123e4567-e89b-12d3-a456-426614174000"
1244
- * requestBody:
1245
- * required: true
1246
- * content:
1247
- * application/json:
1248
- * schema:
1249
- * type: object
1250
- * properties:
1251
- * title:
1252
- * type: string
1253
- * example: "Updated Bookmark Title"
1254
- * url:
1255
- * type: string
1256
- * format: uri
1257
- * example: "https://updated-example.com"
1258
- * slug:
1259
- * type: string
1260
- * nullable: true
1261
- * description: Required if forwarding_enabled is true
1262
- * example: "updated-slug"
1263
- * forwarding_enabled:
1264
- * type: boolean
1265
- * example: true
1266
- * folder_ids:
1267
- * type: array
1268
- * items:
1269
- * type: string
1270
- * description: Array of folder IDs (replaces existing assignments)
1271
- * tag_ids:
1272
- * type: array
1273
- * items:
1274
- * type: string
1275
- * description: Array of tag IDs (replaces existing assignments)
1276
- * team_ids:
1277
- * type: array
1278
- * items:
1279
- * type: string
1280
- * description: Array of team IDs to share with (replaces existing shares)
1281
- * user_ids:
1282
- * type: array
1283
- * items:
1284
- * type: string
1285
- * description: Array of user IDs to share with (replaces existing shares)
1286
- * share_all_teams:
1287
- * type: boolean
1288
- * description: Share with all teams user is a member of
1289
- * responses:
1290
- * 200:
1291
- * description: Bookmark updated successfully
1292
- * 400:
1293
- * description: Slug required when forwarding enabled or slug already exists
1294
- * 401:
1295
- * description: Unauthorized
1296
- * 403:
1297
- * description: User does not own folder or is not member of team
1298
- * 404:
1299
- * description: Bookmark not found
1300
- */
1301
876
  // Update bookmark
1302
877
  router.put('/:id', async (req, res) => {
1303
878
  const authReq = req;
@@ -1456,40 +1031,6 @@ router.put('/:id', async (req, res) => {
1456
1031
  res.status(500).json({ error: error.message });
1457
1032
  }
1458
1033
  });
1459
- /**
1460
- * @swagger
1461
- * /api/bookmarks/{id}:
1462
- * delete:
1463
- * summary: Delete bookmark
1464
- * description: Deletes a bookmark. User must own the bookmark.
1465
- * tags: [Bookmarks]
1466
- * security:
1467
- * - cookieAuth: []
1468
- * - bearerAuth: []
1469
- * parameters:
1470
- * - in: path
1471
- * name: id
1472
- * required: true
1473
- * schema:
1474
- * type: string
1475
- * description: Bookmark ID
1476
- * example: "123e4567-e89b-12d3-a456-426614174000"
1477
- * responses:
1478
- * 200:
1479
- * description: Bookmark deleted successfully
1480
- * content:
1481
- * application/json:
1482
- * schema:
1483
- * type: object
1484
- * properties:
1485
- * message:
1486
- * type: string
1487
- * example: "Bookmark deleted"
1488
- * 401:
1489
- * description: Unauthorized
1490
- * 404:
1491
- * description: Bookmark not found
1492
- */
1493
1034
  // Delete bookmark
1494
1035
  router.delete('/:id', async (req, res) => {
1495
1036
  const authReq = req;
@@ -1508,68 +1049,6 @@ router.delete('/:id', async (req, res) => {
1508
1049
  res.status(500).json({ error: error.message });
1509
1050
  }
1510
1051
  });
1511
- /**
1512
- * @swagger
1513
- * /api/bookmarks/search:
1514
- * get:
1515
- * summary: Search bookmarks, folders, and tags
1516
- * description: Search across bookmarks, folders, and tags for the authenticated user
1517
- * tags: [Bookmarks]
1518
- * security:
1519
- * - cookieAuth: []
1520
- * - bearerAuth: []
1521
- * parameters:
1522
- * - in: query
1523
- * name: q
1524
- * required: true
1525
- * schema:
1526
- * type: string
1527
- * description: Search query
1528
- * example: "example"
1529
- * responses:
1530
- * 200:
1531
- * description: Search results
1532
- * 401:
1533
- * description: Unauthorized
1534
- */
1535
- /**
1536
- * @swagger
1537
- * /api/bookmarks/import:
1538
- * post:
1539
- * summary: Import bookmarks from JSON
1540
- * description: Import bookmarks from a JSON array
1541
- * tags: [Bookmarks]
1542
- * security:
1543
- * - cookieAuth: []
1544
- * - bearerAuth: []
1545
- * requestBody:
1546
- * required: true
1547
- * content:
1548
- * application/json:
1549
- * schema:
1550
- * type: object
1551
- * properties:
1552
- * bookmarks:
1553
- * type: array
1554
- * items:
1555
- * type: object
1556
- * properties:
1557
- * title:
1558
- * type: string
1559
- * url:
1560
- * type: string
1561
- * slug:
1562
- * type: string
1563
- * forwarding_enabled:
1564
- * type: boolean
1565
- * responses:
1566
- * 200:
1567
- * description: Import successful
1568
- * 400:
1569
- * description: Invalid import data
1570
- * 401:
1571
- * description: Unauthorized
1572
- */
1573
1052
  // Import bookmarks from JSON
1574
1053
  router.post('/import', async (req, res) => {
1575
1054
  const authReq = req;