@strapi/admin 5.42.1 → 5.43.0

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 (138) hide show
  1. package/dist/admin/admin/src/components/Form.js +11 -10
  2. package/dist/admin/admin/src/components/Form.js.map +1 -1
  3. package/dist/admin/admin/src/components/Form.mjs +11 -10
  4. package/dist/admin/admin/src/components/Form.mjs.map +1 -1
  5. package/dist/admin/admin/src/components/FormInputs/Date.js +2 -2
  6. package/dist/admin/admin/src/components/FormInputs/Date.js.map +1 -1
  7. package/dist/admin/admin/src/components/FormInputs/Date.mjs +2 -2
  8. package/dist/admin/admin/src/components/FormInputs/Date.mjs.map +1 -1
  9. package/dist/admin/admin/src/components/GuidedTour/Context.js +3 -2
  10. package/dist/admin/admin/src/components/GuidedTour/Context.js.map +1 -1
  11. package/dist/admin/admin/src/components/GuidedTour/Context.mjs +3 -2
  12. package/dist/admin/admin/src/components/GuidedTour/Context.mjs.map +1 -1
  13. package/dist/admin/admin/src/components/PageHelpers.js +1 -1
  14. package/dist/admin/admin/src/components/PageHelpers.js.map +1 -1
  15. package/dist/admin/admin/src/components/PageHelpers.mjs +1 -1
  16. package/dist/admin/admin/src/components/PageHelpers.mjs.map +1 -1
  17. package/dist/admin/admin/src/components/Table.js +28 -15
  18. package/dist/admin/admin/src/components/Table.js.map +1 -1
  19. package/dist/admin/admin/src/components/Table.mjs +29 -16
  20. package/dist/admin/admin/src/components/Table.mjs.map +1 -1
  21. package/dist/admin/admin/src/core/store/configure.js +3 -1
  22. package/dist/admin/admin/src/core/store/configure.js.map +1 -1
  23. package/dist/admin/admin/src/core/store/configure.mjs +3 -1
  24. package/dist/admin/admin/src/core/store/configure.mjs.map +1 -1
  25. package/dist/admin/admin/src/hooks/usePersistentState.js +9 -4
  26. package/dist/admin/admin/src/hooks/usePersistentState.js.map +1 -1
  27. package/dist/admin/admin/src/hooks/usePersistentState.mjs +10 -6
  28. package/dist/admin/admin/src/hooks/usePersistentState.mjs.map +1 -1
  29. package/dist/admin/admin/src/pages/Settings/pages/ApplicationInfo/components/LogoInput.js +4 -1
  30. package/dist/admin/admin/src/pages/Settings/pages/ApplicationInfo/components/LogoInput.js.map +1 -1
  31. package/dist/admin/admin/src/pages/Settings/pages/ApplicationInfo/components/LogoInput.mjs +4 -1
  32. package/dist/admin/admin/src/pages/Settings/pages/ApplicationInfo/components/LogoInput.mjs.map +1 -1
  33. package/dist/admin/admin/src/render.js +2 -0
  34. package/dist/admin/admin/src/render.js.map +1 -1
  35. package/dist/admin/admin/src/render.mjs +2 -0
  36. package/dist/admin/admin/src/render.mjs.map +1 -1
  37. package/dist/admin/admin/src/services/api.js +2 -2
  38. package/dist/admin/admin/src/services/api.js.map +1 -1
  39. package/dist/admin/admin/src/services/api.mjs +2 -2
  40. package/dist/admin/admin/src/services/api.mjs.map +1 -1
  41. package/dist/admin/admin/src/translations/nl.json.js +394 -89
  42. package/dist/admin/admin/src/translations/nl.json.js.map +1 -1
  43. package/dist/admin/admin/src/translations/nl.json.mjs +393 -90
  44. package/dist/admin/admin/src/translations/nl.json.mjs.map +1 -1
  45. package/dist/admin/ee/admin/src/hooks/useAIUsageWarning.js +1 -1
  46. package/dist/admin/ee/admin/src/hooks/useAIUsageWarning.js.map +1 -1
  47. package/dist/admin/ee/admin/src/hooks/useAIUsageWarning.mjs +2 -2
  48. package/dist/admin/ee/admin/src/hooks/useAIUsageWarning.mjs.map +1 -1
  49. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.js +1 -1
  50. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.js.map +1 -1
  51. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.mjs +2 -2
  52. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.mjs.map +1 -1
  53. package/dist/admin/ee/admin/src/services/ai.js +7 -7
  54. package/dist/admin/ee/admin/src/services/ai.js.map +1 -1
  55. package/dist/admin/ee/admin/src/services/ai.mjs +6 -6
  56. package/dist/admin/ee/admin/src/services/ai.mjs.map +1 -1
  57. package/dist/admin/ee.js +2 -2
  58. package/dist/admin/ee.mjs +1 -1
  59. package/dist/admin/index.js +1 -0
  60. package/dist/admin/index.js.map +1 -1
  61. package/dist/admin/index.mjs +1 -1
  62. package/dist/admin/src/core/store/configure.d.ts +2 -2
  63. package/dist/admin/src/core/store/hooks.d.ts +2 -2
  64. package/dist/admin/src/ee.d.ts +1 -1
  65. package/dist/admin/src/hooks/useAdminRoles.d.ts +1 -1
  66. package/dist/admin/src/hooks/usePersistentState.d.ts +2 -1
  67. package/dist/admin/src/index.d.ts +1 -1
  68. package/dist/admin/src/pages/Settings/pages/Webhooks/hooks/useWebhooks.d.ts +4 -4
  69. package/dist/admin/src/selectors.d.ts +2 -2
  70. package/dist/admin/src/services/admin.d.ts +6 -6
  71. package/dist/admin/src/services/api.d.ts +1 -1
  72. package/dist/admin/src/services/apiTokens.d.ts +1 -1
  73. package/dist/admin/src/services/auth.d.ts +11 -11
  74. package/dist/admin/src/services/contentApi.d.ts +1 -1
  75. package/dist/admin/src/services/contentManager.d.ts +1 -1
  76. package/dist/admin/src/services/homepage.d.ts +3 -3
  77. package/dist/admin/src/services/transferTokens.d.ts +1 -1
  78. package/dist/admin/src/services/users.d.ts +8 -8
  79. package/dist/admin/src/services/webhooks.d.ts +2 -2
  80. package/dist/admin/tests/utils.d.ts +1 -1
  81. package/dist/ee/admin/src/services/ai.d.ts +6 -6
  82. package/dist/ee/admin/src/services/auditLogs.d.ts +1 -1
  83. package/dist/ee/server/src/index.d.ts +0 -16
  84. package/dist/ee/server/src/index.d.ts.map +1 -1
  85. package/dist/server/ee/server/src/index.js +0 -16
  86. package/dist/server/ee/server/src/index.js.map +1 -1
  87. package/dist/server/ee/server/src/index.mjs +0 -16
  88. package/dist/server/ee/server/src/index.mjs.map +1 -1
  89. package/dist/server/server/src/ai/controllers/ai.js +52 -0
  90. package/dist/server/server/src/ai/controllers/ai.js.map +1 -0
  91. package/dist/server/server/src/ai/controllers/ai.mjs +50 -0
  92. package/dist/server/server/src/ai/controllers/ai.mjs.map +1 -0
  93. package/dist/server/{ee/server → server}/src/ai/routes/ai.js +1 -2
  94. package/dist/server/server/src/ai/routes/ai.js.map +1 -0
  95. package/dist/server/{ee/server → server}/src/ai/routes/ai.mjs +1 -2
  96. package/dist/server/server/src/ai/routes/ai.mjs.map +1 -0
  97. package/dist/server/{ee/server/src/ai/containers → server/src/ai/services}/ai.js +107 -32
  98. package/dist/server/server/src/ai/services/ai.js.map +1 -0
  99. package/dist/server/{ee/server/src/ai/containers → server/src/ai/services}/ai.mjs +107 -32
  100. package/dist/server/server/src/ai/services/ai.mjs.map +1 -0
  101. package/dist/server/server/src/controllers/index.js +3 -1
  102. package/dist/server/server/src/controllers/index.js.map +1 -1
  103. package/dist/server/server/src/controllers/index.mjs +3 -1
  104. package/dist/server/server/src/controllers/index.mjs.map +1 -1
  105. package/dist/server/server/src/register.js +4 -0
  106. package/dist/server/server/src/register.js.map +1 -1
  107. package/dist/server/server/src/register.mjs +4 -0
  108. package/dist/server/server/src/register.mjs.map +1 -1
  109. package/dist/server/server/src/routes/index.js +3 -1
  110. package/dist/server/server/src/routes/index.js.map +1 -1
  111. package/dist/server/server/src/routes/index.mjs +3 -1
  112. package/dist/server/server/src/routes/index.mjs.map +1 -1
  113. package/dist/{ee/server → server}/src/ai/controllers/ai.d.ts +1 -1
  114. package/dist/server/src/ai/controllers/ai.d.ts.map +1 -0
  115. package/dist/server/src/ai/routes/ai.d.ts.map +1 -0
  116. package/dist/server/src/ai/services/ai.d.ts +30 -0
  117. package/dist/server/src/ai/services/ai.d.ts.map +1 -0
  118. package/dist/server/src/controllers/index.d.ts +5 -0
  119. package/dist/server/src/controllers/index.d.ts.map +1 -1
  120. package/dist/server/src/index.d.ts +5 -0
  121. package/dist/server/src/index.d.ts.map +1 -1
  122. package/dist/server/src/register.d.ts.map +1 -1
  123. package/dist/server/src/routes/index.d.ts.map +1 -1
  124. package/dist/shared/contracts/ai.d.ts +3 -3
  125. package/package.json +8 -8
  126. package/dist/ee/server/src/ai/containers/ai.d.ts +0 -15
  127. package/dist/ee/server/src/ai/containers/ai.d.ts.map +0 -1
  128. package/dist/ee/server/src/ai/controllers/ai.d.ts.map +0 -1
  129. package/dist/ee/server/src/ai/routes/ai.d.ts.map +0 -1
  130. package/dist/server/ee/server/src/ai/containers/ai.js.map +0 -1
  131. package/dist/server/ee/server/src/ai/containers/ai.mjs.map +0 -1
  132. package/dist/server/ee/server/src/ai/controllers/ai.js +0 -121
  133. package/dist/server/ee/server/src/ai/controllers/ai.js.map +0 -1
  134. package/dist/server/ee/server/src/ai/controllers/ai.mjs +0 -119
  135. package/dist/server/ee/server/src/ai/controllers/ai.mjs.map +0 -1
  136. package/dist/server/ee/server/src/ai/routes/ai.js.map +0 -1
  137. package/dist/server/ee/server/src/ai/routes/ai.mjs.map +0 -1
  138. /package/dist/{ee/server → server}/src/ai/routes/ai.d.ts +0 -0
@@ -0,0 +1,50 @@
1
+ var ai = {
2
+ async getAiToken (ctx) {
3
+ if (strapi.ai.admin.isEnabled() === false) {
4
+ return ctx.notFound();
5
+ }
6
+ try {
7
+ // `admin::isAuthenticatedAdmin` only checks `ctx.state.isAuthenticated`, not `ctx.state.user`.
8
+ // With the current admin JWT strategy, a successful auth run always sets both; this handler
9
+ // still requires `user` because `getAiToken()` needs an admin identity. Keeps us safe if the
10
+ // strategy/policy contract ever diverges or this action is invoked outside the normal pipeline.
11
+ if (!ctx.state.user) {
12
+ return ctx.unauthorized('Authentication required');
13
+ }
14
+ const aiToken = await strapi.ai.admin.getAiToken();
15
+ ctx.body = {
16
+ data: aiToken
17
+ };
18
+ } catch (error) {
19
+ return ctx.internalServerError('AI token request failed. Check server logs for details.');
20
+ }
21
+ },
22
+ async getAiUsage (ctx) {
23
+ if (strapi.ai.admin.isEnabled() === false) {
24
+ return ctx.notFound();
25
+ }
26
+ try {
27
+ const usage = await strapi.ai.admin.getAiUsage();
28
+ ctx.body = usage;
29
+ } catch (error) {
30
+ return ctx.internalServerError('AI usage data request failed. Check server logs for details.');
31
+ }
32
+ },
33
+ async getAiFeatureConfig (ctx) {
34
+ if (strapi.ai.admin.isEnabled() === false) {
35
+ return ctx.notFound();
36
+ }
37
+ try {
38
+ const aiFeatureConfig = await strapi.ai.admin.getAiFeatureConfig();
39
+ ctx.body = {
40
+ data: aiFeatureConfig
41
+ };
42
+ } catch (error) {
43
+ strapi.log.error('AI feature config request failed', error);
44
+ return ctx.internalServerError('AI feature config request failed. Check server logs for details.');
45
+ }
46
+ }
47
+ };
48
+
49
+ export { ai as default };
50
+ //# sourceMappingURL=ai.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.mjs","sources":["../../../../../../server/src/ai/controllers/ai.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport { GetAiFeatureConfig, GetAiToken } from '../../../../shared/contracts/ai';\n\nexport default {\n async getAiToken(ctx: Context) {\n if (strapi.ai.admin.isEnabled() === false) {\n return ctx.notFound();\n }\n\n try {\n // `admin::isAuthenticatedAdmin` only checks `ctx.state.isAuthenticated`, not `ctx.state.user`.\n // With the current admin JWT strategy, a successful auth run always sets both; this handler\n // still requires `user` because `getAiToken()` needs an admin identity. Keeps us safe if the\n // strategy/policy contract ever diverges or this action is invoked outside the normal pipeline.\n if (!ctx.state.user) {\n return ctx.unauthorized('Authentication required');\n }\n\n const aiToken = await strapi.ai.admin.getAiToken();\n\n ctx.body = {\n data: aiToken,\n } satisfies GetAiToken.Response;\n } catch (error) {\n return ctx.internalServerError('AI token request failed. Check server logs for details.');\n }\n },\n\n async getAiUsage(ctx: Context) {\n if (strapi.ai.admin.isEnabled() === false) {\n return ctx.notFound();\n }\n\n try {\n const usage = await strapi.ai.admin.getAiUsage();\n ctx.body = usage;\n } catch (error) {\n return ctx.internalServerError(\n 'AI usage data request failed. Check server logs for details.'\n );\n }\n },\n\n async getAiFeatureConfig(ctx: Context) {\n if (strapi.ai.admin.isEnabled() === false) {\n return ctx.notFound();\n }\n\n try {\n const aiFeatureConfig = await strapi.ai.admin.getAiFeatureConfig();\n\n ctx.body = {\n data: aiFeatureConfig,\n } satisfies GetAiFeatureConfig.Response;\n } catch (error) {\n strapi.log.error('AI feature config request failed', error);\n return ctx.internalServerError(\n 'AI feature config request failed. Check server logs for details.'\n );\n }\n },\n};\n"],"names":["getAiToken","ctx","strapi","ai","admin","isEnabled","notFound","state","user","unauthorized","aiToken","body","data","error","internalServerError","getAiUsage","usage","getAiFeatureConfig","aiFeatureConfig","log"],"mappings":"AAGA,SAAe;AACb,IAAA,MAAMA,YAAWC,GAAY,EAAA;AAC3B,QAAA,IAAIC,OAAOC,EAAE,CAACC,KAAK,CAACC,SAAS,OAAO,KAAA,EAAO;AACzC,YAAA,OAAOJ,IAAIK,QAAQ,EAAA;AACrB,QAAA;QAEA,IAAI;;;;;AAKF,YAAA,IAAI,CAACL,GAAAA,CAAIM,KAAK,CAACC,IAAI,EAAE;gBACnB,OAAOP,GAAAA,CAAIQ,YAAY,CAAC,yBAAA,CAAA;AAC1B,YAAA;AAEA,YAAA,MAAMC,UAAU,MAAMR,MAAAA,CAAOC,EAAE,CAACC,KAAK,CAACJ,UAAU,EAAA;AAEhDC,YAAAA,GAAAA,CAAIU,IAAI,GAAG;gBACTC,IAAAA,EAAMF;AACR,aAAA;AACF,QAAA,CAAA,CAAE,OAAOG,KAAAA,EAAO;YACd,OAAOZ,GAAAA,CAAIa,mBAAmB,CAAC,yDAAA,CAAA;AACjC,QAAA;AACF,IAAA,CAAA;AAEA,IAAA,MAAMC,YAAWd,GAAY,EAAA;AAC3B,QAAA,IAAIC,OAAOC,EAAE,CAACC,KAAK,CAACC,SAAS,OAAO,KAAA,EAAO;AACzC,YAAA,OAAOJ,IAAIK,QAAQ,EAAA;AACrB,QAAA;QAEA,IAAI;AACF,YAAA,MAAMU,QAAQ,MAAMd,MAAAA,CAAOC,EAAE,CAACC,KAAK,CAACW,UAAU,EAAA;AAC9Cd,YAAAA,GAAAA,CAAIU,IAAI,GAAGK,KAAAA;AACb,QAAA,CAAA,CAAE,OAAOH,KAAAA,EAAO;YACd,OAAOZ,GAAAA,CAAIa,mBAAmB,CAC5B,8DAAA,CAAA;AAEJ,QAAA;AACF,IAAA,CAAA;AAEA,IAAA,MAAMG,oBAAmBhB,GAAY,EAAA;AACnC,QAAA,IAAIC,OAAOC,EAAE,CAACC,KAAK,CAACC,SAAS,OAAO,KAAA,EAAO;AACzC,YAAA,OAAOJ,IAAIK,QAAQ,EAAA;AACrB,QAAA;QAEA,IAAI;AACF,YAAA,MAAMY,kBAAkB,MAAMhB,MAAAA,CAAOC,EAAE,CAACC,KAAK,CAACa,kBAAkB,EAAA;AAEhEhB,YAAAA,GAAAA,CAAIU,IAAI,GAAG;gBACTC,IAAAA,EAAMM;AACR,aAAA;AACF,QAAA,CAAA,CAAE,OAAOL,KAAAA,EAAO;AACdX,YAAAA,MAAAA,CAAOiB,GAAG,CAACN,KAAK,CAAC,kCAAA,EAAoCA,KAAAA,CAAAA;YACrD,OAAOZ,GAAAA,CAAIa,mBAAmB,CAC5B,kEAAA,CAAA;AAEJ,QAAA;AACF,IAAA;AACF,CAAA;;;;"}
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  var aiRoutes = {
4
- type: 'admin',
5
4
  routes: [
6
5
  {
7
6
  method: 'GET',
@@ -26,7 +25,7 @@ var aiRoutes = {
26
25
  {
27
26
  method: 'GET',
28
27
  path: '/ai-feature-config',
29
- handler: 'ai.getAIFeatureConfig',
28
+ handler: 'ai.getAiFeatureConfig',
30
29
  config: {
31
30
  policies: [
32
31
  'admin::isAuthenticatedAdmin'
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.js","sources":["../../../../../../server/src/ai/routes/ai.ts"],"sourcesContent":["export default {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n path: '/ai-usage',\n handler: 'ai.getAiUsage',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-token',\n handler: 'ai.getAiToken',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-feature-config',\n handler: 'ai.getAiFeatureConfig',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n"],"names":["routes","method","path","handler","config","policies"],"mappings":";;AAAA,eAAe;IAEbA,MAAAA,EAAQ;AACN,QAAA;YACEC,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,WAAA;YACNC,OAAAA,EAAS,eAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,WAAA;YACNC,OAAAA,EAAS,eAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,oBAAA;YACNC,OAAAA,EAAS,uBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF;AACD;AACH,CAAA;;;;"}
@@ -1,5 +1,4 @@
1
1
  var aiRoutes = {
2
- type: 'admin',
3
2
  routes: [
4
3
  {
5
4
  method: 'GET',
@@ -24,7 +23,7 @@ var aiRoutes = {
24
23
  {
25
24
  method: 'GET',
26
25
  path: '/ai-feature-config',
27
- handler: 'ai.getAIFeatureConfig',
26
+ handler: 'ai.getAiFeatureConfig',
28
27
  config: {
29
28
  policies: [
30
29
  'admin::isAuthenticatedAdmin'
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.mjs","sources":["../../../../../../server/src/ai/routes/ai.ts"],"sourcesContent":["export default {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n path: '/ai-usage',\n handler: 'ai.getAiUsage',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-token',\n handler: 'ai.getAiToken',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/ai-feature-config',\n handler: 'ai.getAiFeatureConfig',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n"],"names":["routes","method","path","handler","config","policies"],"mappings":"AAAA,eAAe;IAEbA,MAAAA,EAAQ;AACN,QAAA;YACEC,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,WAAA;YACNC,OAAAA,EAAS,eAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,WAAA;YACNC,OAAAA,EAAS,eAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF,SAAA;AACA,QAAA;YACEJ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,oBAAA;YACNC,OAAAA,EAAS,uBAAA;YACTC,MAAAA,EAAQ;gBACNC,QAAAA,EAAU;AAAC,oBAAA;AAA8B;AAC3C;AACF;AACD;AACH,CAAA;;;;"}
@@ -4,42 +4,70 @@ var crypto = require('crypto');
4
4
  var fs = require('fs');
5
5
  var path = require('path');
6
6
 
7
- /**
8
- * In-memory cache for AI tokens
9
- * Key format: `${projectId}:${userId}`
10
- */ const aiTokenCache = new Map();
11
- const createAIContainer = ({ strapi })=>{
12
- const getAIFeatureConfig = async ()=>{
7
+ const createAiAdminService = ({ strapi })=>{
8
+ /**
9
+ * In-memory cache for AI tokens
10
+ * Key format: `${projectId}:${userId}`
11
+ */ const aiTokenCache = new Map();
12
+ const isEnabled = ()=>{
13
+ const configEnabled = strapi.config.get('admin.ai.enabled', true) === true;
14
+ const licenseEnabled = strapi.ee?.features?.isEnabled('cms-ai') === true;
15
+ return configEnabled && licenseEnabled;
16
+ };
17
+ const getAiFeatureConfig = async ()=>{
18
+ if (!isEnabled()) {
19
+ return {
20
+ isAiI18nConfigured: false,
21
+ isAiMediaLibraryConfigured: false
22
+ };
23
+ }
13
24
  const i18nSettings = await strapi.plugin('i18n').service('settings').getSettings();
14
25
  const uploadSettings = await strapi.plugin('upload').service('upload').getSettings();
15
26
  return {
16
- isAIi18nConfigured: Boolean(i18nSettings?.aiLocalizations),
17
- isAIMediaLibraryConfigured: Boolean(uploadSettings?.aiMetadata)
27
+ isAiI18nConfigured: Boolean(i18nSettings?.aiLocalizations),
28
+ isAiMediaLibraryConfigured: Boolean(uploadSettings?.aiMetadata)
18
29
  };
19
30
  };
20
- const getAiToken = async ()=>{
21
- const ERROR_PREFIX = 'AI token request failed:';
22
- // Check if EE features are enabled first
31
+ /**
32
+ * Resolves the shared context required by both getAiToken and getAiUsage:
33
+ * EE license, project ID, and AI server URL.
34
+ */ const resolveAiContext = (errorPrefix)=>{
35
+ if (!isEnabled()) {
36
+ strapi.log.error(`${errorPrefix} AI is not enabled`);
37
+ throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);
38
+ }
23
39
  if (!strapi.ee?.isEE) {
24
- strapi.log.error(`${ERROR_PREFIX} Enterprise Edition features are not enabled`);
25
- throw new Error('AI token request failed. Check server logs for details.');
40
+ strapi.log.error(`${errorPrefix} Enterprise Edition features are not enabled`);
41
+ throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);
26
42
  }
27
- // Get the EE license
28
- // First try environment variable, then try reading from file
29
43
  let eeLicense = process.env.STRAPI_LICENSE;
30
44
  if (!eeLicense) {
31
45
  try {
32
46
  const licensePath = path.join(strapi.dirs.app.root, 'license.txt');
33
47
  eeLicense = fs.readFileSync(licensePath).toString();
34
- } catch (error) {
48
+ } catch {
35
49
  // License file doesn't exist or can't be read
36
50
  }
37
51
  }
38
52
  if (!eeLicense) {
39
- strapi.log.error(`${ERROR_PREFIX} No EE license found. Please ensure STRAPI_LICENSE environment variable is set or license.txt file exists.`);
40
- throw new Error('AI token request failed. Check server logs for details.');
53
+ strapi.log.error(`${errorPrefix} No EE license found. Please ensure STRAPI_LICENSE environment variable is set or license.txt file exists.`);
54
+ throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);
55
+ }
56
+ const projectId = strapi.config.get('uuid');
57
+ if (!projectId) {
58
+ strapi.log.error(`${errorPrefix} Project ID not configured`);
59
+ throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);
41
60
  }
42
61
  const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';
62
+ return {
63
+ eeLicense,
64
+ projectId,
65
+ aiServerUrl
66
+ };
67
+ };
68
+ const getAiToken = async ()=>{
69
+ const ERROR_PREFIX = 'AI token request failed:';
70
+ const { eeLicense, projectId, aiServerUrl } = resolveAiContext(ERROR_PREFIX);
43
71
  // Get the current user
44
72
  const user = strapi.requestContext.get()?.state?.user;
45
73
  if (!user) {
@@ -48,18 +76,12 @@ const createAIContainer = ({ strapi })=>{
48
76
  }
49
77
  // Create a secure user identifier using only user ID
50
78
  const userIdentifier = user.id.toString();
51
- // Get project ID
52
- const projectId = strapi.config.get('uuid');
53
- if (!projectId) {
54
- strapi.log.error(`${ERROR_PREFIX} Project ID not configured`);
55
- throw new Error('AI token request failed. Check server logs for details.');
56
- }
57
79
  // Check cache for existing valid token
58
80
  const cacheKey = `${projectId}:${userIdentifier}`;
59
81
  const cachedToken = aiTokenCache.get(cacheKey);
60
82
  if (cachedToken) {
61
83
  const now = Date.now();
62
- // Check if token is still valid (with buffer so it has time to to be used)
84
+ // Check if token is still valid (with buffer so it has time to be used)
63
85
  const bufferMs = 2 * 60 * 1000; // 2 minutes
64
86
  if (cachedToken.expiresAtMs && cachedToken.expiresAtMs - bufferMs > now) {
65
87
  strapi.log.info('Using cached AI token');
@@ -73,13 +95,10 @@ const createAIContainer = ({ strapi })=>{
73
95
  }
74
96
  strapi.log.http('Contacting AI Server for token generation');
75
97
  try {
76
- // Call the AI server's getAiJWT endpoint
77
98
  const response = await fetch(`${aiServerUrl}/auth/getAiJWT`, {
78
99
  method: 'POST',
79
100
  headers: {
80
101
  'Content-Type': 'application/json',
81
- // No authorization header needed for public endpoint
82
- // Add request ID for tracing
83
102
  'X-Request-Id': crypto.randomUUID()
84
103
  },
85
104
  body: JSON.stringify({
@@ -132,7 +151,6 @@ const createAIContainer = ({ strapi })=>{
132
151
  expiresAtMs
133
152
  });
134
153
  }
135
- // Return the AI JWT with metadata
136
154
  // Note: Token expires in 1 hour, client should handle refresh
137
155
  return {
138
156
  token: data.jwt,
@@ -146,11 +164,68 @@ const createAIContainer = ({ strapi })=>{
146
164
  throw fetchError;
147
165
  }
148
166
  };
167
+ const getAiUsage = async ()=>{
168
+ const ERROR_PREFIX = 'AI usage data request failed:';
169
+ const { eeLicense, projectId, aiServerUrl } = resolveAiContext(ERROR_PREFIX);
170
+ strapi.log.http('Contacting AI Server for usage data');
171
+ try {
172
+ const response = await fetch(`${aiServerUrl}/cms/ai-data`, {
173
+ method: 'POST',
174
+ headers: {
175
+ 'Content-Type': 'application/json',
176
+ 'X-Request-Id': crypto.randomUUID()
177
+ },
178
+ body: JSON.stringify({
179
+ eeKey: eeLicense,
180
+ projectId
181
+ })
182
+ });
183
+ if (!response.ok) {
184
+ let errorData;
185
+ let errorText;
186
+ try {
187
+ errorText = await response.text();
188
+ errorData = JSON.parse(errorText);
189
+ } catch {
190
+ errorData = {
191
+ error: errorText || 'Failed to parse error response'
192
+ };
193
+ }
194
+ strapi.log.error(`${ERROR_PREFIX} ${errorData?.error || 'Unknown error'}`, {
195
+ status: response.status,
196
+ statusText: response.statusText,
197
+ error: errorData,
198
+ errorText,
199
+ projectId
200
+ });
201
+ throw new Error('AI usage data request failed. Check server logs for details.');
202
+ }
203
+ let data;
204
+ try {
205
+ data = await response.json();
206
+ } catch (parseError) {
207
+ strapi.log.error(`${ERROR_PREFIX} Failed to parse AI server response`, parseError);
208
+ throw new Error('AI usage data request failed. Check server logs for details.');
209
+ }
210
+ return {
211
+ ...data.data,
212
+ subscription: data.subscription
213
+ };
214
+ } catch (fetchError) {
215
+ if (fetchError instanceof Error && fetchError.name === 'AbortError') {
216
+ strapi.log.error(`${ERROR_PREFIX} Request to AI server timed out`);
217
+ throw new Error('AI usage data request failed. Check server logs for details.');
218
+ }
219
+ throw fetchError;
220
+ }
221
+ };
149
222
  return {
150
- getAIFeatureConfig,
151
- getAiToken
223
+ isEnabled,
224
+ getAiFeatureConfig,
225
+ getAiToken,
226
+ getAiUsage
152
227
  };
153
228
  };
154
229
 
155
- exports.createAIContainer = createAIContainer;
230
+ exports.createAiAdminService = createAiAdminService;
156
231
  //# sourceMappingURL=ai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.js","sources":["../../../../../../server/src/ai/services/ai.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport crypto from 'crypto';\nimport fs from 'fs';\nimport path from 'path';\nimport { AdminUser } from '../../../../shared/contracts/shared';\n\nconst createAiAdminService = ({ strapi }: { strapi: Core.Strapi }) => {\n /**\n * In-memory cache for AI tokens\n * Key format: `${projectId}:${userId}`\n */\n const aiTokenCache = new Map<\n string,\n {\n token: string;\n expiresAt?: string;\n expiresAtMs?: number;\n }\n >();\n\n const isEnabled = (): boolean => {\n const configEnabled = strapi.config.get('admin.ai.enabled', true) === true;\n const licenseEnabled = strapi.ee?.features?.isEnabled('cms-ai') === true;\n return configEnabled && licenseEnabled;\n };\n\n const getAiFeatureConfig = async () => {\n if (!isEnabled()) {\n return {\n isAiI18nConfigured: false,\n isAiMediaLibraryConfigured: false,\n };\n }\n\n const i18nSettings = await strapi.plugin('i18n').service('settings').getSettings();\n const uploadSettings = await strapi.plugin('upload').service('upload').getSettings();\n\n return {\n isAiI18nConfigured: Boolean(i18nSettings?.aiLocalizations),\n isAiMediaLibraryConfigured: Boolean(uploadSettings?.aiMetadata),\n };\n };\n\n /**\n * Resolves the shared context required by both getAiToken and getAiUsage:\n * EE license, project ID, and AI server URL.\n */\n const resolveAiContext = (errorPrefix: string) => {\n if (!isEnabled()) {\n strapi.log.error(`${errorPrefix} AI is not enabled`);\n throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);\n }\n\n if (!strapi.ee?.isEE) {\n strapi.log.error(`${errorPrefix} Enterprise Edition features are not enabled`);\n throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);\n }\n\n let eeLicense = process.env.STRAPI_LICENSE;\n\n if (!eeLicense) {\n try {\n const licensePath = path.join(strapi.dirs.app.root, 'license.txt');\n eeLicense = fs.readFileSync(licensePath).toString();\n } catch {\n // License file doesn't exist or can't be read\n }\n }\n\n if (!eeLicense) {\n strapi.log.error(\n `${errorPrefix} No EE license found. Please ensure STRAPI_LICENSE environment variable is set or license.txt file exists.`\n );\n throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);\n }\n\n const projectId = strapi.config.get('uuid');\n if (!projectId) {\n strapi.log.error(`${errorPrefix} Project ID not configured`);\n throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);\n }\n\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n\n return { eeLicense, projectId, aiServerUrl };\n };\n\n const getAiToken = async () => {\n const ERROR_PREFIX = 'AI token request failed:';\n\n const { eeLicense, projectId, aiServerUrl } = resolveAiContext(ERROR_PREFIX);\n\n // Get the current user\n const user = strapi.requestContext.get()?.state?.user as AdminUser | undefined;\n if (!user) {\n strapi.log.error(`${ERROR_PREFIX} No authenticated user in request context`);\n throw new Error('AI token request failed. Check server logs for details.');\n }\n\n // Create a secure user identifier using only user ID\n const userIdentifier = user.id.toString();\n\n // Check cache for existing valid token\n const cacheKey = `${projectId}:${userIdentifier}`;\n const cachedToken = aiTokenCache.get(cacheKey);\n\n if (cachedToken) {\n const now = Date.now();\n // Check if token is still valid (with buffer so it has time to be used)\n const bufferMs = 2 * 60 * 1000; // 2 minutes\n\n if (cachedToken.expiresAtMs && cachedToken.expiresAtMs - bufferMs > now) {\n strapi.log.info('Using cached AI token');\n\n return {\n token: cachedToken.token,\n expiresAt: cachedToken.expiresAt,\n };\n }\n\n // Token expired or will expire soon, remove from cache\n aiTokenCache.delete(cacheKey);\n }\n\n strapi.log.http('Contacting AI Server for token generation');\n\n try {\n const response = await fetch(`${aiServerUrl}/auth/getAiJWT`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Request-Id': crypto.randomUUID(),\n },\n body: JSON.stringify({\n eeLicense,\n userIdentifier,\n projectId,\n }),\n });\n\n if (!response.ok) {\n let errorData;\n let errorText;\n try {\n errorText = await response.text();\n errorData = JSON.parse(errorText);\n } catch {\n errorData = { error: errorText || 'Failed to parse error response' };\n }\n\n strapi.log.error(`${ERROR_PREFIX} ${errorData?.error || 'Unknown error'}`, {\n status: response.status,\n statusText: response.statusText,\n error: errorData,\n errorText,\n projectId,\n });\n\n throw new Error('AI token request failed. Check server logs for details.');\n }\n\n let data;\n try {\n data = (await response.json()) as {\n jwt: string;\n expiresAt?: string;\n };\n } catch (parseError) {\n strapi.log.error(`${ERROR_PREFIX} Failed to parse AI server response`, parseError);\n throw new Error('AI token request failed. Check server logs for details.');\n }\n\n if (!data.jwt) {\n strapi.log.error(`${ERROR_PREFIX} Invalid response: missing JWT token`);\n throw new Error('AI token request failed. Check server logs for details.');\n }\n\n strapi.log.info('AI token generated successfully', {\n userId: user.id,\n expiresAt: data.expiresAt,\n });\n\n // Cache the token if it has an expiration time\n if (data.expiresAt) {\n const expiresAtMs = new Date(data.expiresAt).getTime();\n aiTokenCache.set(cacheKey, {\n token: data.jwt,\n expiresAt: data.expiresAt,\n expiresAtMs,\n });\n }\n\n // Note: Token expires in 1 hour, client should handle refresh\n return {\n token: data.jwt,\n expiresAt: data.expiresAt,\n };\n } catch (fetchError) {\n if (fetchError instanceof Error && fetchError.name === 'AbortError') {\n strapi.log.error(`${ERROR_PREFIX} Request to AI server timed out`);\n throw new Error('AI token request failed. Check server logs for details.');\n }\n\n throw fetchError;\n }\n };\n\n const getAiUsage = async () => {\n const ERROR_PREFIX = 'AI usage data request failed:';\n\n const { eeLicense, projectId, aiServerUrl } = resolveAiContext(ERROR_PREFIX);\n\n strapi.log.http('Contacting AI Server for usage data');\n\n try {\n const response = await fetch(`${aiServerUrl}/cms/ai-data`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Request-Id': crypto.randomUUID(),\n },\n body: JSON.stringify({\n eeKey: eeLicense,\n projectId,\n }),\n });\n\n if (!response.ok) {\n let errorData;\n let errorText;\n try {\n errorText = await response.text();\n errorData = JSON.parse(errorText);\n } catch {\n errorData = { error: errorText || 'Failed to parse error response' };\n }\n\n strapi.log.error(`${ERROR_PREFIX} ${errorData?.error || 'Unknown error'}`, {\n status: response.status,\n statusText: response.statusText,\n error: errorData,\n errorText,\n projectId,\n });\n\n throw new Error('AI usage data request failed. Check server logs for details.');\n }\n\n let data;\n try {\n data = (await response.json()) as {\n data: { cmsAiCreditsUsed: number };\n subscription: {\n subscriptionId: string;\n planPriceId: string;\n subscriptionStatus: string;\n isActiveSubscription: boolean;\n cmsAiEnabled: boolean;\n cmsAiCreditsBase: number;\n cmsAiCreditsMaxUsage: number;\n currentTermStart: string;\n currentTermEnd: string;\n };\n };\n } catch (parseError) {\n strapi.log.error(`${ERROR_PREFIX} Failed to parse AI server response`, parseError);\n throw new Error('AI usage data request failed. Check server logs for details.');\n }\n\n return {\n ...data.data,\n subscription: data.subscription,\n };\n } catch (fetchError) {\n if (fetchError instanceof Error && fetchError.name === 'AbortError') {\n strapi.log.error(`${ERROR_PREFIX} Request to AI server timed out`);\n throw new Error('AI usage data request failed. Check server logs for details.');\n }\n\n throw fetchError;\n }\n };\n\n return {\n isEnabled,\n getAiFeatureConfig,\n getAiToken,\n getAiUsage,\n };\n};\n\nexport { createAiAdminService };\n"],"names":["createAiAdminService","strapi","aiTokenCache","Map","isEnabled","configEnabled","config","get","licenseEnabled","ee","features","getAiFeatureConfig","isAiI18nConfigured","isAiMediaLibraryConfigured","i18nSettings","plugin","service","getSettings","uploadSettings","Boolean","aiLocalizations","aiMetadata","resolveAiContext","errorPrefix","log","error","Error","replace","isEE","eeLicense","process","env","STRAPI_LICENSE","licensePath","path","join","dirs","app","root","fs","readFileSync","toString","projectId","aiServerUrl","STRAPI_AI_URL","getAiToken","ERROR_PREFIX","user","requestContext","state","userIdentifier","id","cacheKey","cachedToken","now","Date","bufferMs","expiresAtMs","info","token","expiresAt","delete","http","response","fetch","method","headers","crypto","randomUUID","body","JSON","stringify","ok","errorData","errorText","text","parse","status","statusText","data","json","parseError","jwt","userId","getTime","set","fetchError","name","getAiUsage","eeKey","subscription"],"mappings":"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"}
@@ -2,42 +2,70 @@ import crypto from 'crypto';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
 
5
- /**
6
- * In-memory cache for AI tokens
7
- * Key format: `${projectId}:${userId}`
8
- */ const aiTokenCache = new Map();
9
- const createAIContainer = ({ strapi })=>{
10
- const getAIFeatureConfig = async ()=>{
5
+ const createAiAdminService = ({ strapi })=>{
6
+ /**
7
+ * In-memory cache for AI tokens
8
+ * Key format: `${projectId}:${userId}`
9
+ */ const aiTokenCache = new Map();
10
+ const isEnabled = ()=>{
11
+ const configEnabled = strapi.config.get('admin.ai.enabled', true) === true;
12
+ const licenseEnabled = strapi.ee?.features?.isEnabled('cms-ai') === true;
13
+ return configEnabled && licenseEnabled;
14
+ };
15
+ const getAiFeatureConfig = async ()=>{
16
+ if (!isEnabled()) {
17
+ return {
18
+ isAiI18nConfigured: false,
19
+ isAiMediaLibraryConfigured: false
20
+ };
21
+ }
11
22
  const i18nSettings = await strapi.plugin('i18n').service('settings').getSettings();
12
23
  const uploadSettings = await strapi.plugin('upload').service('upload').getSettings();
13
24
  return {
14
- isAIi18nConfigured: Boolean(i18nSettings?.aiLocalizations),
15
- isAIMediaLibraryConfigured: Boolean(uploadSettings?.aiMetadata)
25
+ isAiI18nConfigured: Boolean(i18nSettings?.aiLocalizations),
26
+ isAiMediaLibraryConfigured: Boolean(uploadSettings?.aiMetadata)
16
27
  };
17
28
  };
18
- const getAiToken = async ()=>{
19
- const ERROR_PREFIX = 'AI token request failed:';
20
- // Check if EE features are enabled first
29
+ /**
30
+ * Resolves the shared context required by both getAiToken and getAiUsage:
31
+ * EE license, project ID, and AI server URL.
32
+ */ const resolveAiContext = (errorPrefix)=>{
33
+ if (!isEnabled()) {
34
+ strapi.log.error(`${errorPrefix} AI is not enabled`);
35
+ throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);
36
+ }
21
37
  if (!strapi.ee?.isEE) {
22
- strapi.log.error(`${ERROR_PREFIX} Enterprise Edition features are not enabled`);
23
- throw new Error('AI token request failed. Check server logs for details.');
38
+ strapi.log.error(`${errorPrefix} Enterprise Edition features are not enabled`);
39
+ throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);
24
40
  }
25
- // Get the EE license
26
- // First try environment variable, then try reading from file
27
41
  let eeLicense = process.env.STRAPI_LICENSE;
28
42
  if (!eeLicense) {
29
43
  try {
30
44
  const licensePath = path.join(strapi.dirs.app.root, 'license.txt');
31
45
  eeLicense = fs.readFileSync(licensePath).toString();
32
- } catch (error) {
46
+ } catch {
33
47
  // License file doesn't exist or can't be read
34
48
  }
35
49
  }
36
50
  if (!eeLicense) {
37
- strapi.log.error(`${ERROR_PREFIX} No EE license found. Please ensure STRAPI_LICENSE environment variable is set or license.txt file exists.`);
38
- throw new Error('AI token request failed. Check server logs for details.');
51
+ strapi.log.error(`${errorPrefix} No EE license found. Please ensure STRAPI_LICENSE environment variable is set or license.txt file exists.`);
52
+ throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);
53
+ }
54
+ const projectId = strapi.config.get('uuid');
55
+ if (!projectId) {
56
+ strapi.log.error(`${errorPrefix} Project ID not configured`);
57
+ throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);
39
58
  }
40
59
  const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';
60
+ return {
61
+ eeLicense,
62
+ projectId,
63
+ aiServerUrl
64
+ };
65
+ };
66
+ const getAiToken = async ()=>{
67
+ const ERROR_PREFIX = 'AI token request failed:';
68
+ const { eeLicense, projectId, aiServerUrl } = resolveAiContext(ERROR_PREFIX);
41
69
  // Get the current user
42
70
  const user = strapi.requestContext.get()?.state?.user;
43
71
  if (!user) {
@@ -46,18 +74,12 @@ const createAIContainer = ({ strapi })=>{
46
74
  }
47
75
  // Create a secure user identifier using only user ID
48
76
  const userIdentifier = user.id.toString();
49
- // Get project ID
50
- const projectId = strapi.config.get('uuid');
51
- if (!projectId) {
52
- strapi.log.error(`${ERROR_PREFIX} Project ID not configured`);
53
- throw new Error('AI token request failed. Check server logs for details.');
54
- }
55
77
  // Check cache for existing valid token
56
78
  const cacheKey = `${projectId}:${userIdentifier}`;
57
79
  const cachedToken = aiTokenCache.get(cacheKey);
58
80
  if (cachedToken) {
59
81
  const now = Date.now();
60
- // Check if token is still valid (with buffer so it has time to to be used)
82
+ // Check if token is still valid (with buffer so it has time to be used)
61
83
  const bufferMs = 2 * 60 * 1000; // 2 minutes
62
84
  if (cachedToken.expiresAtMs && cachedToken.expiresAtMs - bufferMs > now) {
63
85
  strapi.log.info('Using cached AI token');
@@ -71,13 +93,10 @@ const createAIContainer = ({ strapi })=>{
71
93
  }
72
94
  strapi.log.http('Contacting AI Server for token generation');
73
95
  try {
74
- // Call the AI server's getAiJWT endpoint
75
96
  const response = await fetch(`${aiServerUrl}/auth/getAiJWT`, {
76
97
  method: 'POST',
77
98
  headers: {
78
99
  'Content-Type': 'application/json',
79
- // No authorization header needed for public endpoint
80
- // Add request ID for tracing
81
100
  'X-Request-Id': crypto.randomUUID()
82
101
  },
83
102
  body: JSON.stringify({
@@ -130,7 +149,6 @@ const createAIContainer = ({ strapi })=>{
130
149
  expiresAtMs
131
150
  });
132
151
  }
133
- // Return the AI JWT with metadata
134
152
  // Note: Token expires in 1 hour, client should handle refresh
135
153
  return {
136
154
  token: data.jwt,
@@ -144,11 +162,68 @@ const createAIContainer = ({ strapi })=>{
144
162
  throw fetchError;
145
163
  }
146
164
  };
165
+ const getAiUsage = async ()=>{
166
+ const ERROR_PREFIX = 'AI usage data request failed:';
167
+ const { eeLicense, projectId, aiServerUrl } = resolveAiContext(ERROR_PREFIX);
168
+ strapi.log.http('Contacting AI Server for usage data');
169
+ try {
170
+ const response = await fetch(`${aiServerUrl}/cms/ai-data`, {
171
+ method: 'POST',
172
+ headers: {
173
+ 'Content-Type': 'application/json',
174
+ 'X-Request-Id': crypto.randomUUID()
175
+ },
176
+ body: JSON.stringify({
177
+ eeKey: eeLicense,
178
+ projectId
179
+ })
180
+ });
181
+ if (!response.ok) {
182
+ let errorData;
183
+ let errorText;
184
+ try {
185
+ errorText = await response.text();
186
+ errorData = JSON.parse(errorText);
187
+ } catch {
188
+ errorData = {
189
+ error: errorText || 'Failed to parse error response'
190
+ };
191
+ }
192
+ strapi.log.error(`${ERROR_PREFIX} ${errorData?.error || 'Unknown error'}`, {
193
+ status: response.status,
194
+ statusText: response.statusText,
195
+ error: errorData,
196
+ errorText,
197
+ projectId
198
+ });
199
+ throw new Error('AI usage data request failed. Check server logs for details.');
200
+ }
201
+ let data;
202
+ try {
203
+ data = await response.json();
204
+ } catch (parseError) {
205
+ strapi.log.error(`${ERROR_PREFIX} Failed to parse AI server response`, parseError);
206
+ throw new Error('AI usage data request failed. Check server logs for details.');
207
+ }
208
+ return {
209
+ ...data.data,
210
+ subscription: data.subscription
211
+ };
212
+ } catch (fetchError) {
213
+ if (fetchError instanceof Error && fetchError.name === 'AbortError') {
214
+ strapi.log.error(`${ERROR_PREFIX} Request to AI server timed out`);
215
+ throw new Error('AI usage data request failed. Check server logs for details.');
216
+ }
217
+ throw fetchError;
218
+ }
219
+ };
147
220
  return {
148
- getAIFeatureConfig,
149
- getAiToken
221
+ isEnabled,
222
+ getAiFeatureConfig,
223
+ getAiToken,
224
+ getAiUsage
150
225
  };
151
226
  };
152
227
 
153
- export { createAIContainer };
228
+ export { createAiAdminService };
154
229
  //# sourceMappingURL=ai.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.mjs","sources":["../../../../../../server/src/ai/services/ai.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport crypto from 'crypto';\nimport fs from 'fs';\nimport path from 'path';\nimport { AdminUser } from '../../../../shared/contracts/shared';\n\nconst createAiAdminService = ({ strapi }: { strapi: Core.Strapi }) => {\n /**\n * In-memory cache for AI tokens\n * Key format: `${projectId}:${userId}`\n */\n const aiTokenCache = new Map<\n string,\n {\n token: string;\n expiresAt?: string;\n expiresAtMs?: number;\n }\n >();\n\n const isEnabled = (): boolean => {\n const configEnabled = strapi.config.get('admin.ai.enabled', true) === true;\n const licenseEnabled = strapi.ee?.features?.isEnabled('cms-ai') === true;\n return configEnabled && licenseEnabled;\n };\n\n const getAiFeatureConfig = async () => {\n if (!isEnabled()) {\n return {\n isAiI18nConfigured: false,\n isAiMediaLibraryConfigured: false,\n };\n }\n\n const i18nSettings = await strapi.plugin('i18n').service('settings').getSettings();\n const uploadSettings = await strapi.plugin('upload').service('upload').getSettings();\n\n return {\n isAiI18nConfigured: Boolean(i18nSettings?.aiLocalizations),\n isAiMediaLibraryConfigured: Boolean(uploadSettings?.aiMetadata),\n };\n };\n\n /**\n * Resolves the shared context required by both getAiToken and getAiUsage:\n * EE license, project ID, and AI server URL.\n */\n const resolveAiContext = (errorPrefix: string) => {\n if (!isEnabled()) {\n strapi.log.error(`${errorPrefix} AI is not enabled`);\n throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);\n }\n\n if (!strapi.ee?.isEE) {\n strapi.log.error(`${errorPrefix} Enterprise Edition features are not enabled`);\n throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);\n }\n\n let eeLicense = process.env.STRAPI_LICENSE;\n\n if (!eeLicense) {\n try {\n const licensePath = path.join(strapi.dirs.app.root, 'license.txt');\n eeLicense = fs.readFileSync(licensePath).toString();\n } catch {\n // License file doesn't exist or can't be read\n }\n }\n\n if (!eeLicense) {\n strapi.log.error(\n `${errorPrefix} No EE license found. Please ensure STRAPI_LICENSE environment variable is set or license.txt file exists.`\n );\n throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);\n }\n\n const projectId = strapi.config.get('uuid');\n if (!projectId) {\n strapi.log.error(`${errorPrefix} Project ID not configured`);\n throw new Error(`${errorPrefix.replace(/:$/, '')}. Check server logs for details.`);\n }\n\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n\n return { eeLicense, projectId, aiServerUrl };\n };\n\n const getAiToken = async () => {\n const ERROR_PREFIX = 'AI token request failed:';\n\n const { eeLicense, projectId, aiServerUrl } = resolveAiContext(ERROR_PREFIX);\n\n // Get the current user\n const user = strapi.requestContext.get()?.state?.user as AdminUser | undefined;\n if (!user) {\n strapi.log.error(`${ERROR_PREFIX} No authenticated user in request context`);\n throw new Error('AI token request failed. Check server logs for details.');\n }\n\n // Create a secure user identifier using only user ID\n const userIdentifier = user.id.toString();\n\n // Check cache for existing valid token\n const cacheKey = `${projectId}:${userIdentifier}`;\n const cachedToken = aiTokenCache.get(cacheKey);\n\n if (cachedToken) {\n const now = Date.now();\n // Check if token is still valid (with buffer so it has time to be used)\n const bufferMs = 2 * 60 * 1000; // 2 minutes\n\n if (cachedToken.expiresAtMs && cachedToken.expiresAtMs - bufferMs > now) {\n strapi.log.info('Using cached AI token');\n\n return {\n token: cachedToken.token,\n expiresAt: cachedToken.expiresAt,\n };\n }\n\n // Token expired or will expire soon, remove from cache\n aiTokenCache.delete(cacheKey);\n }\n\n strapi.log.http('Contacting AI Server for token generation');\n\n try {\n const response = await fetch(`${aiServerUrl}/auth/getAiJWT`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Request-Id': crypto.randomUUID(),\n },\n body: JSON.stringify({\n eeLicense,\n userIdentifier,\n projectId,\n }),\n });\n\n if (!response.ok) {\n let errorData;\n let errorText;\n try {\n errorText = await response.text();\n errorData = JSON.parse(errorText);\n } catch {\n errorData = { error: errorText || 'Failed to parse error response' };\n }\n\n strapi.log.error(`${ERROR_PREFIX} ${errorData?.error || 'Unknown error'}`, {\n status: response.status,\n statusText: response.statusText,\n error: errorData,\n errorText,\n projectId,\n });\n\n throw new Error('AI token request failed. Check server logs for details.');\n }\n\n let data;\n try {\n data = (await response.json()) as {\n jwt: string;\n expiresAt?: string;\n };\n } catch (parseError) {\n strapi.log.error(`${ERROR_PREFIX} Failed to parse AI server response`, parseError);\n throw new Error('AI token request failed. Check server logs for details.');\n }\n\n if (!data.jwt) {\n strapi.log.error(`${ERROR_PREFIX} Invalid response: missing JWT token`);\n throw new Error('AI token request failed. Check server logs for details.');\n }\n\n strapi.log.info('AI token generated successfully', {\n userId: user.id,\n expiresAt: data.expiresAt,\n });\n\n // Cache the token if it has an expiration time\n if (data.expiresAt) {\n const expiresAtMs = new Date(data.expiresAt).getTime();\n aiTokenCache.set(cacheKey, {\n token: data.jwt,\n expiresAt: data.expiresAt,\n expiresAtMs,\n });\n }\n\n // Note: Token expires in 1 hour, client should handle refresh\n return {\n token: data.jwt,\n expiresAt: data.expiresAt,\n };\n } catch (fetchError) {\n if (fetchError instanceof Error && fetchError.name === 'AbortError') {\n strapi.log.error(`${ERROR_PREFIX} Request to AI server timed out`);\n throw new Error('AI token request failed. Check server logs for details.');\n }\n\n throw fetchError;\n }\n };\n\n const getAiUsage = async () => {\n const ERROR_PREFIX = 'AI usage data request failed:';\n\n const { eeLicense, projectId, aiServerUrl } = resolveAiContext(ERROR_PREFIX);\n\n strapi.log.http('Contacting AI Server for usage data');\n\n try {\n const response = await fetch(`${aiServerUrl}/cms/ai-data`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Request-Id': crypto.randomUUID(),\n },\n body: JSON.stringify({\n eeKey: eeLicense,\n projectId,\n }),\n });\n\n if (!response.ok) {\n let errorData;\n let errorText;\n try {\n errorText = await response.text();\n errorData = JSON.parse(errorText);\n } catch {\n errorData = { error: errorText || 'Failed to parse error response' };\n }\n\n strapi.log.error(`${ERROR_PREFIX} ${errorData?.error || 'Unknown error'}`, {\n status: response.status,\n statusText: response.statusText,\n error: errorData,\n errorText,\n projectId,\n });\n\n throw new Error('AI usage data request failed. Check server logs for details.');\n }\n\n let data;\n try {\n data = (await response.json()) as {\n data: { cmsAiCreditsUsed: number };\n subscription: {\n subscriptionId: string;\n planPriceId: string;\n subscriptionStatus: string;\n isActiveSubscription: boolean;\n cmsAiEnabled: boolean;\n cmsAiCreditsBase: number;\n cmsAiCreditsMaxUsage: number;\n currentTermStart: string;\n currentTermEnd: string;\n };\n };\n } catch (parseError) {\n strapi.log.error(`${ERROR_PREFIX} Failed to parse AI server response`, parseError);\n throw new Error('AI usage data request failed. Check server logs for details.');\n }\n\n return {\n ...data.data,\n subscription: data.subscription,\n };\n } catch (fetchError) {\n if (fetchError instanceof Error && fetchError.name === 'AbortError') {\n strapi.log.error(`${ERROR_PREFIX} Request to AI server timed out`);\n throw new Error('AI usage data request failed. Check server logs for details.');\n }\n\n throw fetchError;\n }\n };\n\n return {\n isEnabled,\n getAiFeatureConfig,\n getAiToken,\n getAiUsage,\n };\n};\n\nexport { createAiAdminService };\n"],"names":["createAiAdminService","strapi","aiTokenCache","Map","isEnabled","configEnabled","config","get","licenseEnabled","ee","features","getAiFeatureConfig","isAiI18nConfigured","isAiMediaLibraryConfigured","i18nSettings","plugin","service","getSettings","uploadSettings","Boolean","aiLocalizations","aiMetadata","resolveAiContext","errorPrefix","log","error","Error","replace","isEE","eeLicense","process","env","STRAPI_LICENSE","licensePath","path","join","dirs","app","root","fs","readFileSync","toString","projectId","aiServerUrl","STRAPI_AI_URL","getAiToken","ERROR_PREFIX","user","requestContext","state","userIdentifier","id","cacheKey","cachedToken","now","Date","bufferMs","expiresAtMs","info","token","expiresAt","delete","http","response","fetch","method","headers","crypto","randomUUID","body","JSON","stringify","ok","errorData","errorText","text","parse","status","statusText","data","json","parseError","jwt","userId","getTime","set","fetchError","name","getAiUsage","eeKey","subscription"],"mappings":"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"}
@@ -11,6 +11,7 @@ var user = require('./user.js');
11
11
  var webhooks = require('./webhooks.js');
12
12
  var contentApi = require('./content-api.js');
13
13
  var homepage = require('./homepage.js');
14
+ var ai = require('../ai/controllers/ai.js');
14
15
 
15
16
  var controllers = {
16
17
  admin,
@@ -23,7 +24,8 @@ var controllers = {
23
24
  user,
24
25
  webhooks,
25
26
  'content-api': contentApi,
26
- homepage
27
+ homepage,
28
+ ai
27
29
  };
28
30
 
29
31
  module.exports = controllers;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../../server/src/controllers/index.ts"],"sourcesContent":["import type {} from 'koa-body';\n\nimport admin from './admin';\nimport apiToken from './api-token';\nimport authenticatedUser from './authenticated-user';\nimport authentication from './authentication';\nimport permission from './permission';\nimport role from './role';\nimport transfer from './transfer';\nimport user from './user';\nimport webhooks from './webhooks';\nimport contentApi from './content-api';\nimport homepage from './homepage';\n\nexport default {\n admin,\n 'api-token': apiToken,\n 'authenticated-user': authenticatedUser,\n authentication,\n permission,\n role,\n transfer,\n user,\n webhooks,\n 'content-api': contentApi,\n homepage,\n};\n"],"names":["admin","apiToken","authenticatedUser","authentication","permission","role","transfer","user","webhooks","contentApi","homepage"],"mappings":";;;;;;;;;;;;;;AAcA,kBAAe;AACbA,IAAAA,KAAAA;IACA,WAAA,EAAaC,QAAAA;IACb,oBAAA,EAAsBC,iBAAAA;AACtBC,IAAAA,cAAAA;AACAC,IAAAA,UAAAA;AACAC,IAAAA,IAAAA;AACAC,cAAAA,KAAAA;AACAC,IAAAA,IAAAA;AACAC,IAAAA,QAAAA;IACA,aAAA,EAAeC,UAAAA;AACfC,IAAAA;AACF,CAAA;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../../server/src/controllers/index.ts"],"sourcesContent":["import type {} from 'koa-body';\n\nimport admin from './admin';\nimport apiToken from './api-token';\nimport authenticatedUser from './authenticated-user';\nimport authentication from './authentication';\nimport permission from './permission';\nimport role from './role';\nimport transfer from './transfer';\nimport user from './user';\nimport webhooks from './webhooks';\nimport contentApi from './content-api';\nimport homepage from './homepage';\nimport ai from '../ai/controllers/ai';\n\nexport default {\n admin,\n 'api-token': apiToken,\n 'authenticated-user': authenticatedUser,\n authentication,\n permission,\n role,\n transfer,\n user,\n webhooks,\n 'content-api': contentApi,\n homepage,\n ai,\n};\n"],"names":["admin","apiToken","authenticatedUser","authentication","permission","role","transfer","user","webhooks","contentApi","homepage","ai"],"mappings":";;;;;;;;;;;;;;;AAeA,kBAAe;AACbA,IAAAA,KAAAA;IACA,WAAA,EAAaC,QAAAA;IACb,oBAAA,EAAsBC,iBAAAA;AACtBC,IAAAA,cAAAA;AACAC,IAAAA,UAAAA;AACAC,IAAAA,IAAAA;AACAC,cAAAA,KAAAA;AACAC,IAAAA,IAAAA;AACAC,IAAAA,QAAAA;IACA,aAAA,EAAeC,UAAAA;AACfC,IAAAA,QAAAA;AACAC,IAAAA;AACF,CAAA;;;;"}