@strapi/core 5.56.0 → 5.58.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 (377) hide show
  1. package/dist/Strapi.d.ts +29 -0
  2. package/dist/Strapi.d.ts.map +1 -1
  3. package/dist/Strapi.js +10 -3
  4. package/dist/Strapi.js.map +1 -1
  5. package/dist/Strapi.mjs +10 -3
  6. package/dist/Strapi.mjs.map +1 -1
  7. package/dist/configuration/get-dirs.js +2 -2
  8. package/dist/configuration/get-dirs.js.map +1 -1
  9. package/dist/configuration/get-dirs.mjs +2 -2
  10. package/dist/configuration/get-dirs.mjs.map +1 -1
  11. package/dist/configuration/index.d.ts +1 -2
  12. package/dist/configuration/index.d.ts.map +1 -1
  13. package/dist/configuration/index.js +1 -2
  14. package/dist/configuration/index.js.map +1 -1
  15. package/dist/configuration/index.mjs +2 -3
  16. package/dist/configuration/index.mjs.map +1 -1
  17. package/dist/core-api/controller/collection-type.js +3 -3
  18. package/dist/core-api/controller/collection-type.js.map +1 -1
  19. package/dist/core-api/controller/collection-type.mjs +1 -1
  20. package/dist/core-api/controller/collection-type.mjs.map +1 -1
  21. package/dist/core-api/controller/index.js +2 -2
  22. package/dist/core-api/controller/index.js.map +1 -1
  23. package/dist/core-api/controller/index.mjs +2 -2
  24. package/dist/core-api/controller/index.mjs.map +1 -1
  25. package/dist/core-api/controller/single-type.js +2 -2
  26. package/dist/core-api/controller/single-type.js.map +1 -1
  27. package/dist/core-api/controller/single-type.mjs +1 -1
  28. package/dist/core-api/controller/single-type.mjs.map +1 -1
  29. package/dist/core-api/controller/transform.d.ts +1 -4
  30. package/dist/core-api/controller/transform.d.ts.map +1 -1
  31. package/dist/core-api/controller/transform.js +8 -8
  32. package/dist/core-api/controller/transform.js.map +1 -1
  33. package/dist/core-api/controller/transform.mjs +5 -5
  34. package/dist/core-api/controller/transform.mjs.map +1 -1
  35. package/dist/core-api/routes/index.js +1 -1
  36. package/dist/core-api/routes/index.js.map +1 -1
  37. package/dist/core-api/routes/index.mjs +1 -1
  38. package/dist/core-api/routes/index.mjs.map +1 -1
  39. package/dist/core-api/service/pagination.js +9 -9
  40. package/dist/core-api/service/pagination.js.map +1 -1
  41. package/dist/core-api/service/pagination.mjs +7 -7
  42. package/dist/core-api/service/pagination.mjs.map +1 -1
  43. package/dist/domain/content-type/index.d.ts.map +1 -1
  44. package/dist/domain/content-type/index.js +1 -2
  45. package/dist/domain/content-type/index.js.map +1 -1
  46. package/dist/domain/content-type/index.mjs +1 -2
  47. package/dist/domain/content-type/index.mjs.map +1 -1
  48. package/dist/ee/entitlements.d.ts +44 -0
  49. package/dist/ee/entitlements.d.ts.map +1 -0
  50. package/dist/ee/entitlements.js +54 -0
  51. package/dist/ee/entitlements.js.map +1 -0
  52. package/dist/ee/entitlements.mjs +51 -0
  53. package/dist/ee/entitlements.mjs.map +1 -0
  54. package/dist/ee/index.d.ts +33 -0
  55. package/dist/ee/index.d.ts.map +1 -1
  56. package/dist/ee/index.js +74 -7
  57. package/dist/ee/index.js.map +1 -1
  58. package/dist/ee/index.mjs +74 -7
  59. package/dist/ee/index.mjs.map +1 -1
  60. package/dist/ee/license.d.ts +10 -0
  61. package/dist/ee/license.d.ts.map +1 -1
  62. package/dist/ee/license.js +25 -1
  63. package/dist/ee/license.js.map +1 -1
  64. package/dist/ee/license.mjs +25 -2
  65. package/dist/ee/license.mjs.map +1 -1
  66. package/dist/factories.d.ts.map +1 -1
  67. package/dist/factories.js +3 -2
  68. package/dist/factories.js.map +1 -1
  69. package/dist/factories.mjs +3 -2
  70. package/dist/factories.mjs.map +1 -1
  71. package/dist/index.js +1 -1
  72. package/dist/index.mjs +1 -1
  73. package/dist/loaders/apis.d.ts.map +1 -1
  74. package/dist/loaders/apis.js +1 -2
  75. package/dist/loaders/apis.js.map +1 -1
  76. package/dist/loaders/apis.mjs +1 -2
  77. package/dist/loaders/apis.mjs.map +1 -1
  78. package/dist/loaders/plugins/get-enabled-plugins.d.ts +1 -1
  79. package/dist/loaders/plugins/get-enabled-plugins.d.ts.map +1 -1
  80. package/dist/loaders/plugins/get-enabled-plugins.js +6 -5
  81. package/dist/loaders/plugins/get-enabled-plugins.js.map +1 -1
  82. package/dist/loaders/plugins/get-enabled-plugins.mjs +6 -5
  83. package/dist/loaders/plugins/get-enabled-plugins.mjs.map +1 -1
  84. package/dist/loaders/plugins/get-user-plugins-config.js +2 -2
  85. package/dist/loaders/plugins/get-user-plugins-config.js.map +1 -1
  86. package/dist/loaders/plugins/get-user-plugins-config.mjs +2 -2
  87. package/dist/loaders/plugins/get-user-plugins-config.mjs.map +1 -1
  88. package/dist/loaders/plugins/index.js +9 -12
  89. package/dist/loaders/plugins/index.js.map +1 -1
  90. package/dist/loaders/plugins/index.mjs +9 -12
  91. package/dist/loaders/plugins/index.mjs.map +1 -1
  92. package/dist/middlewares/body.js +2 -2
  93. package/dist/middlewares/body.js.map +1 -1
  94. package/dist/middlewares/body.mjs +2 -2
  95. package/dist/middlewares/body.mjs.map +1 -1
  96. package/dist/middlewares/public.js +2 -2
  97. package/dist/middlewares/public.js.map +1 -1
  98. package/dist/middlewares/public.mjs +2 -2
  99. package/dist/middlewares/public.mjs.map +1 -1
  100. package/dist/middlewares/responses.d.ts.map +1 -1
  101. package/dist/middlewares/responses.js +1 -3
  102. package/dist/middlewares/responses.js.map +1 -1
  103. package/dist/middlewares/responses.mjs +1 -3
  104. package/dist/middlewares/responses.mjs.map +1 -1
  105. package/dist/middlewares/security.d.ts.map +1 -1
  106. package/dist/middlewares/security.js +3 -3
  107. package/dist/middlewares/security.js.map +1 -1
  108. package/dist/middlewares/security.mjs +3 -3
  109. package/dist/middlewares/security.mjs.map +1 -1
  110. package/dist/middlewares/session.js +2 -2
  111. package/dist/middlewares/session.js.map +1 -1
  112. package/dist/middlewares/session.mjs +2 -2
  113. package/dist/middlewares/session.mjs.map +1 -1
  114. package/dist/migrations/database/5.0.0-discard-drafts.d.ts.map +1 -1
  115. package/dist/migrations/database/5.0.0-discard-drafts.js +1 -2
  116. package/dist/migrations/database/5.0.0-discard-drafts.js.map +1 -1
  117. package/dist/migrations/database/5.0.0-discard-drafts.mjs +1 -2
  118. package/dist/migrations/database/5.0.0-discard-drafts.mjs.map +1 -1
  119. package/dist/migrations/i18n.d.ts.map +1 -1
  120. package/dist/migrations/i18n.js +6 -4
  121. package/dist/migrations/i18n.js.map +1 -1
  122. package/dist/migrations/i18n.mjs +6 -4
  123. package/dist/migrations/i18n.mjs.map +1 -1
  124. package/dist/package.json.js +16 -16
  125. package/dist/package.json.mjs +16 -16
  126. package/dist/registries/apis.js +2 -2
  127. package/dist/registries/apis.js.map +1 -1
  128. package/dist/registries/apis.mjs +2 -2
  129. package/dist/registries/apis.mjs.map +1 -1
  130. package/dist/registries/components.js +2 -2
  131. package/dist/registries/components.js.map +1 -1
  132. package/dist/registries/components.mjs +2 -2
  133. package/dist/registries/components.mjs.map +1 -1
  134. package/dist/registries/content-types.d.ts +1 -1
  135. package/dist/registries/content-types.js +3 -3
  136. package/dist/registries/content-types.js.map +1 -1
  137. package/dist/registries/content-types.mjs +3 -3
  138. package/dist/registries/content-types.mjs.map +1 -1
  139. package/dist/registries/controllers.js +3 -3
  140. package/dist/registries/controllers.js.map +1 -1
  141. package/dist/registries/controllers.mjs +3 -3
  142. package/dist/registries/controllers.mjs.map +1 -1
  143. package/dist/registries/custom-fields.js +4 -4
  144. package/dist/registries/custom-fields.js.map +1 -1
  145. package/dist/registries/custom-fields.mjs +4 -4
  146. package/dist/registries/custom-fields.mjs.map +1 -1
  147. package/dist/registries/hooks.d.ts +1 -1
  148. package/dist/registries/hooks.js +2 -2
  149. package/dist/registries/hooks.js.map +1 -1
  150. package/dist/registries/hooks.mjs +2 -2
  151. package/dist/registries/hooks.mjs.map +1 -1
  152. package/dist/registries/middlewares.d.ts +1 -1
  153. package/dist/registries/middlewares.js +3 -3
  154. package/dist/registries/middlewares.js.map +1 -1
  155. package/dist/registries/middlewares.mjs +3 -3
  156. package/dist/registries/middlewares.mjs.map +1 -1
  157. package/dist/registries/modules.d.ts +1 -4
  158. package/dist/registries/modules.d.ts.map +1 -1
  159. package/dist/registries/modules.js +3 -3
  160. package/dist/registries/modules.js.map +1 -1
  161. package/dist/registries/modules.mjs +3 -3
  162. package/dist/registries/modules.mjs.map +1 -1
  163. package/dist/registries/plugins.js +2 -2
  164. package/dist/registries/plugins.js.map +1 -1
  165. package/dist/registries/plugins.mjs +2 -2
  166. package/dist/registries/plugins.mjs.map +1 -1
  167. package/dist/registries/policies.d.ts +1 -1
  168. package/dist/registries/policies.js +4 -4
  169. package/dist/registries/policies.js.map +1 -1
  170. package/dist/registries/policies.mjs +3 -3
  171. package/dist/registries/policies.mjs.map +1 -1
  172. package/dist/registries/services.js +3 -3
  173. package/dist/registries/services.js.map +1 -1
  174. package/dist/registries/services.mjs +3 -3
  175. package/dist/registries/services.mjs.map +1 -1
  176. package/dist/services/auth/index.js +3 -3
  177. package/dist/services/auth/index.js.map +1 -1
  178. package/dist/services/auth/index.mjs +3 -3
  179. package/dist/services/auth/index.mjs.map +1 -1
  180. package/dist/services/core-store.js +3 -3
  181. package/dist/services/core-store.js.map +1 -1
  182. package/dist/services/core-store.mjs +1 -1
  183. package/dist/services/core-store.mjs.map +1 -1
  184. package/dist/services/cron.d.ts.map +1 -1
  185. package/dist/services/cron.js +2 -4
  186. package/dist/services/cron.js.map +1 -1
  187. package/dist/services/cron.mjs +2 -4
  188. package/dist/services/cron.mjs.map +1 -1
  189. package/dist/services/document-service/attributes/index.js +2 -2
  190. package/dist/services/document-service/attributes/index.js.map +1 -1
  191. package/dist/services/document-service/attributes/index.mjs +1 -1
  192. package/dist/services/document-service/attributes/index.mjs.map +1 -1
  193. package/dist/services/document-service/attributes/transforms.js +3 -3
  194. package/dist/services/document-service/attributes/transforms.js.map +1 -1
  195. package/dist/services/document-service/attributes/transforms.mjs +2 -2
  196. package/dist/services/document-service/attributes/transforms.mjs.map +1 -1
  197. package/dist/services/document-service/components.d.ts.map +1 -1
  198. package/dist/services/document-service/components.js +13 -14
  199. package/dist/services/document-service/components.js.map +1 -1
  200. package/dist/services/document-service/components.mjs +12 -13
  201. package/dist/services/document-service/components.mjs.map +1 -1
  202. package/dist/services/document-service/draft-and-publish.js +65 -38
  203. package/dist/services/document-service/draft-and-publish.js.map +1 -1
  204. package/dist/services/document-service/draft-and-publish.mjs +59 -32
  205. package/dist/services/document-service/draft-and-publish.mjs.map +1 -1
  206. package/dist/services/document-service/entries.d.ts +2 -2
  207. package/dist/services/document-service/entries.d.ts.map +1 -1
  208. package/dist/services/document-service/entries.js +16 -8
  209. package/dist/services/document-service/entries.js.map +1 -1
  210. package/dist/services/document-service/entries.mjs +17 -9
  211. package/dist/services/document-service/entries.mjs.map +1 -1
  212. package/dist/services/document-service/first-published-at.js +7 -5
  213. package/dist/services/document-service/first-published-at.js.map +1 -1
  214. package/dist/services/document-service/first-published-at.mjs +7 -5
  215. package/dist/services/document-service/first-published-at.mjs.map +1 -1
  216. package/dist/services/document-service/internationalization.d.ts.map +1 -1
  217. package/dist/services/document-service/internationalization.js +37 -28
  218. package/dist/services/document-service/internationalization.js.map +1 -1
  219. package/dist/services/document-service/internationalization.mjs +33 -24
  220. package/dist/services/document-service/internationalization.mjs.map +1 -1
  221. package/dist/services/document-service/params.d.ts +1 -0
  222. package/dist/services/document-service/params.d.ts.map +1 -1
  223. package/dist/services/document-service/params.js +6 -4
  224. package/dist/services/document-service/params.js.map +1 -1
  225. package/dist/services/document-service/params.mjs +6 -5
  226. package/dist/services/document-service/params.mjs.map +1 -1
  227. package/dist/services/document-service/repository.d.ts.map +1 -1
  228. package/dist/services/document-service/repository.js +84 -61
  229. package/dist/services/document-service/repository.js.map +1 -1
  230. package/dist/services/document-service/repository.mjs +47 -24
  231. package/dist/services/document-service/repository.mjs.map +1 -1
  232. package/dist/services/document-service/transform/fields.d.ts.map +1 -1
  233. package/dist/services/document-service/transform/fields.js +7 -1
  234. package/dist/services/document-service/transform/fields.js.map +1 -1
  235. package/dist/services/document-service/transform/fields.mjs +7 -1
  236. package/dist/services/document-service/transform/fields.mjs.map +1 -1
  237. package/dist/services/document-service/transform/id-map.d.ts.map +1 -1
  238. package/dist/services/document-service/transform/id-map.js +2 -1
  239. package/dist/services/document-service/transform/id-map.js.map +1 -1
  240. package/dist/services/document-service/transform/id-map.mjs +2 -1
  241. package/dist/services/document-service/transform/id-map.mjs.map +1 -1
  242. package/dist/services/document-service/transform/id-transform.js +2 -2
  243. package/dist/services/document-service/transform/id-transform.js.map +1 -1
  244. package/dist/services/document-service/transform/id-transform.mjs +1 -1
  245. package/dist/services/document-service/transform/id-transform.mjs.map +1 -1
  246. package/dist/services/document-service/transform/populate.d.ts.map +1 -1
  247. package/dist/services/document-service/transform/populate.js +8 -1
  248. package/dist/services/document-service/transform/populate.js.map +1 -1
  249. package/dist/services/document-service/transform/populate.mjs +8 -1
  250. package/dist/services/document-service/transform/populate.mjs.map +1 -1
  251. package/dist/services/document-service/transform/query.d.ts +3 -1
  252. package/dist/services/document-service/transform/query.d.ts.map +1 -1
  253. package/dist/services/document-service/transform/query.js +12 -6
  254. package/dist/services/document-service/transform/query.js.map +1 -1
  255. package/dist/services/document-service/transform/query.mjs +11 -5
  256. package/dist/services/document-service/transform/query.mjs.map +1 -1
  257. package/dist/services/document-service/transform/relations/extract/data-ids.js +2 -2
  258. package/dist/services/document-service/transform/relations/extract/data-ids.js.map +1 -1
  259. package/dist/services/document-service/transform/relations/extract/data-ids.mjs +1 -1
  260. package/dist/services/document-service/transform/relations/extract/data-ids.mjs.map +1 -1
  261. package/dist/services/document-service/transform/relations/transform/data-ids.js +2 -2
  262. package/dist/services/document-service/transform/relations/transform/data-ids.js.map +1 -1
  263. package/dist/services/document-service/transform/relations/transform/data-ids.mjs +1 -1
  264. package/dist/services/document-service/transform/relations/transform/data-ids.mjs.map +1 -1
  265. package/dist/services/document-service/transform/relations/transform/default-locale.js +1 -1
  266. package/dist/services/document-service/transform/relations/transform/default-locale.js.map +1 -1
  267. package/dist/services/document-service/transform/relations/transform/default-locale.mjs +1 -1
  268. package/dist/services/document-service/transform/relations/transform/default-locale.mjs.map +1 -1
  269. package/dist/services/document-service/transform/relations/utils/dp.d.ts.map +1 -1
  270. package/dist/services/document-service/transform/relations/utils/dp.js +1 -2
  271. package/dist/services/document-service/transform/relations/utils/dp.js.map +1 -1
  272. package/dist/services/document-service/transform/relations/utils/dp.mjs +1 -2
  273. package/dist/services/document-service/transform/relations/utils/dp.mjs.map +1 -1
  274. package/dist/services/document-service/transform/relations/utils/i18n.d.ts +2 -2
  275. package/dist/services/document-service/transform/relations/utils/i18n.d.ts.map +1 -1
  276. package/dist/services/document-service/transform/relations/utils/i18n.js +2 -2
  277. package/dist/services/document-service/transform/relations/utils/i18n.js.map +1 -1
  278. package/dist/services/document-service/transform/relations/utils/i18n.mjs +2 -2
  279. package/dist/services/document-service/transform/relations/utils/i18n.mjs.map +1 -1
  280. package/dist/services/document-service/transform/relations/utils/map-relation.d.ts.map +1 -1
  281. package/dist/services/document-service/transform/relations/utils/map-relation.js +16 -10
  282. package/dist/services/document-service/transform/relations/utils/map-relation.js.map +1 -1
  283. package/dist/services/document-service/transform/relations/utils/map-relation.mjs +13 -7
  284. package/dist/services/document-service/transform/relations/utils/map-relation.mjs.map +1 -1
  285. package/dist/services/document-service/transform/relations/utils/xto-one.js +3 -3
  286. package/dist/services/document-service/transform/relations/utils/xto-one.js.map +1 -1
  287. package/dist/services/document-service/transform/relations/utils/xto-one.mjs +2 -2
  288. package/dist/services/document-service/transform/relations/utils/xto-one.mjs.map +1 -1
  289. package/dist/services/document-service/utils/bidirectional-relations.js +3 -3
  290. package/dist/services/document-service/utils/bidirectional-relations.js.map +1 -1
  291. package/dist/services/document-service/utils/bidirectional-relations.mjs +3 -3
  292. package/dist/services/document-service/utils/bidirectional-relations.mjs.map +1 -1
  293. package/dist/services/document-service/utils/clone-relations.js +3 -3
  294. package/dist/services/document-service/utils/clone-relations.js.map +1 -1
  295. package/dist/services/document-service/utils/clone-relations.mjs +3 -3
  296. package/dist/services/document-service/utils/clone-relations.mjs.map +1 -1
  297. package/dist/services/document-service/utils/self-referential-relations.js +4 -4
  298. package/dist/services/document-service/utils/self-referential-relations.js.map +1 -1
  299. package/dist/services/document-service/utils/self-referential-relations.mjs +4 -4
  300. package/dist/services/document-service/utils/self-referential-relations.mjs.map +1 -1
  301. package/dist/services/document-service/utils/unidirectional-relations.js +3 -3
  302. package/dist/services/document-service/utils/unidirectional-relations.js.map +1 -1
  303. package/dist/services/document-service/utils/unidirectional-relations.mjs +3 -3
  304. package/dist/services/document-service/utils/unidirectional-relations.mjs.map +1 -1
  305. package/dist/services/entity-validator/index.d.ts.map +1 -1
  306. package/dist/services/entity-validator/index.js +9 -10
  307. package/dist/services/entity-validator/index.js.map +1 -1
  308. package/dist/services/entity-validator/index.mjs +4 -5
  309. package/dist/services/entity-validator/index.mjs.map +1 -1
  310. package/dist/services/localization.d.ts +4 -0
  311. package/dist/services/localization.d.ts.map +1 -0
  312. package/dist/services/localization.js +51 -0
  313. package/dist/services/localization.js.map +1 -0
  314. package/dist/services/localization.mjs +49 -0
  315. package/dist/services/localization.mjs.map +1 -0
  316. package/dist/services/server/compose-endpoint.js +7 -7
  317. package/dist/services/server/compose-endpoint.js.map +1 -1
  318. package/dist/services/server/compose-endpoint.mjs +3 -3
  319. package/dist/services/server/compose-endpoint.mjs.map +1 -1
  320. package/dist/services/server/koa-methods.js +2 -2
  321. package/dist/services/server/koa-methods.js.map +1 -1
  322. package/dist/services/server/koa-methods.mjs +1 -1
  323. package/dist/services/server/koa-methods.mjs.map +1 -1
  324. package/dist/services/server/koa.d.ts.map +1 -1
  325. package/dist/services/server/koa.js +1 -2
  326. package/dist/services/server/koa.js.map +1 -1
  327. package/dist/services/server/koa.mjs +1 -2
  328. package/dist/services/server/koa.mjs.map +1 -1
  329. package/dist/services/server/middleware.d.ts.map +1 -1
  330. package/dist/services/server/middleware.js +1 -2
  331. package/dist/services/server/middleware.js.map +1 -1
  332. package/dist/services/server/middleware.mjs +1 -2
  333. package/dist/services/server/middleware.mjs.map +1 -1
  334. package/dist/services/server/routing.js +2 -2
  335. package/dist/services/server/routing.js.map +1 -1
  336. package/dist/services/server/routing.mjs +2 -2
  337. package/dist/services/server/routing.mjs.map +1 -1
  338. package/dist/services/utils/conditional-fields.d.ts +1 -1
  339. package/dist/services/utils/conditional-fields.d.ts.map +1 -1
  340. package/dist/services/utils/conditional-fields.js +2 -8
  341. package/dist/services/utils/conditional-fields.js.map +1 -1
  342. package/dist/services/utils/conditional-fields.mjs +2 -8
  343. package/dist/services/utils/conditional-fields.mjs.map +1 -1
  344. package/dist/services/utils/dynamic-zones.d.ts.map +1 -1
  345. package/dist/services/utils/dynamic-zones.js +2 -8
  346. package/dist/services/utils/dynamic-zones.js.map +1 -1
  347. package/dist/services/utils/dynamic-zones.mjs +2 -8
  348. package/dist/services/utils/dynamic-zones.mjs.map +1 -1
  349. package/dist/utils/cron.js +2 -2
  350. package/dist/utils/cron.js.map +1 -1
  351. package/dist/utils/cron.mjs +1 -1
  352. package/dist/utils/cron.mjs.map +1 -1
  353. package/dist/utils/detect-customizations.d.ts +31 -0
  354. package/dist/utils/detect-customizations.d.ts.map +1 -0
  355. package/dist/utils/detect-customizations.js +173 -0
  356. package/dist/utils/detect-customizations.js.map +1 -0
  357. package/dist/utils/detect-customizations.mjs +165 -0
  358. package/dist/utils/detect-customizations.mjs.map +1 -0
  359. package/dist/utils/filepath-to-prop-path.d.ts.map +1 -1
  360. package/dist/utils/filepath-to-prop-path.js +5 -12
  361. package/dist/utils/filepath-to-prop-path.js.map +1 -1
  362. package/dist/utils/filepath-to-prop-path.mjs +5 -11
  363. package/dist/utils/filepath-to-prop-path.mjs.map +1 -1
  364. package/dist/utils/is-initialized.js +3 -3
  365. package/dist/utils/is-initialized.js.map +1 -1
  366. package/dist/utils/is-initialized.mjs +2 -2
  367. package/dist/utils/is-initialized.mjs.map +1 -1
  368. package/dist/utils/startup-logger.d.ts.map +1 -1
  369. package/dist/utils/startup-logger.js +2 -4
  370. package/dist/utils/startup-logger.js.map +1 -1
  371. package/dist/utils/startup-logger.mjs +2 -3
  372. package/dist/utils/startup-logger.mjs.map +1 -1
  373. package/dist/utils/transform-content-types-to-models.js +4 -4
  374. package/dist/utils/transform-content-types-to-models.js.map +1 -1
  375. package/dist/utils/transform-content-types-to-models.mjs +3 -3
  376. package/dist/utils/transform-content-types-to-models.mjs.map +1 -1
  377. package/package.json +16 -16
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Effective entitlement limits registry.
5
+ *
6
+ * Feature modules register a live resolver for each numeric limit they enforce;
7
+ * the license endpoint and the support debug dump read the resolved, normalized
8
+ * values. A numeric string is read as its number. A resolved value that is nullish,
9
+ * non-numeric, or greater than or equal to UNLIMITED_ENTITLEMENT_THRESHOLD is reported
10
+ * as `null`, meaning "Unlimited".
11
+ */ // The license registry ships a deliberately large number to mean "unlimited"
12
+ // (see the "a number that will never be reached like 9999" convention in
13
+ // content-releases validation). Kept server-side so the frontend never hard-codes it.
14
+ const UNLIMITED_ENTITLEMENT_THRESHOLD = 9999;
15
+ const normalize = (value)=>{
16
+ // License options are untyped JSON, and the registry has shipped some limits as numeric
17
+ // strings (`retentionDays: "90"`). Enforcement coerces those implicitly, so accepting only
18
+ // real numbers here showed a 90-day audit-logs cap as "Unlimited".
19
+ const limit = typeof value === 'string' && value.trim() !== '' ? Number(value) : value;
20
+ if (typeof limit !== 'number' || Number.isNaN(limit)) {
21
+ return null;
22
+ }
23
+ return limit >= UNLIMITED_ENTITLEMENT_THRESHOLD ? null : limit;
24
+ };
25
+ const createEntitlementsRegistry = ()=>{
26
+ const registry = [];
27
+ const register = (input)=>{
28
+ const index = registry.findIndex((entry)=>entry.feature === input.feature);
29
+ if (index >= 0) {
30
+ registry[index] = input;
31
+ } else {
32
+ registry.push(input);
33
+ }
34
+ };
35
+ const list = (getFeature = ()=>undefined)=>registry.map((entry)=>{
36
+ const feature = getFeature(entry.feature);
37
+ return {
38
+ feature: entry.feature,
39
+ limits: entry.limits.map((limit)=>({
40
+ key: limit.key,
41
+ unit: limit.unit,
42
+ value: normalize(limit.get(feature))
43
+ }))
44
+ };
45
+ });
46
+ return {
47
+ register,
48
+ list
49
+ };
50
+ };
51
+
52
+ exports.UNLIMITED_ENTITLEMENT_THRESHOLD = UNLIMITED_ENTITLEMENT_THRESHOLD;
53
+ exports.createEntitlementsRegistry = createEntitlementsRegistry;
54
+ //# sourceMappingURL=entitlements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlements.js","sources":["../../src/ee/entitlements.ts"],"sourcesContent":["/**\n * Effective entitlement limits registry.\n *\n * Feature modules register a live resolver for each numeric limit they enforce;\n * the license endpoint and the support debug dump read the resolved, normalized\n * values. A numeric string is read as its number. A resolved value that is nullish,\n * non-numeric, or greater than or equal to UNLIMITED_ENTITLEMENT_THRESHOLD is reported\n * as `null`, meaning \"Unlimited\".\n */\n\n// The license registry ships a deliberately large number to mean \"unlimited\"\n// (see the \"a number that will never be reached like 9999\" convention in\n// content-releases validation). Kept server-side so the frontend never hard-codes it.\nexport const UNLIMITED_ENTITLEMENT_THRESHOLD = 9999;\n\n/** A feature as a license lists it: a bare name, or `{ name, options }`. */\nexport type EntitlementFeature =\n | string\n | { name: string; options?: Record<string, unknown>; [key: string]: unknown }\n | undefined;\n\nexport interface EntitlementLimitInput {\n key: string;\n unit?: 'days' | 'count';\n /**\n * Resolves the limit the feature enforces from the feature as a license lists it. The same\n * resolver serves the live license and a lapsed license's retained snapshot, so it must read\n * options from the feature it is handed and apply its own defaults and clamps.\n */\n get: (feature?: EntitlementFeature) => unknown;\n}\n\nexport interface EntitlementInput {\n feature: string;\n limits: EntitlementLimitInput[];\n}\n\nexport interface EntitlementLimit {\n key: string;\n unit?: 'days' | 'count';\n value: number | null;\n}\n\nexport interface Entitlement {\n feature: string;\n limits: EntitlementLimit[];\n}\n\nconst normalize = (value: unknown): number | null => {\n // License options are untyped JSON, and the registry has shipped some limits as numeric\n // strings (`retentionDays: \"90\"`). Enforcement coerces those implicitly, so accepting only\n // real numbers here showed a 90-day audit-logs cap as \"Unlimited\".\n const limit = typeof value === 'string' && value.trim() !== '' ? Number(value) : value;\n\n if (typeof limit !== 'number' || Number.isNaN(limit)) {\n return null;\n }\n return limit >= UNLIMITED_ENTITLEMENT_THRESHOLD ? null : limit;\n};\n\nexport const createEntitlementsRegistry = () => {\n const registry: EntitlementInput[] = [];\n\n const register = (input: EntitlementInput): void => {\n const index = registry.findIndex((entry) => entry.feature === input.feature);\n if (index >= 0) {\n registry[index] = input;\n } else {\n registry.push(input);\n }\n };\n\n const list = (\n getFeature: (name: string) => EntitlementFeature = () => undefined\n ): Entitlement[] =>\n registry.map((entry) => {\n const feature = getFeature(entry.feature);\n\n return {\n feature: entry.feature,\n limits: entry.limits.map((limit) => ({\n key: limit.key,\n unit: limit.unit,\n value: normalize(limit.get(feature)),\n })),\n };\n });\n\n return { register, list };\n};\n"],"names":["UNLIMITED_ENTITLEMENT_THRESHOLD","normalize","value","limit","trim","Number","isNaN","createEntitlementsRegistry","registry","register","input","index","findIndex","entry","feature","push","list","getFeature","undefined","map","limits","key","unit","get"],"mappings":";;AAAA;;;;;;;;AAQC;AAGD;AACA;AACO,MAAMA,kCAAkC;AAmC/C,MAAMC,YAAY,CAACC,KAAAA,GAAAA;;;;IAIjB,MAAMC,KAAAA,GAAQ,OAAOD,KAAAA,KAAU,QAAA,IAAYA,MAAME,IAAI,EAAA,KAAO,EAAA,GAAKC,MAAAA,CAAOH,KAAAA,CAAAA,GAASA,KAAAA;AAEjF,IAAA,IAAI,OAAOC,KAAAA,KAAU,QAAA,IAAYE,MAAAA,CAAOC,KAAK,CAACH,KAAAA,CAAAA,EAAQ;QACpD,OAAO,IAAA;AACT,IAAA;IACA,OAAOA,KAAAA,IAASH,kCAAkC,IAAA,GAAOG,KAAAA;AAC3D,CAAA;MAEaI,0BAAAA,GAA6B,IAAA;AACxC,IAAA,MAAMC,WAA+B,EAAE;AAEvC,IAAA,MAAMC,WAAW,CAACC,KAAAA,GAAAA;QAChB,MAAMC,KAAAA,GAAQH,QAAAA,CAASI,SAAS,CAAC,CAACC,QAAUA,KAAAA,CAAMC,OAAO,KAAKJ,KAAAA,CAAMI,OAAO,CAAA;AAC3E,QAAA,IAAIH,SAAS,CAAA,EAAG;YACdH,QAAQ,CAACG,MAAM,GAAGD,KAAAA;QACpB,CAAA,MAAO;AACLF,YAAAA,QAAAA,CAASO,IAAI,CAACL,KAAAA,CAAAA;AAChB,QAAA;AACF,IAAA,CAAA;IAEA,MAAMM,IAAAA,GAAO,CACXC,UAAAA,GAAmD,IAAMC,SAAS,GAElEV,QAAAA,CAASW,GAAG,CAAC,CAACN,KAAAA,GAAAA;YACZ,MAAMC,OAAAA,GAAUG,UAAAA,CAAWJ,KAAAA,CAAMC,OAAO,CAAA;YAExC,OAAO;AACLA,gBAAAA,OAAAA,EAASD,MAAMC,OAAO;AACtBM,gBAAAA,MAAAA,EAAQP,MAAMO,MAAM,CAACD,GAAG,CAAC,CAAChB,SAAW;AACnCkB,wBAAAA,GAAAA,EAAKlB,MAAMkB,GAAG;AACdC,wBAAAA,IAAAA,EAAMnB,MAAMmB,IAAI;wBAChBpB,KAAAA,EAAOD,SAAAA,CAAUE,KAAAA,CAAMoB,GAAG,CAACT,OAAAA,CAAAA;qBAC7B,CAAA;AACF,aAAA;AACF,QAAA,CAAA,CAAA;IAEF,OAAO;AAAEL,QAAAA,QAAAA;AAAUO,QAAAA;AAAK,KAAA;AAC1B;;;;;"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Effective entitlement limits registry.
3
+ *
4
+ * Feature modules register a live resolver for each numeric limit they enforce;
5
+ * the license endpoint and the support debug dump read the resolved, normalized
6
+ * values. A numeric string is read as its number. A resolved value that is nullish,
7
+ * non-numeric, or greater than or equal to UNLIMITED_ENTITLEMENT_THRESHOLD is reported
8
+ * as `null`, meaning "Unlimited".
9
+ */ // The license registry ships a deliberately large number to mean "unlimited"
10
+ // (see the "a number that will never be reached like 9999" convention in
11
+ // content-releases validation). Kept server-side so the frontend never hard-codes it.
12
+ const UNLIMITED_ENTITLEMENT_THRESHOLD = 9999;
13
+ const normalize = (value)=>{
14
+ // License options are untyped JSON, and the registry has shipped some limits as numeric
15
+ // strings (`retentionDays: "90"`). Enforcement coerces those implicitly, so accepting only
16
+ // real numbers here showed a 90-day audit-logs cap as "Unlimited".
17
+ const limit = typeof value === 'string' && value.trim() !== '' ? Number(value) : value;
18
+ if (typeof limit !== 'number' || Number.isNaN(limit)) {
19
+ return null;
20
+ }
21
+ return limit >= UNLIMITED_ENTITLEMENT_THRESHOLD ? null : limit;
22
+ };
23
+ const createEntitlementsRegistry = ()=>{
24
+ const registry = [];
25
+ const register = (input)=>{
26
+ const index = registry.findIndex((entry)=>entry.feature === input.feature);
27
+ if (index >= 0) {
28
+ registry[index] = input;
29
+ } else {
30
+ registry.push(input);
31
+ }
32
+ };
33
+ const list = (getFeature = ()=>undefined)=>registry.map((entry)=>{
34
+ const feature = getFeature(entry.feature);
35
+ return {
36
+ feature: entry.feature,
37
+ limits: entry.limits.map((limit)=>({
38
+ key: limit.key,
39
+ unit: limit.unit,
40
+ value: normalize(limit.get(feature))
41
+ }))
42
+ };
43
+ });
44
+ return {
45
+ register,
46
+ list
47
+ };
48
+ };
49
+
50
+ export { UNLIMITED_ENTITLEMENT_THRESHOLD, createEntitlementsRegistry };
51
+ //# sourceMappingURL=entitlements.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlements.mjs","sources":["../../src/ee/entitlements.ts"],"sourcesContent":["/**\n * Effective entitlement limits registry.\n *\n * Feature modules register a live resolver for each numeric limit they enforce;\n * the license endpoint and the support debug dump read the resolved, normalized\n * values. A numeric string is read as its number. A resolved value that is nullish,\n * non-numeric, or greater than or equal to UNLIMITED_ENTITLEMENT_THRESHOLD is reported\n * as `null`, meaning \"Unlimited\".\n */\n\n// The license registry ships a deliberately large number to mean \"unlimited\"\n// (see the \"a number that will never be reached like 9999\" convention in\n// content-releases validation). Kept server-side so the frontend never hard-codes it.\nexport const UNLIMITED_ENTITLEMENT_THRESHOLD = 9999;\n\n/** A feature as a license lists it: a bare name, or `{ name, options }`. */\nexport type EntitlementFeature =\n | string\n | { name: string; options?: Record<string, unknown>; [key: string]: unknown }\n | undefined;\n\nexport interface EntitlementLimitInput {\n key: string;\n unit?: 'days' | 'count';\n /**\n * Resolves the limit the feature enforces from the feature as a license lists it. The same\n * resolver serves the live license and a lapsed license's retained snapshot, so it must read\n * options from the feature it is handed and apply its own defaults and clamps.\n */\n get: (feature?: EntitlementFeature) => unknown;\n}\n\nexport interface EntitlementInput {\n feature: string;\n limits: EntitlementLimitInput[];\n}\n\nexport interface EntitlementLimit {\n key: string;\n unit?: 'days' | 'count';\n value: number | null;\n}\n\nexport interface Entitlement {\n feature: string;\n limits: EntitlementLimit[];\n}\n\nconst normalize = (value: unknown): number | null => {\n // License options are untyped JSON, and the registry has shipped some limits as numeric\n // strings (`retentionDays: \"90\"`). Enforcement coerces those implicitly, so accepting only\n // real numbers here showed a 90-day audit-logs cap as \"Unlimited\".\n const limit = typeof value === 'string' && value.trim() !== '' ? Number(value) : value;\n\n if (typeof limit !== 'number' || Number.isNaN(limit)) {\n return null;\n }\n return limit >= UNLIMITED_ENTITLEMENT_THRESHOLD ? null : limit;\n};\n\nexport const createEntitlementsRegistry = () => {\n const registry: EntitlementInput[] = [];\n\n const register = (input: EntitlementInput): void => {\n const index = registry.findIndex((entry) => entry.feature === input.feature);\n if (index >= 0) {\n registry[index] = input;\n } else {\n registry.push(input);\n }\n };\n\n const list = (\n getFeature: (name: string) => EntitlementFeature = () => undefined\n ): Entitlement[] =>\n registry.map((entry) => {\n const feature = getFeature(entry.feature);\n\n return {\n feature: entry.feature,\n limits: entry.limits.map((limit) => ({\n key: limit.key,\n unit: limit.unit,\n value: normalize(limit.get(feature)),\n })),\n };\n });\n\n return { register, list };\n};\n"],"names":["UNLIMITED_ENTITLEMENT_THRESHOLD","normalize","value","limit","trim","Number","isNaN","createEntitlementsRegistry","registry","register","input","index","findIndex","entry","feature","push","list","getFeature","undefined","map","limits","key","unit","get"],"mappings":"AAAA;;;;;;;;AAQC;AAGD;AACA;AACO,MAAMA,kCAAkC;AAmC/C,MAAMC,YAAY,CAACC,KAAAA,GAAAA;;;;IAIjB,MAAMC,KAAAA,GAAQ,OAAOD,KAAAA,KAAU,QAAA,IAAYA,MAAME,IAAI,EAAA,KAAO,EAAA,GAAKC,MAAAA,CAAOH,KAAAA,CAAAA,GAASA,KAAAA;AAEjF,IAAA,IAAI,OAAOC,KAAAA,KAAU,QAAA,IAAYE,MAAAA,CAAOC,KAAK,CAACH,KAAAA,CAAAA,EAAQ;QACpD,OAAO,IAAA;AACT,IAAA;IACA,OAAOA,KAAAA,IAASH,kCAAkC,IAAA,GAAOG,KAAAA;AAC3D,CAAA;MAEaI,0BAAAA,GAA6B,IAAA;AACxC,IAAA,MAAMC,WAA+B,EAAE;AAEvC,IAAA,MAAMC,WAAW,CAACC,KAAAA,GAAAA;QAChB,MAAMC,KAAAA,GAAQH,QAAAA,CAASI,SAAS,CAAC,CAACC,QAAUA,KAAAA,CAAMC,OAAO,KAAKJ,KAAAA,CAAMI,OAAO,CAAA;AAC3E,QAAA,IAAIH,SAAS,CAAA,EAAG;YACdH,QAAQ,CAACG,MAAM,GAAGD,KAAAA;QACpB,CAAA,MAAO;AACLF,YAAAA,QAAAA,CAASO,IAAI,CAACL,KAAAA,CAAAA;AAChB,QAAA;AACF,IAAA,CAAA;IAEA,MAAMM,IAAAA,GAAO,CACXC,UAAAA,GAAmD,IAAMC,SAAS,GAElEV,QAAAA,CAASW,GAAG,CAAC,CAACN,KAAAA,GAAAA;YACZ,MAAMC,OAAAA,GAAUG,UAAAA,CAAWJ,KAAAA,CAAMC,OAAO,CAAA;YAExC,OAAO;AACLA,gBAAAA,OAAAA,EAASD,MAAMC,OAAO;AACtBM,gBAAAA,MAAAA,EAAQP,MAAMO,MAAM,CAACD,GAAG,CAAC,CAAChB,SAAW;AACnCkB,wBAAAA,GAAAA,EAAKlB,MAAMkB,GAAG;AACdC,wBAAAA,IAAAA,EAAMnB,MAAMmB,IAAI;wBAChBpB,KAAAA,EAAOD,SAAAA,CAAUE,KAAAA,CAAMoB,GAAG,CAACT,OAAAA,CAAAA;qBAC7B,CAAA;AACF,aAAA;AACF,QAAA,CAAA,CAAA;IAEF,OAAO;AAAEL,QAAAA,QAAAA;AAAUO,QAAAA;AAAK,KAAA;AAC1B;;;;"}
@@ -1,5 +1,21 @@
1
1
  import type { Logger } from '@strapi/logger';
2
2
  import type { Core } from '@strapi/types';
3
+ interface LicenseInfoState {
4
+ licenseKey?: string;
5
+ features?: Array<{
6
+ name: string;
7
+ [key: string]: any;
8
+ } | string>;
9
+ expireAt?: string;
10
+ seats?: number;
11
+ type?: string;
12
+ isTrial: boolean;
13
+ subscriptionId?: string;
14
+ planPriceId?: string;
15
+ /** End of the subscription term, epoch milliseconds. */
16
+ renewalDate?: string | number;
17
+ }
18
+ type LicenseStatus = 'none' | 'active' | 'expired' | 'unknown';
3
19
  declare const _default: Readonly<{
4
20
  init: (licenseDir: string, logger?: Logger) => void;
5
21
  checkLicense: ({ strapi }: {
@@ -11,8 +27,20 @@ declare const _default: Readonly<{
11
27
  trialEndsAt: string;
12
28
  } | null>;
13
29
  readonly isEE: boolean;
30
+ readonly licenseStatus: LicenseStatus;
31
+ /** Display-only; see EE.retainedLicense. Never use for feature gating. */
32
+ readonly retainedLicense: Omit<LicenseInfoState, "licenseKey"> | null;
14
33
  readonly seats: number | undefined;
15
34
  readonly type: string | undefined;
35
+ readonly expireAt: string | undefined;
36
+ /** Null when the registry does not provide it yet; survives expiry via the retained snapshot. */
37
+ readonly renewalDate: string | number | null;
38
+ /**
39
+ * Every feature the current plan supports, in display order, regardless of whether this
40
+ * license includes it. Falls back to the retained license's type so an expired license
41
+ * still lists rows. See `PLAN_FEATURE_CATALOG` in `./license`.
42
+ */
43
+ readonly planFeatureCatalog: string[];
16
44
  readonly isTrial: boolean;
17
45
  readonly planPriceId: string | undefined;
18
46
  readonly subscriptionId: string | undefined;
@@ -27,6 +55,11 @@ declare const _default: Readonly<{
27
55
  } | undefined;
28
56
  isEnabled: (featureName: string) => boolean;
29
57
  }>;
58
+ entitlements: Readonly<{
59
+ register: (input: import("./entitlements").EntitlementInput) => void;
60
+ list: () => import("./entitlements").Entitlement[];
61
+ listRetained(): import("./entitlements").Entitlement[];
62
+ }>;
30
63
  }>;
31
64
  export default _default;
32
65
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ee/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;;uBAsEhB,MAAM,WAAW,MAAM;+BA4IT;QAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;KAAE;mCA0B5D;QACD,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;KACrB,KAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;;;;;;;;;;kBA7Nd,MAAM;;2BA4PT,MAAM;;kBA5PH,MAAM;;iCA8RN,MAAM;;;AAhCnC,wBAkCG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ee/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAe1C,UAAU,gBAAgB;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,GAAG,MAAM,CAAC,CAAC;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/B;AAED,KAAK,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;;uBAgFrC,MAAM,WAAW,MAAM;+BAsJT;QAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;KAAE;mCA0B5D;QACD,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;KACrB,KAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;;;IAgDzC,0EAA0E;;;;;IAiB1E,iGAAiG;;IAKjG;;;;OAIG;iCACuB,MAAM,EAAE;;;;;;;kBAxVT,MAAM;;2BA4SP,MAAM;;kBA5SL,MAAM;;iCA8WJ,MAAM;;;;;;;;AA9DnC,wBAuFG"}
package/dist/ee/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var fp = require('lodash/fp');
3
+ var _ = require('lodash');
4
4
  var fetch = require('../utils/fetch.js');
5
5
  var license = require('./license.js');
6
+ var entitlements$1 = require('./entitlements.js');
6
7
  var cron = require('../utils/cron.js');
7
8
 
8
9
  const ONE_MINUTE = 1000 * 60;
@@ -10,17 +11,35 @@ const ee = {
10
11
  enabled: false,
11
12
  licenseInfo: {
12
13
  isTrial: false
13
- }
14
+ },
15
+ retainedLicense: null,
16
+ licenseStatus: 'none'
14
17
  };
15
- const disable = (message)=>{
18
+ const disable = (message, status = 'unknown')=>{
16
19
  // Prevent emitting ee.disable if it was already disabled
17
20
  const shouldEmitEvent = ee.enabled !== false;
18
21
  ee.logger?.warn(`${message} Switching to CE.`);
22
+ // Retain a display-only snapshot (never the key) BEFORE wiping, so the admin panel can
23
+ // still show which license this instance has and why it is unusable. Guarded on `type`
24
+ // so a repeat disable() call cannot overwrite the snapshot with an already-wiped one.
25
+ if (ee.licenseInfo.type) {
26
+ ee.retainedLicense = _.pick(ee.licenseInfo, [
27
+ 'features',
28
+ 'expireAt',
29
+ 'seats',
30
+ 'type',
31
+ 'isTrial',
32
+ 'subscriptionId',
33
+ 'planPriceId',
34
+ 'renewalDate'
35
+ ]);
36
+ }
37
+ ee.licenseStatus = status;
19
38
  // Only keep the license key and isTrial for potential re-enabling during a later check
20
- ee.licenseInfo = fp.pick([
39
+ ee.licenseInfo = _.pick(ee.licenseInfo, [
21
40
  'licenseKey',
22
41
  'isTrial'
23
- ], ee.licenseInfo);
42
+ ]);
24
43
  ee.licenseInfo.isTrial = false;
25
44
  ee.enabled = false;
26
45
  if (shouldEmitEvent) {
@@ -32,6 +51,8 @@ const enable = ()=>{
32
51
  // Prevent emitting ee.enable if it was already enabled
33
52
  const shouldEmitEvent = ee.enabled !== true;
34
53
  ee.enabled = true;
54
+ ee.licenseStatus = 'active';
55
+ ee.retainedLicense = null;
35
56
  if (shouldEmitEvent) {
36
57
  // Notify EE features that they should be disabled
37
58
  strapi.eventHub.emit('ee.enable');
@@ -79,8 +100,15 @@ let initialized = false;
79
100
  lastCheckAt: Date.now()
80
101
  };
81
102
  const fallback = (error)=>{
103
+ // Whether the registry was unreachable or actually refused the license is only
104
+ // knowable here, from `shouldFallback`. Record it rather than letting the admin
105
+ // panel infer it from the presence of a cached license: an instance that has never
106
+ // reached the registry has no cache to fall back to, and would otherwise be told
107
+ // its license was refused when the registry was merely unreachable.
108
+ result.errorKind = error instanceof license.LicenseCheckError && error.shouldFallback ? 'unreachable' : 'rejected';
82
109
  if (error instanceof license.LicenseCheckError && error.shouldFallback && storedInfo?.license) {
83
110
  ee.logger?.warn(`${error.message} The last stored one will be used as a potential fallback.`);
111
+ result.error = error.message; // record why we fell back so usingCachedLicense is derivable
84
112
  return storedInfo.license;
85
113
  }
86
114
  result.error = error.message;
@@ -96,7 +124,7 @@ let initialized = false;
96
124
  try {
97
125
  // Verify license and check if its info changed
98
126
  const newLicenseInfo = license.verifyLicense(license$1);
99
- const licenseInfoChanged = !fp.isEqual(newLicenseInfo.features, ee.licenseInfo.features) || newLicenseInfo.seats !== ee.licenseInfo.seats || newLicenseInfo.type !== ee.licenseInfo.type;
127
+ const licenseInfoChanged = !_.isEqual(newLicenseInfo.features, ee.licenseInfo.features) || newLicenseInfo.seats !== ee.licenseInfo.seats || newLicenseInfo.type !== ee.licenseInfo.type;
100
128
  // Store the new license info
101
129
  ee.licenseInfo = newLicenseInfo;
102
130
  const wasEnabled = ee.enabled;
@@ -144,7 +172,7 @@ const validateInfo = ()=>{
144
172
  }
145
173
  const expirationTime = new Date(ee.licenseInfo.expireAt).getTime();
146
174
  if (expirationTime < new Date().getTime()) {
147
- return disable('License expired.');
175
+ return disable('License expired.', 'expired');
148
176
  }
149
177
  enable();
150
178
  };
@@ -191,6 +219,7 @@ const list = ()=>{
191
219
  }) || [];
192
220
  };
193
221
  const get = (featureName)=>list().find((feature)=>feature.name === featureName);
222
+ const entitlements = entitlements$1.createEntitlementsRegistry();
194
223
  var index = Object.freeze({
195
224
  init,
196
225
  checkLicense,
@@ -198,12 +227,32 @@ var index = Object.freeze({
198
227
  get isEE () {
199
228
  return ee.enabled;
200
229
  },
230
+ get licenseStatus () {
231
+ return ee.licenseStatus;
232
+ },
233
+ /** Display-only; see EE.retainedLicense. Never use for feature gating. */ get retainedLicense () {
234
+ return ee.retainedLicense;
235
+ },
201
236
  get seats () {
202
237
  return ee.licenseInfo.seats;
203
238
  },
204
239
  get type () {
205
240
  return ee.licenseInfo.type;
206
241
  },
242
+ get expireAt () {
243
+ return ee.licenseInfo.expireAt;
244
+ },
245
+ /** Null when the registry does not provide it yet; survives expiry via the retained snapshot. */ get renewalDate () {
246
+ return ee.licenseInfo.renewalDate ?? ee.retainedLicense?.renewalDate ?? null;
247
+ },
248
+ /**
249
+ * Every feature the current plan supports, in display order, regardless of whether this
250
+ * license includes it. Falls back to the retained license's type so an expired license
251
+ * still lists rows. See `PLAN_FEATURE_CATALOG` in `./license`.
252
+ */ get planFeatureCatalog () {
253
+ const type = ee.licenseInfo.type ?? ee.retainedLicense?.type;
254
+ return type && type in license.PLAN_FEATURE_CATALOG ? license.PLAN_FEATURE_CATALOG[type] : [];
255
+ },
207
256
  get isTrial () {
208
257
  return ee.licenseInfo.isTrial;
209
258
  },
@@ -217,6 +266,24 @@ var index = Object.freeze({
217
266
  list,
218
267
  get,
219
268
  isEnabled: (featureName)=>get(featureName) !== undefined
269
+ }),
270
+ entitlements: Object.freeze({
271
+ register: entitlements.register,
272
+ // Resolvers are registered during `register()`, before the license is validated, and each
273
+ // falls back to a built-in default when the feature is absent. Without this gate an
274
+ // instance whose license was disabled would still report generous limits, which reads as
275
+ // "these are your granted limits". No license, no entitlements.
276
+ list: ()=>ee.enabled ? entitlements.list(get) : [],
277
+ // A lapsed license's limits, from the same resolvers run against its retained feature list,
278
+ // so a lapsed Plan card and the debug dump carry the defaults and clamps the plan enforced
279
+ // instead of raw options. Only features the retained license listed are reported.
280
+ listRetained () {
281
+ const retainedFeatures = (ee.retainedLicense?.features ?? []).map((feature)=>typeof feature === 'object' ? feature : {
282
+ name: feature
283
+ });
284
+ const getRetained = (name)=>retainedFeatures.find((feature)=>feature.name === name);
285
+ return entitlements.list(getRetained).filter((entry)=>getRetained(entry.feature) !== undefined);
286
+ }
220
287
  })
221
288
  });
222
289
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/ee/index.ts"],"sourcesContent":["import { pick, isEqual } from 'lodash/fp';\nimport type { Logger } from '@strapi/logger';\nimport type { Core } from '@strapi/types';\nimport { createStrapiFetch } from '../utils/fetch';\nimport {\n readLicense,\n verifyLicense,\n fetchLicense,\n LicenseCheckError,\n LICENSE_REGISTRY_URI,\n} from './license';\nimport { shiftCronExpression } from '../utils/cron';\n\nconst ONE_MINUTE = 1000 * 60;\n\ninterface EE {\n enabled: boolean;\n licenseInfo: {\n licenseKey?: string;\n features?: Array<{ name: string; [key: string]: any } | string>;\n expireAt?: string;\n seats?: number;\n type?: string;\n isTrial: boolean;\n subscriptionId?: string;\n planPriceId?: string;\n };\n logger?: Logger;\n}\n\nconst ee: EE = {\n enabled: false,\n licenseInfo: {\n isTrial: false,\n },\n};\n\nconst disable = (message: string) => {\n // Prevent emitting ee.disable if it was already disabled\n const shouldEmitEvent = ee.enabled !== false;\n\n ee.logger?.warn(`${message} Switching to CE.`);\n // Only keep the license key and isTrial for potential re-enabling during a later check\n ee.licenseInfo = pick(['licenseKey', 'isTrial'], ee.licenseInfo);\n\n ee.licenseInfo.isTrial = false;\n\n ee.enabled = false;\n\n if (shouldEmitEvent) {\n // Notify EE features that they should be disabled\n strapi.eventHub.emit('ee.disable');\n }\n};\n\nconst enable = () => {\n // Prevent emitting ee.enable if it was already enabled\n const shouldEmitEvent = ee.enabled !== true;\n\n ee.enabled = true;\n\n if (shouldEmitEvent) {\n // Notify EE features that they should be disabled\n strapi.eventHub.emit('ee.enable');\n }\n};\n\nlet initialized = false;\n\n/**\n * Optimistically enable EE if the format of the license is valid, only run once.\n */\nconst init = (licenseDir: string, logger?: Logger) => {\n if (initialized) {\n return;\n }\n\n initialized = true;\n ee.logger = logger;\n\n if (process.env.STRAPI_DISABLE_EE?.toLowerCase() === 'true') {\n return;\n }\n\n try {\n const license = process.env.STRAPI_LICENSE || readLicense(licenseDir);\n\n if (license) {\n ee.licenseInfo = verifyLicense(license);\n enable();\n }\n } catch (error) {\n if (error instanceof Error) {\n disable(error.message);\n } else {\n disable('Invalid license.');\n }\n }\n};\n\n/**\n * Contact the license registry to update the license to its latest state.\n *\n * Store the result in database to avoid unecessary requests, and will fallback to that in case of a network failure.\n */\nconst onlineUpdate = async ({ strapi }: { strapi: Core.Strapi }) => {\n const { get, commit, rollback } = await strapi.db.transaction();\n const transaction = get();\n\n try {\n const storedInfo = await strapi.db\n ?.queryBuilder('strapi::core-store')\n .where({ key: 'ee_information' })\n .select('value')\n .first()\n .transacting(transaction)\n .forUpdate()\n .execute()\n .then((result: any) => (result ? JSON.parse(result.value) : result));\n\n const shouldContactRegistry = (storedInfo?.lastCheckAt ?? 0) < Date.now() - ONE_MINUTE;\n const result: {\n license?: string | null;\n error?: string;\n lastCheckAt?: number;\n } = { lastCheckAt: Date.now() };\n\n const fallback = (error: Error) => {\n if (error instanceof LicenseCheckError && error.shouldFallback && storedInfo?.license) {\n ee.logger?.warn(\n `${error.message} The last stored one will be used as a potential fallback.`\n );\n return storedInfo.license;\n }\n\n result.error = error.message;\n disable(error.message);\n };\n\n if (!ee?.licenseInfo?.licenseKey) {\n throw new Error('Missing license key.');\n }\n\n const license = shouldContactRegistry\n ? await fetchLicense({ strapi }, ee.licenseInfo.licenseKey, strapi.config.get('uuid')).catch(\n fallback\n )\n : storedInfo.license;\n\n if (license) {\n try {\n // Verify license and check if its info changed\n const newLicenseInfo = verifyLicense(license);\n const licenseInfoChanged =\n !isEqual(newLicenseInfo.features, ee.licenseInfo.features) ||\n newLicenseInfo.seats !== ee.licenseInfo.seats ||\n newLicenseInfo.type !== ee.licenseInfo.type;\n\n // Store the new license info\n ee.licenseInfo = newLicenseInfo;\n const wasEnabled = ee.enabled;\n validateInfo();\n\n // Notify EE features\n if (licenseInfoChanged && wasEnabled) {\n strapi.eventHub.emit('ee.update');\n }\n } catch (error) {\n if (error instanceof Error) {\n disable(error.message);\n } else {\n disable('Invalid license.');\n }\n }\n } else if (!shouldContactRegistry) {\n disable(storedInfo.error);\n }\n\n if (shouldContactRegistry) {\n result.license = license ?? null;\n const query = strapi.db.queryBuilder('strapi::core-store').transacting(transaction);\n\n if (!storedInfo) {\n query.insert({ key: 'ee_information', value: JSON.stringify(result) });\n } else {\n query.update({ value: JSON.stringify(result) }).where({ key: 'ee_information' });\n }\n\n await query.execute();\n }\n\n await commit();\n } catch {\n // Example of errors: SQLite does not support FOR UPDATE\n await rollback();\n }\n};\n\nconst validateInfo = () => {\n if (typeof ee.licenseInfo.expireAt === 'undefined') {\n throw new Error('Missing license key.');\n }\n\n const expirationTime = new Date(ee.licenseInfo.expireAt).getTime();\n\n if (expirationTime < new Date().getTime()) {\n return disable('License expired.');\n }\n\n enable();\n};\n\nconst checkLicense = async ({ strapi }: { strapi: Core.Strapi }) => {\n const shouldStayOffline =\n ee.licenseInfo.type === 'gold' &&\n // This env variable support is temporarily used to ease the migration between online vs offline\n process.env.STRAPI_DISABLE_LICENSE_PING?.toLowerCase() === 'true';\n\n if (!shouldStayOffline) {\n await onlineUpdate({ strapi });\n\n strapi.cron.add({\n onlineUpdate: {\n task: () => onlineUpdate({ strapi }),\n options: shiftCronExpression('0 0 */12 * * *'),\n },\n });\n } else {\n if (!ee.licenseInfo.expireAt) {\n return disable('Your license does not have offline support.');\n }\n\n validateInfo();\n }\n};\n\nconst getTrialEndDate = async ({\n strapi,\n}: {\n strapi: Core.Strapi;\n}): Promise<{ trialEndsAt: string } | null> => {\n const silentFetch = createStrapiFetch(strapi, {\n logs: false,\n });\n\n const res = await silentFetch(\n `${LICENSE_REGISTRY_URI}/api/licenses/${ee.licenseInfo.licenseKey}/trial-countdown`,\n {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n }\n ).catch(() => {\n throw new LicenseCheckError(\n 'Could not proceed to retrieve the trial time left for your license.',\n true\n );\n });\n\n const data = (await res.json()) as { trialEndsAt: string } | null;\n\n return data;\n};\n\nconst list = () => {\n return (\n ee.licenseInfo.features?.map((feature) =>\n typeof feature === 'object' ? feature : { name: feature }\n ) || []\n );\n};\n\nconst get = (featureName: string) => list().find((feature) => feature.name === featureName);\n\nexport default Object.freeze({\n init,\n checkLicense,\n getTrialEndDate,\n\n get isEE() {\n return ee.enabled;\n },\n\n get seats() {\n return ee.licenseInfo.seats;\n },\n\n get type() {\n return ee.licenseInfo.type;\n },\n\n get isTrial() {\n return ee.licenseInfo.isTrial;\n },\n\n get planPriceId() {\n return ee.licenseInfo.planPriceId;\n },\n\n get subscriptionId() {\n return ee.licenseInfo.subscriptionId;\n },\n\n features: Object.freeze({\n list,\n get,\n isEnabled: (featureName: string) => get(featureName) !== undefined,\n }),\n});\n"],"names":["ONE_MINUTE","ee","enabled","licenseInfo","isTrial","disable","message","shouldEmitEvent","logger","warn","pick","strapi","eventHub","emit","enable","initialized","init","licenseDir","process","env","STRAPI_DISABLE_EE","toLowerCase","license","STRAPI_LICENSE","readLicense","verifyLicense","error","Error","onlineUpdate","get","commit","rollback","db","transaction","storedInfo","queryBuilder","where","key","select","first","transacting","forUpdate","execute","then","result","JSON","parse","value","shouldContactRegistry","lastCheckAt","Date","now","fallback","LicenseCheckError","shouldFallback","licenseKey","fetchLicense","config","catch","newLicenseInfo","licenseInfoChanged","isEqual","features","seats","type","wasEnabled","validateInfo","query","insert","stringify","update","expireAt","expirationTime","getTime","checkLicense","shouldStayOffline","STRAPI_DISABLE_LICENSE_PING","cron","add","task","options","shiftCronExpression","getTrialEndDate","silentFetch","createStrapiFetch","logs","res","LICENSE_REGISTRY_URI","method","headers","data","json","list","map","feature","name","featureName","find","Object","freeze","isEE","planPriceId","subscriptionId","isEnabled","undefined"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/ee/index.ts"],"sourcesContent":["import { isEqual, pick } from 'lodash';\nimport type { Logger } from '@strapi/logger';\nimport type { Core } from '@strapi/types';\nimport { createStrapiFetch } from '../utils/fetch';\nimport {\n readLicense,\n verifyLicense,\n fetchLicense,\n LicenseCheckError,\n LICENSE_REGISTRY_URI,\n PLAN_FEATURE_CATALOG,\n} from './license';\nimport { createEntitlementsRegistry } from './entitlements';\nimport { shiftCronExpression } from '../utils/cron';\n\nconst ONE_MINUTE = 1000 * 60;\n\ninterface LicenseInfoState {\n licenseKey?: string;\n features?: Array<{ name: string; [key: string]: any } | string>;\n expireAt?: string;\n seats?: number;\n type?: string;\n isTrial: boolean;\n subscriptionId?: string;\n planPriceId?: string;\n /** End of the subscription term, epoch milliseconds. */\n renewalDate?: string | number;\n}\n\ntype LicenseStatus = 'none' | 'active' | 'expired' | 'unknown';\n\ninterface EE {\n enabled: boolean;\n licenseInfo: LicenseInfoState;\n /**\n * Display-only copy of the last known license, retained when a license exists but is\n * not usable (expired / could not be validated) so the admin panel can explain why.\n * NEVER read by enforcement paths (features.list/get/isEnabled, isEE) and never holds\n * the license key.\n */\n retainedLicense: Omit<LicenseInfoState, 'licenseKey'> | null;\n licenseStatus: LicenseStatus;\n logger?: Logger;\n}\n\nconst ee: EE = {\n enabled: false,\n licenseInfo: {\n isTrial: false,\n },\n retainedLicense: null,\n licenseStatus: 'none',\n};\n\nconst disable = (message: string, status: 'expired' | 'unknown' = 'unknown') => {\n // Prevent emitting ee.disable if it was already disabled\n const shouldEmitEvent = ee.enabled !== false;\n\n ee.logger?.warn(`${message} Switching to CE.`);\n\n // Retain a display-only snapshot (never the key) BEFORE wiping, so the admin panel can\n // still show which license this instance has and why it is unusable. Guarded on `type`\n // so a repeat disable() call cannot overwrite the snapshot with an already-wiped one.\n if (ee.licenseInfo.type) {\n ee.retainedLicense = pick(ee.licenseInfo, [\n 'features',\n 'expireAt',\n 'seats',\n 'type',\n 'isTrial',\n 'subscriptionId',\n 'planPriceId',\n 'renewalDate',\n ]);\n }\n ee.licenseStatus = status;\n\n // Only keep the license key and isTrial for potential re-enabling during a later check\n ee.licenseInfo = pick(ee.licenseInfo, ['licenseKey', 'isTrial']);\n\n ee.licenseInfo.isTrial = false;\n\n ee.enabled = false;\n\n if (shouldEmitEvent) {\n // Notify EE features that they should be disabled\n strapi.eventHub.emit('ee.disable');\n }\n};\n\nconst enable = () => {\n // Prevent emitting ee.enable if it was already enabled\n const shouldEmitEvent = ee.enabled !== true;\n\n ee.enabled = true;\n ee.licenseStatus = 'active';\n ee.retainedLicense = null;\n\n if (shouldEmitEvent) {\n // Notify EE features that they should be disabled\n strapi.eventHub.emit('ee.enable');\n }\n};\n\nlet initialized = false;\n\n/**\n * Optimistically enable EE if the format of the license is valid, only run once.\n */\nconst init = (licenseDir: string, logger?: Logger) => {\n if (initialized) {\n return;\n }\n\n initialized = true;\n ee.logger = logger;\n\n if (process.env.STRAPI_DISABLE_EE?.toLowerCase() === 'true') {\n return;\n }\n\n try {\n const license = process.env.STRAPI_LICENSE || readLicense(licenseDir);\n\n if (license) {\n ee.licenseInfo = verifyLicense(license);\n enable();\n }\n } catch (error) {\n if (error instanceof Error) {\n disable(error.message);\n } else {\n disable('Invalid license.');\n }\n }\n};\n\n/**\n * Contact the license registry to update the license to its latest state.\n *\n * Store the result in database to avoid unecessary requests, and will fallback to that in case of a network failure.\n */\nconst onlineUpdate = async ({ strapi }: { strapi: Core.Strapi }) => {\n const { get, commit, rollback } = await strapi.db.transaction();\n const transaction = get();\n\n try {\n const storedInfo = await strapi.db\n ?.queryBuilder('strapi::core-store')\n .where({ key: 'ee_information' })\n .select('value')\n .first()\n .transacting(transaction)\n .forUpdate()\n .execute()\n .then((result: any) => (result ? JSON.parse(result.value) : result));\n\n const shouldContactRegistry = (storedInfo?.lastCheckAt ?? 0) < Date.now() - ONE_MINUTE;\n const result: {\n license?: string | null;\n error?: string;\n errorKind?: 'unreachable' | 'rejected';\n lastCheckAt?: number;\n } = { lastCheckAt: Date.now() };\n\n const fallback = (error: Error) => {\n // Whether the registry was unreachable or actually refused the license is only\n // knowable here, from `shouldFallback`. Record it rather than letting the admin\n // panel infer it from the presence of a cached license: an instance that has never\n // reached the registry has no cache to fall back to, and would otherwise be told\n // its license was refused when the registry was merely unreachable.\n result.errorKind =\n error instanceof LicenseCheckError && error.shouldFallback ? 'unreachable' : 'rejected';\n\n if (error instanceof LicenseCheckError && error.shouldFallback && storedInfo?.license) {\n ee.logger?.warn(\n `${error.message} The last stored one will be used as a potential fallback.`\n );\n result.error = error.message; // record why we fell back so usingCachedLicense is derivable\n return storedInfo.license;\n }\n\n result.error = error.message;\n disable(error.message);\n };\n\n if (!ee?.licenseInfo?.licenseKey) {\n throw new Error('Missing license key.');\n }\n\n const license = shouldContactRegistry\n ? await fetchLicense({ strapi }, ee.licenseInfo.licenseKey, strapi.config.get('uuid')).catch(\n fallback\n )\n : storedInfo.license;\n\n if (license) {\n try {\n // Verify license and check if its info changed\n const newLicenseInfo = verifyLicense(license);\n const licenseInfoChanged =\n !isEqual(newLicenseInfo.features, ee.licenseInfo.features) ||\n newLicenseInfo.seats !== ee.licenseInfo.seats ||\n newLicenseInfo.type !== ee.licenseInfo.type;\n\n // Store the new license info\n ee.licenseInfo = newLicenseInfo;\n const wasEnabled = ee.enabled;\n validateInfo();\n\n // Notify EE features\n if (licenseInfoChanged && wasEnabled) {\n strapi.eventHub.emit('ee.update');\n }\n } catch (error) {\n if (error instanceof Error) {\n disable(error.message);\n } else {\n disable('Invalid license.');\n }\n }\n } else if (!shouldContactRegistry) {\n disable(storedInfo.error);\n }\n\n if (shouldContactRegistry) {\n result.license = license ?? null;\n const query = strapi.db.queryBuilder('strapi::core-store').transacting(transaction);\n\n if (!storedInfo) {\n query.insert({ key: 'ee_information', value: JSON.stringify(result) });\n } else {\n query.update({ value: JSON.stringify(result) }).where({ key: 'ee_information' });\n }\n\n await query.execute();\n }\n\n await commit();\n } catch {\n // Example of errors: SQLite does not support FOR UPDATE\n await rollback();\n }\n};\n\nconst validateInfo = () => {\n if (typeof ee.licenseInfo.expireAt === 'undefined') {\n throw new Error('Missing license key.');\n }\n\n const expirationTime = new Date(ee.licenseInfo.expireAt).getTime();\n\n if (expirationTime < new Date().getTime()) {\n return disable('License expired.', 'expired');\n }\n\n enable();\n};\n\nconst checkLicense = async ({ strapi }: { strapi: Core.Strapi }) => {\n const shouldStayOffline =\n ee.licenseInfo.type === 'gold' &&\n // This env variable support is temporarily used to ease the migration between online vs offline\n process.env.STRAPI_DISABLE_LICENSE_PING?.toLowerCase() === 'true';\n\n if (!shouldStayOffline) {\n await onlineUpdate({ strapi });\n\n strapi.cron.add({\n onlineUpdate: {\n task: () => onlineUpdate({ strapi }),\n options: shiftCronExpression('0 0 */12 * * *'),\n },\n });\n } else {\n if (!ee.licenseInfo.expireAt) {\n return disable('Your license does not have offline support.');\n }\n\n validateInfo();\n }\n};\n\nconst getTrialEndDate = async ({\n strapi,\n}: {\n strapi: Core.Strapi;\n}): Promise<{ trialEndsAt: string } | null> => {\n const silentFetch = createStrapiFetch(strapi, {\n logs: false,\n });\n\n const res = await silentFetch(\n `${LICENSE_REGISTRY_URI}/api/licenses/${ee.licenseInfo.licenseKey}/trial-countdown`,\n {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n }\n ).catch(() => {\n throw new LicenseCheckError(\n 'Could not proceed to retrieve the trial time left for your license.',\n true\n );\n });\n\n const data = (await res.json()) as { trialEndsAt: string } | null;\n\n return data;\n};\n\nconst list = () => {\n return (\n ee.licenseInfo.features?.map((feature) =>\n typeof feature === 'object' ? feature : { name: feature }\n ) || []\n );\n};\n\nconst get = (featureName: string) => list().find((feature) => feature.name === featureName);\n\nconst entitlements = createEntitlementsRegistry();\n\nexport default Object.freeze({\n init,\n checkLicense,\n getTrialEndDate,\n\n get isEE() {\n return ee.enabled;\n },\n\n get licenseStatus() {\n return ee.licenseStatus;\n },\n\n /** Display-only; see EE.retainedLicense. Never use for feature gating. */\n get retainedLicense() {\n return ee.retainedLicense;\n },\n\n get seats() {\n return ee.licenseInfo.seats;\n },\n\n get type() {\n return ee.licenseInfo.type;\n },\n\n get expireAt() {\n return ee.licenseInfo.expireAt;\n },\n\n /** Null when the registry does not provide it yet; survives expiry via the retained snapshot. */\n get renewalDate() {\n return ee.licenseInfo.renewalDate ?? ee.retainedLicense?.renewalDate ?? null;\n },\n\n /**\n * Every feature the current plan supports, in display order, regardless of whether this\n * license includes it. Falls back to the retained license's type so an expired license\n * still lists rows. See `PLAN_FEATURE_CATALOG` in `./license`.\n */\n get planFeatureCatalog(): string[] {\n const type = ee.licenseInfo.type ?? ee.retainedLicense?.type;\n return type && type in PLAN_FEATURE_CATALOG\n ? PLAN_FEATURE_CATALOG[type as keyof typeof PLAN_FEATURE_CATALOG]\n : [];\n },\n\n get isTrial() {\n return ee.licenseInfo.isTrial;\n },\n\n get planPriceId() {\n return ee.licenseInfo.planPriceId;\n },\n\n get subscriptionId() {\n return ee.licenseInfo.subscriptionId;\n },\n\n features: Object.freeze({\n list,\n get,\n isEnabled: (featureName: string) => get(featureName) !== undefined,\n }),\n\n entitlements: Object.freeze({\n register: entitlements.register,\n // Resolvers are registered during `register()`, before the license is validated, and each\n // falls back to a built-in default when the feature is absent. Without this gate an\n // instance whose license was disabled would still report generous limits, which reads as\n // \"these are your granted limits\". No license, no entitlements.\n list: () => (ee.enabled ? entitlements.list(get) : []),\n // A lapsed license's limits, from the same resolvers run against its retained feature list,\n // so a lapsed Plan card and the debug dump carry the defaults and clamps the plan enforced\n // instead of raw options. Only features the retained license listed are reported.\n listRetained() {\n const retainedFeatures = (ee.retainedLicense?.features ?? []).map((feature) =>\n typeof feature === 'object' ? feature : { name: feature }\n );\n const getRetained = (name: string) =>\n retainedFeatures.find((feature) => feature.name === name);\n\n return entitlements\n .list(getRetained)\n .filter((entry) => getRetained(entry.feature) !== undefined);\n },\n }),\n});\n"],"names":["ONE_MINUTE","ee","enabled","licenseInfo","isTrial","retainedLicense","licenseStatus","disable","message","status","shouldEmitEvent","logger","warn","type","pick","strapi","eventHub","emit","enable","initialized","init","licenseDir","process","env","STRAPI_DISABLE_EE","toLowerCase","license","STRAPI_LICENSE","readLicense","verifyLicense","error","Error","onlineUpdate","get","commit","rollback","db","transaction","storedInfo","queryBuilder","where","key","select","first","transacting","forUpdate","execute","then","result","JSON","parse","value","shouldContactRegistry","lastCheckAt","Date","now","fallback","errorKind","LicenseCheckError","shouldFallback","licenseKey","fetchLicense","config","catch","newLicenseInfo","licenseInfoChanged","isEqual","features","seats","wasEnabled","validateInfo","query","insert","stringify","update","expireAt","expirationTime","getTime","checkLicense","shouldStayOffline","STRAPI_DISABLE_LICENSE_PING","cron","add","task","options","shiftCronExpression","getTrialEndDate","silentFetch","createStrapiFetch","logs","res","LICENSE_REGISTRY_URI","method","headers","data","json","list","map","feature","name","featureName","find","entitlements","createEntitlementsRegistry","Object","freeze","isEE","renewalDate","planFeatureCatalog","PLAN_FEATURE_CATALOG","planPriceId","subscriptionId","isEnabled","undefined","register","listRetained","retainedFeatures","getRetained","filter","entry"],"mappings":"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"}
package/dist/ee/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
- import { isEqual, pick } from 'lodash/fp';
1
+ import { isEqual, pick } from 'lodash';
2
2
  import { createStrapiFetch } from '../utils/fetch.mjs';
3
- import { LICENSE_REGISTRY_URI, LicenseCheckError, readLicense, verifyLicense, fetchLicense } from './license.mjs';
3
+ import { PLAN_FEATURE_CATALOG, LICENSE_REGISTRY_URI, LicenseCheckError, readLicense, verifyLicense, fetchLicense } from './license.mjs';
4
+ import { createEntitlementsRegistry } from './entitlements.mjs';
4
5
  import { shiftCronExpression } from '../utils/cron.mjs';
5
6
 
6
7
  const ONE_MINUTE = 1000 * 60;
@@ -8,17 +9,35 @@ const ee = {
8
9
  enabled: false,
9
10
  licenseInfo: {
10
11
  isTrial: false
11
- }
12
+ },
13
+ retainedLicense: null,
14
+ licenseStatus: 'none'
12
15
  };
13
- const disable = (message)=>{
16
+ const disable = (message, status = 'unknown')=>{
14
17
  // Prevent emitting ee.disable if it was already disabled
15
18
  const shouldEmitEvent = ee.enabled !== false;
16
19
  ee.logger?.warn(`${message} Switching to CE.`);
20
+ // Retain a display-only snapshot (never the key) BEFORE wiping, so the admin panel can
21
+ // still show which license this instance has and why it is unusable. Guarded on `type`
22
+ // so a repeat disable() call cannot overwrite the snapshot with an already-wiped one.
23
+ if (ee.licenseInfo.type) {
24
+ ee.retainedLicense = pick(ee.licenseInfo, [
25
+ 'features',
26
+ 'expireAt',
27
+ 'seats',
28
+ 'type',
29
+ 'isTrial',
30
+ 'subscriptionId',
31
+ 'planPriceId',
32
+ 'renewalDate'
33
+ ]);
34
+ }
35
+ ee.licenseStatus = status;
17
36
  // Only keep the license key and isTrial for potential re-enabling during a later check
18
- ee.licenseInfo = pick([
37
+ ee.licenseInfo = pick(ee.licenseInfo, [
19
38
  'licenseKey',
20
39
  'isTrial'
21
- ], ee.licenseInfo);
40
+ ]);
22
41
  ee.licenseInfo.isTrial = false;
23
42
  ee.enabled = false;
24
43
  if (shouldEmitEvent) {
@@ -30,6 +49,8 @@ const enable = ()=>{
30
49
  // Prevent emitting ee.enable if it was already enabled
31
50
  const shouldEmitEvent = ee.enabled !== true;
32
51
  ee.enabled = true;
52
+ ee.licenseStatus = 'active';
53
+ ee.retainedLicense = null;
33
54
  if (shouldEmitEvent) {
34
55
  // Notify EE features that they should be disabled
35
56
  strapi.eventHub.emit('ee.enable');
@@ -77,8 +98,15 @@ let initialized = false;
77
98
  lastCheckAt: Date.now()
78
99
  };
79
100
  const fallback = (error)=>{
101
+ // Whether the registry was unreachable or actually refused the license is only
102
+ // knowable here, from `shouldFallback`. Record it rather than letting the admin
103
+ // panel infer it from the presence of a cached license: an instance that has never
104
+ // reached the registry has no cache to fall back to, and would otherwise be told
105
+ // its license was refused when the registry was merely unreachable.
106
+ result.errorKind = error instanceof LicenseCheckError && error.shouldFallback ? 'unreachable' : 'rejected';
80
107
  if (error instanceof LicenseCheckError && error.shouldFallback && storedInfo?.license) {
81
108
  ee.logger?.warn(`${error.message} The last stored one will be used as a potential fallback.`);
109
+ result.error = error.message; // record why we fell back so usingCachedLicense is derivable
82
110
  return storedInfo.license;
83
111
  }
84
112
  result.error = error.message;
@@ -142,7 +170,7 @@ const validateInfo = ()=>{
142
170
  }
143
171
  const expirationTime = new Date(ee.licenseInfo.expireAt).getTime();
144
172
  if (expirationTime < new Date().getTime()) {
145
- return disable('License expired.');
173
+ return disable('License expired.', 'expired');
146
174
  }
147
175
  enable();
148
176
  };
@@ -189,6 +217,7 @@ const list = ()=>{
189
217
  }) || [];
190
218
  };
191
219
  const get = (featureName)=>list().find((feature)=>feature.name === featureName);
220
+ const entitlements = createEntitlementsRegistry();
192
221
  var index = Object.freeze({
193
222
  init,
194
223
  checkLicense,
@@ -196,12 +225,32 @@ var index = Object.freeze({
196
225
  get isEE () {
197
226
  return ee.enabled;
198
227
  },
228
+ get licenseStatus () {
229
+ return ee.licenseStatus;
230
+ },
231
+ /** Display-only; see EE.retainedLicense. Never use for feature gating. */ get retainedLicense () {
232
+ return ee.retainedLicense;
233
+ },
199
234
  get seats () {
200
235
  return ee.licenseInfo.seats;
201
236
  },
202
237
  get type () {
203
238
  return ee.licenseInfo.type;
204
239
  },
240
+ get expireAt () {
241
+ return ee.licenseInfo.expireAt;
242
+ },
243
+ /** Null when the registry does not provide it yet; survives expiry via the retained snapshot. */ get renewalDate () {
244
+ return ee.licenseInfo.renewalDate ?? ee.retainedLicense?.renewalDate ?? null;
245
+ },
246
+ /**
247
+ * Every feature the current plan supports, in display order, regardless of whether this
248
+ * license includes it. Falls back to the retained license's type so an expired license
249
+ * still lists rows. See `PLAN_FEATURE_CATALOG` in `./license`.
250
+ */ get planFeatureCatalog () {
251
+ const type = ee.licenseInfo.type ?? ee.retainedLicense?.type;
252
+ return type && type in PLAN_FEATURE_CATALOG ? PLAN_FEATURE_CATALOG[type] : [];
253
+ },
205
254
  get isTrial () {
206
255
  return ee.licenseInfo.isTrial;
207
256
  },
@@ -215,6 +264,24 @@ var index = Object.freeze({
215
264
  list,
216
265
  get,
217
266
  isEnabled: (featureName)=>get(featureName) !== undefined
267
+ }),
268
+ entitlements: Object.freeze({
269
+ register: entitlements.register,
270
+ // Resolvers are registered during `register()`, before the license is validated, and each
271
+ // falls back to a built-in default when the feature is absent. Without this gate an
272
+ // instance whose license was disabled would still report generous limits, which reads as
273
+ // "these are your granted limits". No license, no entitlements.
274
+ list: ()=>ee.enabled ? entitlements.list(get) : [],
275
+ // A lapsed license's limits, from the same resolvers run against its retained feature list,
276
+ // so a lapsed Plan card and the debug dump carry the defaults and clamps the plan enforced
277
+ // instead of raw options. Only features the retained license listed are reported.
278
+ listRetained () {
279
+ const retainedFeatures = (ee.retainedLicense?.features ?? []).map((feature)=>typeof feature === 'object' ? feature : {
280
+ name: feature
281
+ });
282
+ const getRetained = (name)=>retainedFeatures.find((feature)=>feature.name === name);
283
+ return entitlements.list(getRetained).filter((entry)=>getRetained(entry.feature) !== undefined);
284
+ }
218
285
  })
219
286
  });
220
287