@carlonicora/nextjs-jsonapi 1.15.0 → 1.17.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 (321) hide show
  1. package/dist/ApiData-DPKNfY-9.d.mts +10 -0
  2. package/dist/ApiData-DPKNfY-9.d.ts +10 -0
  3. package/dist/ApiRequestDataTypeInterface-DIEOFn9s.d.mts +40 -0
  4. package/dist/ApiRequestDataTypeInterface-DIEOFn9s.d.ts +40 -0
  5. package/dist/{ApiResponseInterface-QLDnxLA9.d.ts → ApiResponseInterface-BKyod24U.d.ts} +3 -11
  6. package/dist/{ApiResponseInterface-B4QdWh-y.d.mts → ApiResponseInterface-Dqvu09tz.d.mts} +3 -11
  7. package/dist/{BlockNoteEditor-FGXYUAWI.js → BlockNoteEditor-34T5CY27.js} +17 -16
  8. package/dist/BlockNoteEditor-34T5CY27.js.map +1 -0
  9. package/dist/{BlockNoteEditor-ITJLAOXC.mjs → BlockNoteEditor-4Z6TZBJE.mjs} +7 -6
  10. package/dist/{BlockNoteEditor-ITJLAOXC.mjs.map → BlockNoteEditor-4Z6TZBJE.mjs.map} +1 -1
  11. package/dist/JsonApiContext-Bsm_Q2oe.d.mts +41 -0
  12. package/dist/JsonApiContext-Bsm_Q2oe.d.ts +41 -0
  13. package/dist/JsonApiRequest-54ZBO7WQ.js +24 -0
  14. package/dist/{JsonApiRequest-FXZCYIER.js.map → JsonApiRequest-54ZBO7WQ.js.map} +1 -1
  15. package/dist/{JsonApiRequest-HFWXMKMA.mjs → JsonApiRequest-XWQWTFEQ.mjs} +2 -2
  16. package/dist/chunk-3EPNHTMH.js +26 -0
  17. package/dist/chunk-3EPNHTMH.js.map +1 -0
  18. package/dist/{chunk-TGBXBUWM.mjs → chunk-3VM3WAOV.mjs} +8 -1
  19. package/dist/chunk-3VM3WAOV.mjs.map +1 -0
  20. package/dist/{chunk-6YD42BP6.js → chunk-7DTKRMYW.js} +31 -19
  21. package/dist/chunk-7DTKRMYW.js.map +1 -0
  22. package/dist/{chunk-PK5DRSUD.js → chunk-D7H7SRWB.js} +4104 -793
  23. package/dist/chunk-D7H7SRWB.js.map +1 -0
  24. package/dist/{chunk-JGVXZS7M.mjs → chunk-KUFWHMMY.mjs} +1592 -133
  25. package/dist/chunk-KUFWHMMY.mjs.map +1 -0
  26. package/dist/{chunk-SJIVGCNM.mjs → chunk-KX7YG6LY.mjs} +27 -15
  27. package/dist/chunk-KX7YG6LY.mjs.map +1 -0
  28. package/dist/{chunk-FPZPD4JI.js → chunk-LI6CPNJI.js} +17 -10
  29. package/dist/chunk-LI6CPNJI.js.map +1 -0
  30. package/dist/{chunk-WAFOKMKT.mjs → chunk-SXPXC2TY.mjs} +3729 -418
  31. package/dist/chunk-SXPXC2TY.mjs.map +1 -0
  32. package/dist/{chunk-C6QXZGL7.js → chunk-UYY34W7R.js} +1622 -163
  33. package/dist/chunk-UYY34W7R.js.map +1 -0
  34. package/dist/chunk-VOXD3ZLY.mjs +26 -0
  35. package/dist/chunk-VOXD3ZLY.mjs.map +1 -0
  36. package/dist/client/index.d.mts +11 -45
  37. package/dist/client/index.d.ts +11 -45
  38. package/dist/client/index.js +10 -6
  39. package/dist/client/index.js.map +1 -1
  40. package/dist/client/index.mjs +13 -9
  41. package/dist/components/index.d.mts +254 -9
  42. package/dist/components/index.d.ts +254 -9
  43. package/dist/components/index.js +85 -6
  44. package/dist/components/index.js.map +1 -1
  45. package/dist/components/index.mjs +84 -5
  46. package/dist/{config-C5tGGrYf.d.mts → config--nwiW74Z.d.ts} +7 -2
  47. package/dist/{config-eceYM5kN.d.ts → config-BKSQmUWU.d.mts} +7 -2
  48. package/dist/{content.interface-CxBBC7ec.d.mts → content.interface-4VICFRA0.d.ts} +2 -1
  49. package/dist/{content.interface-TB2MfJGs.d.ts → content.interface-CFc97-Cj.d.mts} +2 -1
  50. package/dist/contexts/index.d.mts +3 -2
  51. package/dist/contexts/index.d.ts +3 -2
  52. package/dist/contexts/index.js +7 -6
  53. package/dist/contexts/index.js.map +1 -1
  54. package/dist/contexts/index.mjs +6 -5
  55. package/dist/core/index.d.mts +524 -18
  56. package/dist/core/index.d.ts +524 -18
  57. package/dist/core/index.js +54 -4
  58. package/dist/core/index.js.map +1 -1
  59. package/dist/core/index.mjs +53 -3
  60. package/dist/index.d.mts +16 -12
  61. package/dist/index.d.ts +16 -12
  62. package/dist/index.js +57 -5
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +58 -6
  65. package/dist/{notification.interface-lG6UpTpt.d.mts → notification.interface-BGaPiCUM.d.mts} +3 -42
  66. package/dist/{notification.interface-lG6UpTpt.d.ts → notification.interface-CqwaOIgM.d.ts} +3 -42
  67. package/dist/{s3.service-DP_hsssD.d.mts → s3.service-BYs88XEE.d.ts} +21 -2
  68. package/dist/{s3.service-Dq-PTUNa.d.ts → s3.service-C0BjOdvn.d.mts} +21 -2
  69. package/dist/scripts/generate-web-module/generator.d.ts.map +1 -1
  70. package/dist/scripts/generate-web-module/generator.js +66 -0
  71. package/dist/scripts/generate-web-module/generator.js.map +1 -1
  72. package/dist/scripts/generate-web-module/templates/index.d.ts +8 -0
  73. package/dist/scripts/generate-web-module/templates/index.d.ts.map +1 -1
  74. package/dist/scripts/generate-web-module/templates/index.js +18 -1
  75. package/dist/scripts/generate-web-module/templates/index.js.map +1 -1
  76. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.d.ts +7 -0
  77. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.d.ts.map +1 -0
  78. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.js +141 -0
  79. package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.js.map +1 -0
  80. package/dist/scripts/generate-web-module/templates/project/env.template.d.ts +7 -0
  81. package/dist/scripts/generate-web-module/templates/project/env.template.d.ts.map +1 -0
  82. package/dist/scripts/generate-web-module/templates/project/env.template.js +110 -0
  83. package/dist/scripts/generate-web-module/templates/project/env.template.js.map +1 -0
  84. package/dist/scripts/generate-web-module/templates/project/main-layout.template.d.ts +7 -0
  85. package/dist/scripts/generate-web-module/templates/project/main-layout.template.d.ts.map +1 -0
  86. package/dist/scripts/generate-web-module/templates/project/main-layout.template.js +101 -0
  87. package/dist/scripts/generate-web-module/templates/project/main-layout.template.js.map +1 -0
  88. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.d.ts +7 -0
  89. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.d.ts.map +1 -0
  90. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.js +66 -0
  91. package/dist/scripts/generate-web-module/templates/project/middleware-env.template.js.map +1 -0
  92. package/dist/scripts/generate-web-module/templates/project/settings-container.template.d.ts +7 -0
  93. package/dist/scripts/generate-web-module/templates/project/settings-container.template.d.ts.map +1 -0
  94. package/dist/scripts/generate-web-module/templates/project/settings-container.template.js +257 -0
  95. package/dist/scripts/generate-web-module/templates/project/settings-container.template.js.map +1 -0
  96. package/dist/scripts/generate-web-module/templates/project/settings-context.template.d.ts +7 -0
  97. package/dist/scripts/generate-web-module/templates/project/settings-context.template.d.ts.map +1 -0
  98. package/dist/scripts/generate-web-module/templates/project/settings-context.template.js +124 -0
  99. package/dist/scripts/generate-web-module/templates/project/settings-context.template.js.map +1 -0
  100. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.d.ts +7 -0
  101. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.d.ts.map +1 -0
  102. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.js +78 -0
  103. package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.js.map +1 -0
  104. package/dist/scripts/generate-web-module/templates/project/settings-page.template.d.ts +7 -0
  105. package/dist/scripts/generate-web-module/templates/project/settings-page.template.d.ts.map +1 -0
  106. package/dist/scripts/generate-web-module/templates/project/settings-page.template.js +75 -0
  107. package/dist/scripts/generate-web-module/templates/project/settings-page.template.js.map +1 -0
  108. package/dist/scripts/generate-web-module/types/template-data.interface.d.ts +1 -1
  109. package/dist/scripts/generate-web-module/types/template-data.interface.d.ts.map +1 -1
  110. package/dist/server/index.d.mts +6 -4
  111. package/dist/server/index.d.ts +6 -4
  112. package/dist/server/index.js +13 -13
  113. package/dist/server/index.js.map +1 -1
  114. package/dist/server/index.mjs +3 -3
  115. package/dist/stripe-subscription.interface-B-TM40Io.d.ts +226 -0
  116. package/dist/stripe-subscription.interface-DDxnpj0F.d.mts +226 -0
  117. package/dist/testing/index.d.mts +338 -0
  118. package/dist/testing/index.d.ts +338 -0
  119. package/dist/testing/index.js +323 -0
  120. package/dist/testing/index.js.map +1 -0
  121. package/dist/testing/index.mjs +323 -0
  122. package/dist/testing/index.mjs.map +1 -0
  123. package/dist/{useSocket-Bua6MwLi.d.mts → useSocket-BNj9PrRw.d.mts} +1 -1
  124. package/dist/{useSocket-D5dhUp4m.d.ts → useSocket-Dwt8cz1x.d.ts} +1 -1
  125. package/package.json +29 -3
  126. package/scripts/generate-web-module/generator.ts +83 -0
  127. package/scripts/generate-web-module/templates/index.ts +10 -0
  128. package/scripts/generate-web-module/templates/project/bootstrapper.template.ts +108 -0
  129. package/scripts/generate-web-module/templates/project/env.template.ts +77 -0
  130. package/scripts/generate-web-module/templates/project/main-layout.template.tsx +68 -0
  131. package/scripts/generate-web-module/templates/project/middleware-env.template.ts +33 -0
  132. package/scripts/generate-web-module/templates/project/settings-container.template.tsx +224 -0
  133. package/scripts/generate-web-module/templates/project/settings-context.template.tsx +91 -0
  134. package/scripts/generate-web-module/templates/project/settings-module-page.template.tsx +45 -0
  135. package/scripts/generate-web-module/templates/project/settings-page.template.tsx +42 -0
  136. package/scripts/generate-web-module/types/template-data.interface.ts +1 -1
  137. package/src/client/config.ts +9 -0
  138. package/src/client/hooks/__tests__/useJsonApiGet.test.tsx +229 -0
  139. package/src/client/hooks/__tests__/useJsonApiMutation.test.tsx +348 -0
  140. package/src/client/hooks/__tests__/useRehydration.test.ts +188 -0
  141. package/src/components/forms/__tests__/FormCheckbox.test.tsx +238 -0
  142. package/src/components/forms/__tests__/FormDate.test.tsx +212 -0
  143. package/src/components/forms/__tests__/FormInput.test.tsx +292 -0
  144. package/src/components/forms/__tests__/FormSelect.test.tsx +173 -0
  145. package/src/components/index.ts +7 -0
  146. package/src/components/tables/__tests__/ContentListTable.test.tsx +411 -0
  147. package/src/core/abstracts/AbstractService.ts +104 -0
  148. package/src/core/endpoint/EndpointCreator.ts +7 -4
  149. package/src/core/endpoint/__tests__/EndpointCreator.test.ts +168 -0
  150. package/src/core/factories/__tests__/JsonApiDataFactory.test.ts +109 -0
  151. package/src/core/factories/__tests__/RehydrationFactory.test.ts +151 -0
  152. package/src/core/index.ts +12 -4
  153. package/src/core/interfaces/ApiResponseInterface.ts +1 -0
  154. package/src/core/registry/ModuleRegistry.ts +11 -2
  155. package/src/core/registry/__tests__/DataClassRegistry.test.ts +136 -0
  156. package/src/core/registry/__tests__/ModuleRegistrar.test.ts +159 -0
  157. package/src/core/utils/translateResponse.ts +17 -0
  158. package/src/features/auth/components/details/LandingComponent.tsx +14 -12
  159. package/src/features/billing/components/cards/BillingUsageSummaryCard.tsx +97 -0
  160. package/src/features/billing/components/cards/CustomerInfoCard.tsx +112 -0
  161. package/src/features/billing/components/cards/InvoicesSummaryCard.tsx +114 -0
  162. package/src/features/billing/components/cards/PaymentMethodSummaryCard.tsx +119 -0
  163. package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +146 -0
  164. package/src/features/billing/components/cards/index.ts +5 -0
  165. package/src/features/billing/components/containers/BillingDashboardContainer.tsx +427 -0
  166. package/src/features/billing/components/containers/index.ts +1 -0
  167. package/src/features/billing/components/index.ts +6 -0
  168. package/src/features/billing/components/modals/BillingDetailModal.tsx +36 -0
  169. package/src/features/billing/components/modals/index.ts +1 -0
  170. package/src/features/billing/components/providers/StripeProvider.tsx +48 -0
  171. package/src/features/billing/components/providers/index.ts +1 -0
  172. package/src/features/billing/components/utils/currency.ts +49 -0
  173. package/src/features/billing/components/utils/date.ts +21 -0
  174. package/src/features/billing/components/utils/index.ts +2 -0
  175. package/src/features/billing/components/widgets/BillingAlertBanner.tsx +63 -0
  176. package/src/features/billing/components/widgets/index.ts +1 -0
  177. package/src/features/billing/data/Billing.ts +17 -0
  178. package/src/features/billing/data/billing.service.ts +58 -0
  179. package/src/features/billing/data/index.ts +5 -0
  180. package/src/features/billing/index.ts +3 -0
  181. package/src/features/billing/modules/billing.module.ts +9 -0
  182. package/src/features/billing/modules/index.ts +1 -0
  183. package/src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx +79 -0
  184. package/src/features/billing/stripe-customer/components/containers/index.ts +1 -0
  185. package/src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx +151 -0
  186. package/src/features/billing/stripe-customer/components/details/index.ts +1 -0
  187. package/src/features/billing/stripe-customer/components/forms/PaymentMethodEditor.tsx +186 -0
  188. package/src/features/billing/stripe-customer/components/forms/index.ts +1 -0
  189. package/src/features/billing/stripe-customer/components/index.ts +4 -0
  190. package/src/features/billing/stripe-customer/components/lists/PaymentMethodsList.tsx +19 -0
  191. package/src/features/billing/stripe-customer/components/lists/index.ts +1 -0
  192. package/src/features/billing/stripe-customer/data/index.ts +5 -0
  193. package/src/features/billing/stripe-customer/data/payment-method.interface.ts +27 -0
  194. package/src/features/billing/stripe-customer/data/payment-method.ts +119 -0
  195. package/src/features/billing/stripe-customer/data/stripe-customer.interface.ts +16 -0
  196. package/src/features/billing/stripe-customer/data/stripe-customer.service.ts +128 -0
  197. package/src/features/billing/stripe-customer/data/stripe-customer.ts +71 -0
  198. package/src/features/billing/stripe-customer/index.ts +3 -0
  199. package/src/features/billing/stripe-customer/stripe-customer.module.ts +9 -0
  200. package/src/features/billing/stripe-customer/stripe-payment-method.module.ts +9 -0
  201. package/src/features/billing/stripe-invoice/components/containers/InvoicesContainer.tsx +66 -0
  202. package/src/features/billing/stripe-invoice/components/containers/index.ts +1 -0
  203. package/src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx +172 -0
  204. package/src/features/billing/stripe-invoice/components/details/index.ts +1 -0
  205. package/src/features/billing/stripe-invoice/components/index.ts +4 -0
  206. package/src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx +84 -0
  207. package/src/features/billing/stripe-invoice/components/lists/index.ts +1 -0
  208. package/src/features/billing/stripe-invoice/components/widgets/InvoiceStatusBadge.tsx +41 -0
  209. package/src/features/billing/stripe-invoice/components/widgets/index.ts +1 -0
  210. package/src/features/billing/stripe-invoice/data/index.ts +3 -0
  211. package/src/features/billing/stripe-invoice/data/stripe-invoice.interface.ts +65 -0
  212. package/src/features/billing/stripe-invoice/data/stripe-invoice.service.ts +64 -0
  213. package/src/features/billing/stripe-invoice/data/stripe-invoice.ts +177 -0
  214. package/src/features/billing/stripe-invoice/index.ts +2 -0
  215. package/src/features/billing/stripe-invoice/stripe-invoice.module.ts +9 -0
  216. package/src/features/billing/stripe-price/components/forms/PriceEditor.tsx +304 -0
  217. package/src/features/billing/stripe-price/components/forms/index.ts +1 -0
  218. package/src/features/billing/stripe-price/components/index.ts +2 -0
  219. package/src/features/billing/stripe-price/components/lists/PricesList.tsx +283 -0
  220. package/src/features/billing/stripe-price/components/lists/index.ts +1 -0
  221. package/src/features/billing/stripe-price/data/index.ts +3 -0
  222. package/src/features/billing/stripe-price/data/stripe-price.interface.ts +48 -0
  223. package/src/features/billing/stripe-price/data/stripe-price.service.ts +123 -0
  224. package/src/features/billing/stripe-price/data/stripe-price.ts +156 -0
  225. package/src/features/billing/stripe-price/index.ts +2 -0
  226. package/src/features/billing/stripe-price/stripe-price.module.ts +9 -0
  227. package/src/features/billing/stripe-product/components/containers/ProductsAdminContainer.tsx +86 -0
  228. package/src/features/billing/stripe-product/components/containers/index.ts +1 -0
  229. package/src/features/billing/stripe-product/components/forms/ProductEditor.tsx +100 -0
  230. package/src/features/billing/stripe-product/components/forms/index.ts +1 -0
  231. package/src/features/billing/stripe-product/components/index.ts +3 -0
  232. package/src/features/billing/stripe-product/components/lists/ProductsList.tsx +206 -0
  233. package/src/features/billing/stripe-product/components/lists/index.ts +1 -0
  234. package/src/features/billing/stripe-product/data/index.ts +3 -0
  235. package/src/features/billing/stripe-product/data/stripe-product.interface.ts +18 -0
  236. package/src/features/billing/stripe-product/data/stripe-product.service.ts +112 -0
  237. package/src/features/billing/stripe-product/data/stripe-product.ts +74 -0
  238. package/src/features/billing/stripe-product/index.ts +2 -0
  239. package/src/features/billing/stripe-product/stripe-product.module.ts +9 -0
  240. package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +304 -0
  241. package/src/features/billing/stripe-subscription/components/containers/index.ts +1 -0
  242. package/src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx +223 -0
  243. package/src/features/billing/stripe-subscription/components/details/index.ts +1 -0
  244. package/src/features/billing/stripe-subscription/components/forms/CancelSubscriptionDialog.tsx +116 -0
  245. package/src/features/billing/stripe-subscription/components/forms/SubscriptionEditor.tsx +331 -0
  246. package/src/features/billing/stripe-subscription/components/forms/index.ts +2 -0
  247. package/src/features/billing/stripe-subscription/components/index.ts +5 -0
  248. package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +104 -0
  249. package/src/features/billing/stripe-subscription/components/lists/index.ts +1 -0
  250. package/src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx +95 -0
  251. package/src/features/billing/stripe-subscription/components/widgets/PricingCardsGrid.tsx +110 -0
  252. package/src/features/billing/stripe-subscription/components/widgets/ProrationPreview.tsx +41 -0
  253. package/src/features/billing/stripe-subscription/components/widgets/SubscriptionStatusBadge.tsx +60 -0
  254. package/src/features/billing/stripe-subscription/components/widgets/index.ts +4 -0
  255. package/src/features/billing/stripe-subscription/data/index.ts +3 -0
  256. package/src/features/billing/stripe-subscription/data/stripe-subscription.interface.ts +66 -0
  257. package/src/features/billing/stripe-subscription/data/stripe-subscription.service.ts +193 -0
  258. package/src/features/billing/stripe-subscription/data/stripe-subscription.ts +135 -0
  259. package/src/features/billing/stripe-subscription/hooks/index.ts +1 -0
  260. package/src/features/billing/stripe-subscription/hooks/useConfirmSubscriptionPayment.ts +111 -0
  261. package/src/features/billing/stripe-subscription/index.ts +5 -0
  262. package/src/features/billing/stripe-subscription/stripe-subscription.module.ts +9 -0
  263. package/src/features/billing/stripe-usage/components/containers/UsageContainer.tsx +109 -0
  264. package/src/features/billing/stripe-usage/components/containers/index.ts +1 -0
  265. package/src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx +90 -0
  266. package/src/features/billing/stripe-usage/components/details/index.ts +1 -0
  267. package/src/features/billing/stripe-usage/components/index.ts +4 -0
  268. package/src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx +72 -0
  269. package/src/features/billing/stripe-usage/components/lists/index.ts +1 -0
  270. package/src/features/billing/stripe-usage/components/widgets/UsageSummaryCards.tsx +19 -0
  271. package/src/features/billing/stripe-usage/components/widgets/index.ts +1 -0
  272. package/src/features/billing/stripe-usage/data/index.ts +3 -0
  273. package/src/features/billing/stripe-usage/data/stripe-usage.interface.ts +55 -0
  274. package/src/features/billing/stripe-usage/data/stripe-usage.service.ts +129 -0
  275. package/src/features/billing/stripe-usage/data/stripe-usage.ts +70 -0
  276. package/src/features/billing/stripe-usage/index.ts +2 -0
  277. package/src/features/billing/stripe-usage/stripe-usage.module.ts +9 -0
  278. package/src/features/company/components/forms/CompanyEditor.tsx +2 -2
  279. package/src/features/company/contexts/CompanyContext.tsx +2 -2
  280. package/src/features/feature/components/forms/FormFeatures.tsx +13 -106
  281. package/src/features/feature/data/feature.interface.ts +1 -1
  282. package/src/features/feature/data/feature.ts +4 -4
  283. package/src/features/index.ts +7 -0
  284. package/src/features/module/data/module.interface.ts +0 -1
  285. package/src/features/module/data/module.ts +0 -6
  286. package/src/features/user/components/lists/ContributorsList.tsx +2 -2
  287. package/src/features/user/components/widgets/UserAvatar.tsx +1 -1
  288. package/src/hooks/__tests__/useDataListRetriever.test.ts +321 -0
  289. package/src/hooks/__tests__/useDebounce.test.ts +170 -0
  290. package/src/index.ts +5 -2
  291. package/src/login/config.ts +27 -0
  292. package/src/login/index.ts +2 -0
  293. package/src/shadcnui/custom/link.tsx +16 -6
  294. package/src/testing/factories/createMockApiData.ts +143 -0
  295. package/src/testing/factories/createMockModule.ts +32 -0
  296. package/src/testing/factories/createMockResponse.ts +93 -0
  297. package/src/testing/factories/createMockService.ts +79 -0
  298. package/src/testing/index.ts +70 -0
  299. package/src/testing/matchers/jsonApiMatchers.ts +174 -0
  300. package/src/testing/providers/MockJsonApiProvider.tsx +58 -0
  301. package/src/testing/utils/renderWithProviders.tsx +76 -0
  302. package/src/utils/__tests__/date-formatter.test.ts +161 -0
  303. package/src/utils/__tests__/exists.test.ts +100 -0
  304. package/src/utils/blocknote-diff.util.ts +2 -1
  305. package/src/utils/blocknote-word-diff-renderer.util.ts +8 -7
  306. package/src/utils/cn.test.ts +44 -0
  307. package/dist/AuthComponent-hxOPs9o8.d.mts +0 -11
  308. package/dist/AuthComponent-hxOPs9o8.d.ts +0 -11
  309. package/dist/BlockNoteEditor-FGXYUAWI.js.map +0 -1
  310. package/dist/JsonApiRequest-FXZCYIER.js +0 -24
  311. package/dist/chunk-6YD42BP6.js.map +0 -1
  312. package/dist/chunk-C6QXZGL7.js.map +0 -1
  313. package/dist/chunk-FPZPD4JI.js.map +0 -1
  314. package/dist/chunk-JGVXZS7M.mjs.map +0 -1
  315. package/dist/chunk-PK5DRSUD.js.map +0 -1
  316. package/dist/chunk-SJIVGCNM.mjs.map +0 -1
  317. package/dist/chunk-TGBXBUWM.mjs.map +0 -1
  318. package/dist/chunk-WAFOKMKT.mjs.map +0 -1
  319. package/src/discord/config.ts +0 -15
  320. package/src/discord/index.ts +0 -1
  321. /package/dist/{JsonApiRequest-HFWXMKMA.mjs.map → JsonApiRequest-XWQWTFEQ.mjs.map} +0 -0
@@ -0,0 +1,168 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { EndpointCreator } from "../EndpointCreator";
3
+ import { createMockModule } from "../../../testing";
4
+
5
+ describe("EndpointCreator", () => {
6
+ describe("basic URL generation", () => {
7
+ it("should generate URL from string endpoint", () => {
8
+ const creator = new EndpointCreator({ endpoint: "articles" });
9
+ expect(creator.generate()).toBe("articles");
10
+ });
11
+
12
+ it("should generate URL from module endpoint", () => {
13
+ const mockModule = createMockModule({ name: "articles" });
14
+ const creator = new EndpointCreator({ endpoint: mockModule });
15
+ expect(creator.generate()).toBe("articles");
16
+ });
17
+
18
+ it("should include id in URL", () => {
19
+ const creator = new EndpointCreator({ endpoint: "articles", id: "123" });
20
+ expect(creator.generate()).toBe("articles/123");
21
+ });
22
+
23
+ it("should include child endpoint", () => {
24
+ const creator = new EndpointCreator({
25
+ endpoint: "articles",
26
+ id: "123",
27
+ childEndpoint: "comments",
28
+ });
29
+ expect(creator.generate()).toBe("articles/123/comments");
30
+ });
31
+
32
+ it("should include child id", () => {
33
+ const creator = new EndpointCreator({
34
+ endpoint: "articles",
35
+ id: "123",
36
+ childEndpoint: "comments",
37
+ childId: "456",
38
+ });
39
+ expect(creator.generate()).toBe("articles/123/comments/456");
40
+ });
41
+ });
42
+
43
+ describe("fluent API", () => {
44
+ it("should support chaining endpoint()", () => {
45
+ const creator = new EndpointCreator({ endpoint: "initial" });
46
+ const result = creator.endpoint("articles");
47
+ expect(result).toBe(creator);
48
+ expect(creator.generate()).toBe("articles");
49
+ });
50
+
51
+ it("should support chaining id()", () => {
52
+ const creator = new EndpointCreator({ endpoint: "articles" });
53
+ const result = creator.id("123");
54
+ expect(result).toBe(creator);
55
+ expect(creator.generate()).toBe("articles/123");
56
+ });
57
+
58
+ it("should support chaining childEndpoint()", () => {
59
+ const creator = new EndpointCreator({ endpoint: "articles", id: "123" });
60
+ const result = creator.childEndpoint("comments");
61
+ expect(result).toBe(creator);
62
+ expect(creator.generate()).toBe("articles/123/comments");
63
+ });
64
+
65
+ it("should support chaining childId()", () => {
66
+ const creator = new EndpointCreator({
67
+ endpoint: "articles",
68
+ id: "123",
69
+ childEndpoint: "comments",
70
+ });
71
+ const result = creator.childId("456");
72
+ expect(result).toBe(creator);
73
+ expect(creator.generate()).toBe("articles/123/comments/456");
74
+ });
75
+
76
+ it("should support full fluent chain", () => {
77
+ const creator = new EndpointCreator({ endpoint: "articles" })
78
+ .id("123")
79
+ .childEndpoint("comments")
80
+ .childId("456");
81
+ expect(creator.generate()).toBe("articles/123/comments/456");
82
+ });
83
+ });
84
+
85
+ describe("query parameters", () => {
86
+ it("should add additional params", () => {
87
+ const creator = new EndpointCreator({
88
+ endpoint: "articles",
89
+ additionalParams: [{ key: "page", value: "1" }],
90
+ });
91
+ expect(creator.generate()).toBe("articles?page=1");
92
+ });
93
+
94
+ it("should support addAdditionalParam()", () => {
95
+ const creator = new EndpointCreator({ endpoint: "articles" });
96
+ creator.addAdditionalParam("page", "1");
97
+ creator.addAdditionalParam("limit", "10");
98
+ expect(creator.generate()).toBe("articles?page=1&limit=10");
99
+ });
100
+
101
+ it("should support array values in params", () => {
102
+ const creator = new EndpointCreator({ endpoint: "articles" });
103
+ creator.addAdditionalParam("filter", ["tag1", "tag2"]);
104
+ expect(creator.generate()).toBe("articles?filter=tag1,tag2");
105
+ });
106
+
107
+ it("should combine URL and params", () => {
108
+ const creator = new EndpointCreator({
109
+ endpoint: "articles",
110
+ id: "123",
111
+ });
112
+ creator.addAdditionalParam("include", "author");
113
+ expect(creator.generate()).toBe("articles/123?include=author");
114
+ });
115
+ });
116
+
117
+ describe("limitToType", () => {
118
+ it("should add include param with single type", () => {
119
+ const creator = new EndpointCreator({ endpoint: "articles" });
120
+ creator.limitToType(["author"]);
121
+ expect(creator.generate()).toBe("articles?include=author");
122
+ });
123
+
124
+ it("should add include param with multiple types", () => {
125
+ const creator = new EndpointCreator({ endpoint: "articles" });
126
+ creator.limitToType(["author", "comments", "tags"]);
127
+ expect(creator.generate()).toBe("articles?include=author,comments,tags");
128
+ });
129
+ });
130
+
131
+ describe("limitToFields", () => {
132
+ it("should add fields param with single selector", () => {
133
+ const creator = new EndpointCreator({ endpoint: "articles" });
134
+ creator.limitToFields([{ type: "articles", fields: ["title", "body"] }]);
135
+ expect(creator.generate()).toBe("articles?fields[articles]=title,body");
136
+ });
137
+
138
+ it("should add fields param with multiple selectors", () => {
139
+ const creator = new EndpointCreator({ endpoint: "articles" });
140
+ creator.limitToFields([
141
+ { type: "articles", fields: ["title", "body"] },
142
+ { type: "authors", fields: ["name", "email"] },
143
+ ]);
144
+ expect(creator.generate()).toBe(
145
+ "articles?fields[articles]=title,body&fields[authors]=name,email"
146
+ );
147
+ });
148
+
149
+ it("should handle empty selectors array", () => {
150
+ const creator = new EndpointCreator({ endpoint: "articles" });
151
+ creator.limitToFields([]);
152
+ expect(creator.generate()).toBe("articles");
153
+ });
154
+ });
155
+
156
+ describe("module endpoint support", () => {
157
+ it("should work with module as child endpoint", () => {
158
+ const parentModule = createMockModule({ name: "users" });
159
+ const childModule = createMockModule({ name: "posts" });
160
+ const creator = new EndpointCreator({
161
+ endpoint: parentModule,
162
+ id: "1",
163
+ childEndpoint: childModule,
164
+ });
165
+ expect(creator.generate()).toBe("users/1/posts");
166
+ });
167
+ });
168
+ });
@@ -0,0 +1,109 @@
1
+ import { describe, it, expect, beforeEach, vi } from "vitest";
2
+ import { JsonApiDataFactory } from "../JsonApiDataFactory";
3
+ import { DataClassRegistry } from "../../registry/DataClassRegistry";
4
+ import { ApiDataInterface } from "../../interfaces/ApiDataInterface";
5
+
6
+ // Mock class that tracks createJsonApi calls
7
+ class MockDataClass implements Partial<ApiDataInterface> {
8
+ type = "articles";
9
+ id = "1";
10
+
11
+ createJsonApi = vi.fn((data: any) => ({
12
+ type: "articles",
13
+ attributes: data,
14
+ }));
15
+
16
+ get included() {
17
+ return [];
18
+ }
19
+ get createdAt() {
20
+ return new Date();
21
+ }
22
+ get updatedAt() {
23
+ return new Date();
24
+ }
25
+ get self() {
26
+ return "/articles/1";
27
+ }
28
+ get jsonApi() {
29
+ return { type: this.type, id: this.id };
30
+ }
31
+ generateApiUrl() {
32
+ return `/articles/${this.id}`;
33
+ }
34
+ dehydrate() {
35
+ return { jsonApi: this.jsonApi, included: [], allData: [] };
36
+ }
37
+ rehydrate(data: any) {
38
+ return this;
39
+ }
40
+ }
41
+
42
+ describe("JsonApiDataFactory", () => {
43
+ const mockModule = { name: "articles", model: MockDataClass };
44
+
45
+ beforeEach(() => {
46
+ DataClassRegistry.clear();
47
+ vi.clearAllMocks();
48
+ });
49
+
50
+ describe("create", () => {
51
+ it("should create JSON:API formatted data", () => {
52
+ DataClassRegistry.registerObjectClass(mockModule as any, MockDataClass as any);
53
+
54
+ const inputData = { title: "Test Article", body: "Content" };
55
+ const result = JsonApiDataFactory.create(mockModule as any, inputData);
56
+
57
+ expect(result).toEqual({
58
+ type: "articles",
59
+ attributes: inputData,
60
+ });
61
+ });
62
+
63
+ it("should use the registered class to create data", () => {
64
+ DataClassRegistry.registerObjectClass(mockModule as any, MockDataClass as any);
65
+
66
+ const inputData = { title: "Test" };
67
+ JsonApiDataFactory.create(mockModule as any, inputData);
68
+
69
+ // The create method should have been called
70
+ // Note: We can't directly verify createJsonApi was called since
71
+ // it's called on a new instance, but we can verify the output format
72
+ });
73
+
74
+ it("should throw for unregistered module", () => {
75
+ const unregisteredModule = { name: "unknown", model: MockDataClass };
76
+
77
+ expect(() =>
78
+ JsonApiDataFactory.create(unregisteredModule as any, { data: "test" })
79
+ ).toThrow("Class not registered for key: unknown");
80
+ });
81
+
82
+ it("should handle empty data", () => {
83
+ DataClassRegistry.registerObjectClass(mockModule as any, MockDataClass as any);
84
+
85
+ const result = JsonApiDataFactory.create(mockModule as any, {});
86
+
87
+ expect(result).toEqual({
88
+ type: "articles",
89
+ attributes: {},
90
+ });
91
+ });
92
+
93
+ it("should handle complex nested data", () => {
94
+ DataClassRegistry.registerObjectClass(mockModule as any, MockDataClass as any);
95
+
96
+ const complexData = {
97
+ title: "Test",
98
+ metadata: {
99
+ tags: ["tag1", "tag2"],
100
+ author: { name: "John", email: "john@example.com" },
101
+ },
102
+ };
103
+
104
+ const result = JsonApiDataFactory.create(mockModule as any, complexData);
105
+
106
+ expect(result.attributes).toEqual(complexData);
107
+ });
108
+ });
109
+ });
@@ -0,0 +1,151 @@
1
+ import { describe, it, expect, beforeEach, vi } from "vitest";
2
+ import { RehydrationFactory } from "../RehydrationFactory";
3
+ import { DataClassRegistry } from "../../registry/DataClassRegistry";
4
+ import { ApiDataInterface } from "../../interfaces/ApiDataInterface";
5
+ import { JsonApiHydratedDataInterface } from "../../interfaces/JsonApiHydratedDataInterface";
6
+
7
+ // Mock class that tracks rehydrate calls
8
+ class MockDataClass implements Partial<ApiDataInterface> {
9
+ type = "articles";
10
+ id = "1";
11
+ rehydratedData: JsonApiHydratedDataInterface | null = null;
12
+
13
+ rehydrate(data: JsonApiHydratedDataInterface) {
14
+ this.rehydratedData = data;
15
+ return this;
16
+ }
17
+
18
+ get included() {
19
+ return [];
20
+ }
21
+ get createdAt() {
22
+ return new Date();
23
+ }
24
+ get updatedAt() {
25
+ return new Date();
26
+ }
27
+ get self() {
28
+ return "/articles/1";
29
+ }
30
+ get jsonApi() {
31
+ return { type: this.type, id: this.id };
32
+ }
33
+ generateApiUrl() {
34
+ return `/articles/${this.id}`;
35
+ }
36
+ dehydrate() {
37
+ return { jsonApi: this.jsonApi, included: [], allData: [] };
38
+ }
39
+ createJsonApi(data: any) {
40
+ return { type: this.type, attributes: data };
41
+ }
42
+ }
43
+
44
+ describe("RehydrationFactory", () => {
45
+ const mockModule = { name: "articles", model: MockDataClass };
46
+
47
+ beforeEach(() => {
48
+ DataClassRegistry.clear();
49
+ });
50
+
51
+ describe("rehydrate", () => {
52
+ it("should rehydrate a single data object", () => {
53
+ DataClassRegistry.registerObjectClass(mockModule as any, MockDataClass as any);
54
+
55
+ const hydratedData: JsonApiHydratedDataInterface = {
56
+ jsonApi: { type: "articles", id: "1", attributes: { title: "Test" } },
57
+ included: [],
58
+ allData: [],
59
+ };
60
+
61
+ const result = RehydrationFactory.rehydrate(mockModule as any, hydratedData);
62
+
63
+ expect(result).toBeInstanceOf(MockDataClass);
64
+ expect((result as MockDataClass).rehydratedData).toBe(hydratedData);
65
+ });
66
+
67
+ it("should throw for unregistered module", () => {
68
+ const unregisteredModule = { name: "unknown", model: MockDataClass };
69
+
70
+ const hydratedData: JsonApiHydratedDataInterface = {
71
+ jsonApi: {},
72
+ included: [],
73
+ };
74
+
75
+ expect(() =>
76
+ RehydrationFactory.rehydrate(unregisteredModule as any, hydratedData)
77
+ ).toThrow("Class not registered for key: unknown");
78
+ });
79
+
80
+ it("should create a new instance for rehydration", () => {
81
+ DataClassRegistry.registerObjectClass(mockModule as any, MockDataClass as any);
82
+
83
+ const hydratedData1: JsonApiHydratedDataInterface = {
84
+ jsonApi: { type: "articles", id: "1" },
85
+ included: [],
86
+ };
87
+ const hydratedData2: JsonApiHydratedDataInterface = {
88
+ jsonApi: { type: "articles", id: "2" },
89
+ included: [],
90
+ };
91
+
92
+ const result1 = RehydrationFactory.rehydrate(mockModule as any, hydratedData1);
93
+ const result2 = RehydrationFactory.rehydrate(mockModule as any, hydratedData2);
94
+
95
+ // Each rehydration should create a new instance
96
+ expect(result1).not.toBe(result2);
97
+ });
98
+ });
99
+
100
+ describe("rehydrateList", () => {
101
+ it("should rehydrate an array of data objects", () => {
102
+ DataClassRegistry.registerObjectClass(mockModule as any, MockDataClass as any);
103
+
104
+ const hydratedDataList: JsonApiHydratedDataInterface[] = [
105
+ { jsonApi: { type: "articles", id: "1" }, included: [] },
106
+ { jsonApi: { type: "articles", id: "2" }, included: [] },
107
+ { jsonApi: { type: "articles", id: "3" }, included: [] },
108
+ ];
109
+
110
+ const results = RehydrationFactory.rehydrateList(mockModule as any, hydratedDataList);
111
+
112
+ expect(results).toHaveLength(3);
113
+ results.forEach((result, index) => {
114
+ expect(result).toBeInstanceOf(MockDataClass);
115
+ expect((result as MockDataClass).rehydratedData).toBe(hydratedDataList[index]);
116
+ });
117
+ });
118
+
119
+ it("should return empty array for empty input", () => {
120
+ DataClassRegistry.registerObjectClass(mockModule as any, MockDataClass as any);
121
+
122
+ const results = RehydrationFactory.rehydrateList(mockModule as any, []);
123
+
124
+ expect(results).toEqual([]);
125
+ });
126
+
127
+ it("should throw for unregistered module", () => {
128
+ const unregisteredModule = { name: "unknown", model: MockDataClass };
129
+
130
+ expect(() =>
131
+ RehydrationFactory.rehydrateList(unregisteredModule as any, [
132
+ { jsonApi: {}, included: [] },
133
+ ])
134
+ ).toThrow("Class not registered for key: unknown");
135
+ });
136
+
137
+ it("should create unique instances for each item", () => {
138
+ DataClassRegistry.registerObjectClass(mockModule as any, MockDataClass as any);
139
+
140
+ const hydratedDataList: JsonApiHydratedDataInterface[] = [
141
+ { jsonApi: { type: "articles", id: "1" }, included: [] },
142
+ { jsonApi: { type: "articles", id: "2" }, included: [] },
143
+ ];
144
+
145
+ const results = RehydrationFactory.rehydrateList(mockModule as any, hydratedDataList);
146
+
147
+ // Each item should be a unique instance
148
+ expect(results[0]).not.toBe(results[1]);
149
+ });
150
+ });
151
+ });
package/src/core/index.ts CHANGED
@@ -29,13 +29,21 @@ export * from "../utils";
29
29
  export * from "../permissions";
30
30
 
31
31
  // Feature data classes, interfaces, and modules
32
+ export * from "../features/auth/auth.module";
32
33
  export * from "../features/auth/data";
33
34
  export * from "../features/auth/enums";
34
- export * from "../features/auth/auth.module";
35
- export * from "../features/company/data";
35
+ export * from "../features/billing/data";
36
+ export * from "../features/billing/modules";
37
+ export * from "../features/billing/stripe-customer";
38
+ export * from "../features/billing/stripe-invoice";
39
+ export * from "../features/billing/stripe-price";
40
+ export * from "../features/billing/stripe-product";
41
+ export * from "../features/billing/stripe-subscription";
42
+ export * from "../features/billing/stripe-usage";
36
43
  export * from "../features/company/company.module";
37
- export * from "../features/content/data";
44
+ export * from "../features/company/data";
38
45
  export * from "../features/content/content.module";
46
+ export * from "../features/content/data";
39
47
  export * from "../features/feature/data";
40
48
  export * from "../features/feature/feature.module";
41
49
  export * from "../features/module";
@@ -47,6 +55,6 @@ export * from "../features/role/data";
47
55
  export * from "../features/role/role.module";
48
56
  export * from "../features/s3";
49
57
  export * from "../features/search";
58
+ export * from "../features/user/author.module";
50
59
  export * from "../features/user/data";
51
60
  export * from "../features/user/user.module";
52
- export * from "../features/user/author.module";
@@ -4,6 +4,7 @@ export interface ApiResponseInterface {
4
4
  ok: boolean;
5
5
  response: number;
6
6
  raw?: any;
7
+ meta?: Record<string, any>;
7
8
 
8
9
  self?: string;
9
10
  next?: string;
@@ -1,6 +1,6 @@
1
- import { ApiRequestDataTypeInterface } from "../interfaces/ApiRequestDataTypeInterface";
2
1
  import { ModuleWithPermissions } from "../../permissions/types";
3
- import { tryBootstrap, hasBootstrapper } from "./bootstrapStore";
2
+ import { ApiRequestDataTypeInterface } from "../interfaces/ApiRequestDataTypeInterface";
3
+ import { hasBootstrapper, tryBootstrap } from "./bootstrapStore";
4
4
 
5
5
  // Foundation module types - defined by LIBRARY
6
6
  export interface FoundationModuleDefinitions {
@@ -17,6 +17,15 @@ export interface FoundationModuleDefinitions {
17
17
  Content: ModuleWithPermissions;
18
18
  UserTopic: ModuleWithPermissions;
19
19
  UserExpertise: ModuleWithPermissions;
20
+ // Billing modules - READ: all users, UPDATE: CompanyAdministrator, ADMIN: Administrator
21
+ Billing: ModuleWithPermissions;
22
+ StripeCustomer: ModuleWithPermissions;
23
+ StripePaymentMethod: ModuleWithPermissions;
24
+ StripeSubscription: ModuleWithPermissions;
25
+ StripeInvoice: ModuleWithPermissions;
26
+ StripeProduct: ModuleWithPermissions;
27
+ StripePrice: ModuleWithPermissions;
28
+ StripeUsage: ModuleWithPermissions;
20
29
  }
21
30
 
22
31
  // App-specific modules - apps will augment this interface ONLY
@@ -0,0 +1,136 @@
1
+ import { describe, it, expect, beforeEach } from "vitest";
2
+ import { DataClassRegistry, DataClass } from "../DataClassRegistry";
3
+ import { createMockModule } from "../../../testing";
4
+ import { ApiDataInterface } from "../../interfaces/ApiDataInterface";
5
+
6
+ // Mock class for testing
7
+ class MockArticle implements Partial<ApiDataInterface> {
8
+ type = "articles";
9
+ id = "1";
10
+ get included() {
11
+ return [];
12
+ }
13
+ get createdAt() {
14
+ return new Date();
15
+ }
16
+ get updatedAt() {
17
+ return new Date();
18
+ }
19
+ get self() {
20
+ return "/articles/1";
21
+ }
22
+ get jsonApi() {
23
+ return { type: this.type, id: this.id };
24
+ }
25
+ generateApiUrl() {
26
+ return `/articles/${this.id}`;
27
+ }
28
+ dehydrate() {
29
+ return { jsonApi: this.jsonApi, included: [], allData: [] };
30
+ }
31
+ rehydrate(data: any) {
32
+ return this;
33
+ }
34
+ createJsonApi(data: any) {
35
+ return { type: this.type, attributes: data };
36
+ }
37
+ }
38
+
39
+ describe("DataClassRegistry", () => {
40
+ beforeEach(() => {
41
+ DataClassRegistry.clear();
42
+ });
43
+
44
+ describe("registerObjectClass", () => {
45
+ it("should register a class", () => {
46
+ const module = createMockModule({ name: "articles" });
47
+ DataClassRegistry.registerObjectClass(module, MockArticle as any);
48
+ expect(() => DataClassRegistry.get(module)).not.toThrow();
49
+ });
50
+
51
+ it("should not register duplicate classes", () => {
52
+ const module = createMockModule({ name: "articles" });
53
+ DataClassRegistry.registerObjectClass(module, MockArticle as any);
54
+ DataClassRegistry.registerObjectClass(module, MockArticle as any);
55
+ // Should not throw, just ignore duplicate
56
+ expect(() => DataClassRegistry.get(module)).not.toThrow();
57
+ });
58
+ });
59
+
60
+ describe("get", () => {
61
+ it("should retrieve registered class", () => {
62
+ const module = createMockModule({ name: "articles" });
63
+ DataClassRegistry.registerObjectClass(module, MockArticle as any);
64
+ const retrieved = DataClassRegistry.get(module);
65
+ expect(retrieved).toBe(MockArticle);
66
+ });
67
+
68
+ it("should throw for unregistered class", () => {
69
+ const module = createMockModule({ name: "unknown" });
70
+ expect(() => DataClassRegistry.get(module)).toThrow(
71
+ "Class not registered for key: unknown"
72
+ );
73
+ });
74
+ });
75
+
76
+ describe("bootstrap", () => {
77
+ it("should register all modules from object", () => {
78
+ const modules = {
79
+ Article: {
80
+ name: "articles",
81
+ model: MockArticle,
82
+ },
83
+ User: {
84
+ name: "users",
85
+ model: MockArticle,
86
+ },
87
+ };
88
+
89
+ DataClassRegistry.bootstrap(modules as any);
90
+
91
+ expect(() =>
92
+ DataClassRegistry.get({ name: "articles", model: MockArticle } as any)
93
+ ).not.toThrow();
94
+ expect(() =>
95
+ DataClassRegistry.get({ name: "users", model: MockArticle } as any)
96
+ ).not.toThrow();
97
+ });
98
+
99
+ it("should skip modules without model", () => {
100
+ const modules = {
101
+ Article: {
102
+ name: "articles",
103
+ model: MockArticle,
104
+ },
105
+ Invalid: {
106
+ name: "invalid",
107
+ // no model
108
+ },
109
+ };
110
+
111
+ DataClassRegistry.bootstrap(modules as any);
112
+
113
+ expect(() =>
114
+ DataClassRegistry.get({ name: "articles", model: MockArticle } as any)
115
+ ).not.toThrow();
116
+ expect(() =>
117
+ DataClassRegistry.get({ name: "invalid", model: null } as any)
118
+ ).toThrow();
119
+ });
120
+ });
121
+
122
+ describe("clear", () => {
123
+ it("should clear all registered classes", () => {
124
+ const module = createMockModule({ name: "articles" });
125
+ DataClassRegistry.registerObjectClass(module, MockArticle as any);
126
+ DataClassRegistry.clear();
127
+ expect(() => DataClassRegistry.get(module)).toThrow();
128
+ });
129
+ });
130
+
131
+ describe("DataClass alias", () => {
132
+ it("should be an alias for DataClassRegistry", () => {
133
+ expect(DataClass).toBe(DataClassRegistry);
134
+ });
135
+ });
136
+ });