@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,170 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { renderHook, act } from "@testing-library/react";
3
+ import { useDebounce } from "../useDebounce";
4
+
5
+ describe("useDebounce", () => {
6
+ beforeEach(() => {
7
+ vi.useFakeTimers();
8
+ });
9
+
10
+ afterEach(() => {
11
+ vi.useRealTimers();
12
+ });
13
+
14
+ it("should delay callback execution", () => {
15
+ const callback = vi.fn();
16
+ const { result } = renderHook(() => useDebounce(callback, 500));
17
+
18
+ act(() => {
19
+ result.current("test");
20
+ });
21
+
22
+ // Callback should not be called immediately
23
+ expect(callback).not.toHaveBeenCalled();
24
+
25
+ // Advance timers by 500ms
26
+ act(() => {
27
+ vi.advanceTimersByTime(500);
28
+ });
29
+
30
+ // Now callback should be called
31
+ expect(callback).toHaveBeenCalledTimes(1);
32
+ expect(callback).toHaveBeenCalledWith("test");
33
+ });
34
+
35
+ it("should reset timer on subsequent calls", () => {
36
+ const callback = vi.fn();
37
+ const { result } = renderHook(() => useDebounce(callback, 500));
38
+
39
+ act(() => {
40
+ result.current("first");
41
+ });
42
+
43
+ // Advance 300ms (less than delay)
44
+ act(() => {
45
+ vi.advanceTimersByTime(300);
46
+ });
47
+
48
+ // Call again - should reset timer
49
+ act(() => {
50
+ result.current("second");
51
+ });
52
+
53
+ // Advance another 300ms (total 600ms from first call, but only 300ms from second)
54
+ act(() => {
55
+ vi.advanceTimersByTime(300);
56
+ });
57
+
58
+ // Still not called
59
+ expect(callback).not.toHaveBeenCalled();
60
+
61
+ // Advance remaining 200ms
62
+ act(() => {
63
+ vi.advanceTimersByTime(200);
64
+ });
65
+
66
+ // Now should be called with the second argument
67
+ expect(callback).toHaveBeenCalledTimes(1);
68
+ expect(callback).toHaveBeenCalledWith("second");
69
+ });
70
+
71
+ it("should cancel pending call", () => {
72
+ const callback = vi.fn();
73
+ const { result } = renderHook(() => useDebounce(callback, 500));
74
+
75
+ act(() => {
76
+ result.current("test");
77
+ });
78
+
79
+ // Cancel before timer fires
80
+ act(() => {
81
+ result.current.cancel();
82
+ });
83
+
84
+ // Advance past delay
85
+ act(() => {
86
+ vi.advanceTimersByTime(600);
87
+ });
88
+
89
+ // Callback should not be called
90
+ expect(callback).not.toHaveBeenCalled();
91
+ });
92
+
93
+ it("should pass multiple arguments to callback", () => {
94
+ const callback = vi.fn();
95
+ const { result } = renderHook(() =>
96
+ useDebounce((a: string, b: number, c: boolean) => callback(a, b, c), 500)
97
+ );
98
+
99
+ act(() => {
100
+ result.current("hello", 42, true);
101
+ });
102
+
103
+ act(() => {
104
+ vi.advanceTimersByTime(500);
105
+ });
106
+
107
+ expect(callback).toHaveBeenCalledWith("hello", 42, true);
108
+ });
109
+
110
+ it("should update callback reference when callback changes", () => {
111
+ const callback1 = vi.fn();
112
+ const callback2 = vi.fn();
113
+
114
+ const { result, rerender } = renderHook(
115
+ ({ cb }) => useDebounce(cb, 500),
116
+ { initialProps: { cb: callback1 } }
117
+ );
118
+
119
+ act(() => {
120
+ result.current("test");
121
+ });
122
+
123
+ // Change callback before timer fires
124
+ rerender({ cb: callback2 });
125
+
126
+ act(() => {
127
+ vi.advanceTimersByTime(500);
128
+ });
129
+
130
+ // Should call the new callback
131
+ expect(callback1).not.toHaveBeenCalled();
132
+ expect(callback2).toHaveBeenCalledWith("test");
133
+ });
134
+
135
+ it("should handle different delay values", () => {
136
+ const callback = vi.fn();
137
+ const { result } = renderHook(() => useDebounce(callback, 1000));
138
+
139
+ act(() => {
140
+ result.current("test");
141
+ });
142
+
143
+ act(() => {
144
+ vi.advanceTimersByTime(500);
145
+ });
146
+
147
+ expect(callback).not.toHaveBeenCalled();
148
+
149
+ act(() => {
150
+ vi.advanceTimersByTime(500);
151
+ });
152
+
153
+ expect(callback).toHaveBeenCalledTimes(1);
154
+ });
155
+
156
+ it("should handle zero delay", () => {
157
+ const callback = vi.fn();
158
+ const { result } = renderHook(() => useDebounce(callback, 0));
159
+
160
+ act(() => {
161
+ result.current("test");
162
+ });
163
+
164
+ act(() => {
165
+ vi.advanceTimersByTime(0);
166
+ });
167
+
168
+ expect(callback).toHaveBeenCalledWith("test");
169
+ });
170
+ });
package/src/index.ts CHANGED
@@ -9,14 +9,17 @@ export * from "./core";
9
9
  export * from "./permissions";
10
10
 
11
11
  // JSON:API configuration (client-safe)
12
- export { configureJsonApi, getApiUrl, getAppUrl, getTrackablePages } from "./client/config";
12
+ export { configureJsonApi, getApiUrl, getAppUrl, getTrackablePages, getStripePublishableKey } from "./client/config";
13
13
 
14
14
  // I18n configuration (NOT hooks - those are in /hooks with "use client")
15
15
  export { configureI18n } from "./i18n";
16
16
  export type { I18nConfig } from "./i18n";
17
17
 
18
+ // Login configuration (multi-provider auth)
19
+ export { configureLogin } from "./login";
20
+ export type { LoginConfig } from "./login";
21
+
18
22
  // Roles configuration
19
- export { configureDiscord } from "./discord";
20
23
  export { configureRoles, getRoleId, isRolesConfigured } from "./roles";
21
24
  export type { RoleIdConfig } from "./roles";
22
25
 
@@ -0,0 +1,27 @@
1
+ let _useDiscordAuth: boolean = false;
2
+ let _useInternalAuth: boolean = true;
3
+ let _allowRegistration: boolean = true;
4
+
5
+ export interface LoginConfig {
6
+ useDiscordAuth: boolean;
7
+ useInternalAuth: boolean;
8
+ allowRegistration?: boolean;
9
+ }
10
+
11
+ export function configureLogin(params: LoginConfig): void {
12
+ _useDiscordAuth = params.useDiscordAuth;
13
+ _useInternalAuth = params.useInternalAuth;
14
+ _allowRegistration = params.allowRegistration ?? true;
15
+ }
16
+
17
+ export function isDiscordAuthEnabled(): boolean {
18
+ return _useDiscordAuth;
19
+ }
20
+
21
+ export function isInternalAuthEnabled(): boolean {
22
+ return _useInternalAuth;
23
+ }
24
+
25
+ export function isRegistrationAllowed(): boolean {
26
+ return _allowRegistration;
27
+ }
@@ -0,0 +1,2 @@
1
+ export { configureLogin, isDiscordAuthEnabled, isInternalAuthEnabled, isRegistrationAllowed } from "./config";
2
+ export type { LoginConfig } from "./config";
@@ -1,16 +1,26 @@
1
1
  "use client";
2
2
 
3
- import NextLink from "next/link";
4
- import { cn } from "../../utils/cn";
5
3
  import * as React from "react";
4
+ import { getI18nLink } from "../../i18n";
5
+ import { cn } from "../../utils/cn";
6
6
 
7
- // Create our custom Link props interface that extends Next.js Link
8
- export interface LinkProps extends React.ComponentPropsWithoutRef<typeof NextLink> {
7
+ // Create our custom Link props interface
8
+ // Note: We use 'any' for now since the actual Link is retrieved at runtime
9
+ export interface LinkProps {
10
+ href: string;
11
+ children: React.ReactNode;
9
12
  className?: string;
13
+ [key: string]: any;
10
14
  }
11
15
 
12
- const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(({ className, ...props }, ref) => {
13
- return <NextLink ref={ref} className={cn(`font-medium`, className)} {...props} />;
16
+ const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(({ className, href, children, ...props }, ref) => {
17
+ // Get the configured next-intl Link component at runtime (after i18n is configured)
18
+ const NextIntlLink = getI18nLink();
19
+ return (
20
+ <NextIntlLink prefetch={false} ref={ref} href={href} className={cn(`font-medium`, className)} {...props}>
21
+ {children}
22
+ </NextIntlLink>
23
+ );
14
24
  });
15
25
 
16
26
  Link.displayName = "Link";
@@ -0,0 +1,143 @@
1
+ import { ApiDataInterface } from "../../core/interfaces/ApiDataInterface";
2
+
3
+ export interface CreateMockApiDataOptions {
4
+ type: string;
5
+ id?: string;
6
+ attributes?: Record<string, any>;
7
+ relationships?: Record<string, any>;
8
+ included?: any[];
9
+ createdAt?: Date;
10
+ updatedAt?: Date;
11
+ self?: string;
12
+ }
13
+
14
+ /**
15
+ * Creates a mock ApiDataInterface object for testing.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';
20
+ *
21
+ * const mockArticle = createMockApiData({
22
+ * type: 'articles',
23
+ * id: '1',
24
+ * attributes: { title: 'Test Article', body: 'Content here' },
25
+ * });
26
+ * ```
27
+ *
28
+ * @example With relationships
29
+ * ```ts
30
+ * const mockArticle = createMockApiData({
31
+ * type: 'articles',
32
+ * id: '1',
33
+ * attributes: { title: 'Test' },
34
+ * relationships: {
35
+ * author: { data: { type: 'users', id: '42' } },
36
+ * },
37
+ * });
38
+ * ```
39
+ */
40
+ export function createMockApiData(options: CreateMockApiDataOptions): ApiDataInterface {
41
+ const {
42
+ type,
43
+ id = `mock-${type}-${Math.random().toString(36).substring(7)}`,
44
+ attributes = {},
45
+ relationships = {},
46
+ included = [],
47
+ createdAt = new Date(),
48
+ updatedAt = new Date(),
49
+ self,
50
+ } = options;
51
+
52
+ const jsonApiData = {
53
+ type,
54
+ id,
55
+ attributes: {
56
+ ...attributes,
57
+ createdAt: createdAt.toISOString(),
58
+ updatedAt: updatedAt.toISOString(),
59
+ },
60
+ relationships,
61
+ };
62
+
63
+ const mockData: ApiDataInterface = {
64
+ get included() {
65
+ return included;
66
+ },
67
+ get type() {
68
+ return type;
69
+ },
70
+ get id() {
71
+ return id;
72
+ },
73
+ get createdAt() {
74
+ return createdAt;
75
+ },
76
+ get updatedAt() {
77
+ return updatedAt;
78
+ },
79
+ get self() {
80
+ return self;
81
+ },
82
+ get jsonApi() {
83
+ return jsonApiData;
84
+ },
85
+ generateApiUrl: (params?: any) => {
86
+ const baseUrl = `/${type}/${id}`;
87
+ if (params) {
88
+ const searchParams = new URLSearchParams(params);
89
+ return `${baseUrl}?${searchParams.toString()}`;
90
+ }
91
+ return baseUrl;
92
+ },
93
+ dehydrate: () => ({
94
+ jsonApi: jsonApiData,
95
+ included,
96
+ allData: [jsonApiData],
97
+ }),
98
+ rehydrate: function (data: any) {
99
+ return this;
100
+ },
101
+ createJsonApi: (data: any) => ({
102
+ type,
103
+ id,
104
+ attributes: data,
105
+ }),
106
+ };
107
+
108
+ // Add attribute accessors to the mock object
109
+ Object.keys(attributes).forEach((key) => {
110
+ Object.defineProperty(mockData, key, {
111
+ get: () => attributes[key],
112
+ enumerable: true,
113
+ });
114
+ });
115
+
116
+ return mockData;
117
+ }
118
+
119
+ /**
120
+ * Creates an array of mock ApiDataInterface objects.
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * import { createMockApiDataList } from '@carlonicora/nextjs-jsonapi/testing';
125
+ *
126
+ * const mockArticles = createMockApiDataList('articles', 5, (index) => ({
127
+ * title: `Article ${index + 1}`,
128
+ * }));
129
+ * ```
130
+ */
131
+ export function createMockApiDataList(
132
+ type: string,
133
+ count: number,
134
+ attributesFactory?: (index: number) => Record<string, any>
135
+ ): ApiDataInterface[] {
136
+ return Array.from({ length: count }, (_, index) =>
137
+ createMockApiData({
138
+ type,
139
+ id: `${index + 1}`,
140
+ attributes: attributesFactory?.(index) ?? {},
141
+ })
142
+ );
143
+ }
@@ -0,0 +1,32 @@
1
+ import { ApiRequestDataTypeInterface } from "../../core/interfaces/ApiRequestDataTypeInterface";
2
+
3
+ export interface CreateMockModuleOptions {
4
+ name: string;
5
+ cache?: string;
6
+ inclusions?: ApiRequestDataTypeInterface["inclusions"];
7
+ }
8
+
9
+ /**
10
+ * Creates a mock module definition for testing.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { createMockModule } from '@carlonicora/nextjs-jsonapi/testing';
15
+ *
16
+ * const mockArticleModule = createMockModule({ name: 'articles' });
17
+ * ```
18
+ */
19
+ export function createMockModule(options: CreateMockModuleOptions): ApiRequestDataTypeInterface {
20
+ // Create a mock model class
21
+ class MockModel {
22
+ id = "mock-id";
23
+ type = options.name;
24
+ }
25
+
26
+ return {
27
+ name: options.name,
28
+ cache: options.cache,
29
+ inclusions: options.inclusions,
30
+ model: MockModel,
31
+ };
32
+ }
@@ -0,0 +1,93 @@
1
+ import { ApiResponseInterface } from "../../core/interfaces/ApiResponseInterface";
2
+ import { ApiDataInterface } from "../../core/interfaces/ApiDataInterface";
3
+
4
+ export interface CreateMockResponseOptions {
5
+ data?: ApiDataInterface | ApiDataInterface[] | null;
6
+ ok?: boolean;
7
+ response?: number;
8
+ error?: string;
9
+ meta?: Record<string, any>;
10
+ self?: string;
11
+ next?: string;
12
+ prev?: string;
13
+ }
14
+
15
+ /**
16
+ * Creates a mock API response for testing.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { createMockResponse, createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';
21
+ *
22
+ * const mockData = createMockApiData({ type: 'articles', id: '1' });
23
+ * const response = createMockResponse({ data: mockData, ok: true });
24
+ * ```
25
+ *
26
+ * @example With pagination
27
+ * ```ts
28
+ * const response = createMockResponse({
29
+ * data: [mockData],
30
+ * ok: true,
31
+ * next: '/articles?page=2',
32
+ * prev: '/articles?page=0',
33
+ * });
34
+ * ```
35
+ */
36
+ export function createMockResponse(options: CreateMockResponseOptions = {}): ApiResponseInterface {
37
+ const {
38
+ data = null,
39
+ ok = true,
40
+ response = ok ? 200 : 500,
41
+ error = ok ? "" : "Error",
42
+ meta,
43
+ self,
44
+ next,
45
+ prev,
46
+ } = options;
47
+
48
+ const mockResponse: ApiResponseInterface = {
49
+ ok,
50
+ response,
51
+ data: data as ApiDataInterface | ApiDataInterface[],
52
+ error,
53
+ meta,
54
+ self,
55
+ next,
56
+ prev,
57
+ };
58
+
59
+ // Add pagination methods if next/prev provided
60
+ if (next) {
61
+ mockResponse.nextPage = async () =>
62
+ createMockResponse({ ...options, next: undefined, prev: self });
63
+ }
64
+
65
+ if (prev) {
66
+ mockResponse.prevPage = async () =>
67
+ createMockResponse({ ...options, prev: undefined, next: self });
68
+ }
69
+
70
+ return mockResponse;
71
+ }
72
+
73
+ /**
74
+ * Creates a mock error response for testing error scenarios.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * import { createMockErrorResponse } from '@carlonicora/nextjs-jsonapi/testing';
79
+ *
80
+ * const errorResponse = createMockErrorResponse(404, 'Not Found');
81
+ * ```
82
+ */
83
+ export function createMockErrorResponse(
84
+ statusCode: number,
85
+ errorMessage: string
86
+ ): ApiResponseInterface {
87
+ return createMockResponse({
88
+ ok: false,
89
+ response: statusCode,
90
+ error: errorMessage,
91
+ data: null,
92
+ });
93
+ }
@@ -0,0 +1,79 @@
1
+ import { vi, type Mock } from "vitest";
2
+ import { ApiResponseInterface } from "../../core/interfaces/ApiResponseInterface";
3
+ import { createMockResponse } from "./createMockResponse";
4
+
5
+ export type MockApiMethod = Mock<(...args: any[]) => Promise<ApiResponseInterface>>;
6
+
7
+ export interface MockService {
8
+ get: MockApiMethod;
9
+ post: MockApiMethod;
10
+ put: MockApiMethod;
11
+ patch: MockApiMethod;
12
+ delete: MockApiMethod;
13
+ }
14
+
15
+ export interface CreateMockServiceOptions {
16
+ defaultResponse?: ApiResponseInterface;
17
+ }
18
+
19
+ /**
20
+ * Creates a mock service with Vitest mock functions for all HTTP methods.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import { createMockService, createMockResponse } from '@carlonicora/nextjs-jsonapi/testing';
25
+ *
26
+ * const mockService = createMockService();
27
+ * mockService.get.mockResolvedValue(createMockResponse({ data: mockData }));
28
+ *
29
+ * // Use in test
30
+ * expect(mockService.get).toHaveBeenCalled();
31
+ * ```
32
+ *
33
+ * @example With default response
34
+ * ```ts
35
+ * const mockService = createMockService({
36
+ * defaultResponse: createMockResponse({ ok: true, data: [] }),
37
+ * });
38
+ * ```
39
+ */
40
+ export function createMockService(options: CreateMockServiceOptions = {}): MockService {
41
+ const defaultResponse = options.defaultResponse ?? createMockResponse({ ok: true });
42
+
43
+ return {
44
+ get: vi.fn().mockResolvedValue(defaultResponse),
45
+ post: vi.fn().mockResolvedValue(defaultResponse),
46
+ put: vi.fn().mockResolvedValue(defaultResponse),
47
+ patch: vi.fn().mockResolvedValue(defaultResponse),
48
+ delete: vi.fn().mockResolvedValue(defaultResponse),
49
+ };
50
+ }
51
+
52
+ /**
53
+ * Creates a mock service that returns errors for all methods.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * import { createMockErrorService } from '@carlonicora/nextjs-jsonapi/testing';
58
+ *
59
+ * const errorService = createMockErrorService(500, 'Internal Server Error');
60
+ * ```
61
+ */
62
+ export function createMockErrorService(
63
+ statusCode: number = 500,
64
+ errorMessage: string = "Error"
65
+ ): MockService {
66
+ const errorResponse = createMockResponse({
67
+ ok: false,
68
+ response: statusCode,
69
+ error: errorMessage,
70
+ });
71
+
72
+ return {
73
+ get: vi.fn().mockResolvedValue(errorResponse),
74
+ post: vi.fn().mockResolvedValue(errorResponse),
75
+ put: vi.fn().mockResolvedValue(errorResponse),
76
+ patch: vi.fn().mockResolvedValue(errorResponse),
77
+ delete: vi.fn().mockResolvedValue(errorResponse),
78
+ };
79
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Test utilities for @carlonicora/nextjs-jsonapi
3
+ *
4
+ * Import from '@carlonicora/nextjs-jsonapi/testing'
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import {
9
+ * MockJsonApiProvider,
10
+ * renderWithProviders,
11
+ * createMockApiData,
12
+ * createMockResponse,
13
+ * createMockModule,
14
+ * createMockService,
15
+ * jsonApiMatchers,
16
+ * extendExpectWithJsonApiMatchers,
17
+ * } from '@carlonicora/nextjs-jsonapi/testing';
18
+ * ```
19
+ */
20
+
21
+ // Providers
22
+ export {
23
+ MockJsonApiProvider,
24
+ defaultMockConfig,
25
+ type MockJsonApiProviderProps,
26
+ } from "./providers/MockJsonApiProvider";
27
+
28
+ // Factories
29
+ export {
30
+ createMockModule,
31
+ type CreateMockModuleOptions,
32
+ } from "./factories/createMockModule";
33
+
34
+ export {
35
+ createMockResponse,
36
+ createMockErrorResponse,
37
+ type CreateMockResponseOptions,
38
+ } from "./factories/createMockResponse";
39
+
40
+ export {
41
+ createMockService,
42
+ createMockErrorService,
43
+ type MockService,
44
+ type MockApiMethod,
45
+ type CreateMockServiceOptions,
46
+ } from "./factories/createMockService";
47
+
48
+ export {
49
+ createMockApiData,
50
+ createMockApiDataList,
51
+ type CreateMockApiDataOptions,
52
+ } from "./factories/createMockApiData";
53
+
54
+ // Matchers
55
+ export {
56
+ jsonApiMatchers,
57
+ extendExpectWithJsonApiMatchers,
58
+ } from "./matchers/jsonApiMatchers";
59
+
60
+ // Utilities
61
+ export {
62
+ renderWithProviders,
63
+ render,
64
+ screen,
65
+ waitFor,
66
+ fireEvent,
67
+ within,
68
+ userEvent,
69
+ type RenderWithProvidersOptions,
70
+ } from "./utils/renderWithProviders";