@carlonicora/nextjs-jsonapi 3.28.2 → 4.0.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 (213) hide show
  1. package/dist/{BlockNoteEditor-36VL2TNM.js → BlockNoteEditor-BXMTGKDV.js} +21 -20
  2. package/dist/BlockNoteEditor-BXMTGKDV.js.map +1 -0
  3. package/dist/{BlockNoteEditor-4IDXT6ZU.mjs → BlockNoteEditor-FGVQP35E.mjs} +9 -8
  4. package/dist/{BlockNoteEditor-4IDXT6ZU.mjs.map → BlockNoteEditor-FGVQP35E.mjs.map} +1 -1
  5. package/dist/{BlockNoteViewer-KRTAFTUX.mjs → BlockNoteViewer-DQYT6IJW.mjs} +3 -3
  6. package/dist/{BlockNoteViewer-7BFNTN4E.js → BlockNoteViewer-YH7G66PS.js} +4 -4
  7. package/dist/{BlockNoteViewer-7BFNTN4E.js.map → BlockNoteViewer-YH7G66PS.js.map} +1 -1
  8. package/dist/{HandbookSectionInterface-DgYH--Ik.d.mts → HandbookSectionInterface-BYsmnPEz.d.mts} +1 -1
  9. package/dist/{HandbookSectionInterface-Ck1wZJ81.d.ts → HandbookSectionInterface-OePKPbqN.d.ts} +1 -1
  10. package/dist/{JsonApiRequest-UHOWNI3O.mjs → JsonApiRequest-MEP6AXDT.mjs} +2 -2
  11. package/dist/JsonApiRequest-OB6WL4LA.js +26 -0
  12. package/dist/{JsonApiRequest-TE5WD3WS.js.map → JsonApiRequest-OB6WL4LA.js.map} +1 -1
  13. package/dist/ServerSession-DFNNNkg7.d.ts +29 -0
  14. package/dist/ServerSession-DK1z0_Ql.d.mts +29 -0
  15. package/dist/{analytics.modules-CfczU12P.d.ts → analytics.modules-Bsacu6ik.d.ts} +1 -1
  16. package/dist/{analytics.modules-pzGwMASI.d.mts → analytics.modules-txdCLNG-.d.mts} +1 -1
  17. package/dist/billing/index.js +404 -402
  18. package/dist/billing/index.js.map +1 -1
  19. package/dist/billing/index.mjs +10 -8
  20. package/dist/billing/index.mjs.map +1 -1
  21. package/dist/{chunk-7B4E42R5.mjs → chunk-3CZ2GK5R.mjs} +33 -9
  22. package/dist/chunk-3CZ2GK5R.mjs.map +1 -0
  23. package/dist/{chunk-4Z45NYPR.js → chunk-5W5MN7JP.js} +14 -83
  24. package/dist/chunk-5W5MN7JP.js.map +1 -0
  25. package/dist/{chunk-CAKOFJZD.js → chunk-6OFANJTE.js} +195 -142
  26. package/dist/chunk-6OFANJTE.js.map +1 -0
  27. package/dist/{chunk-5TRFNKJS.js → chunk-6TUB7Y6T.js} +23 -25
  28. package/dist/chunk-6TUB7Y6T.js.map +1 -0
  29. package/dist/{chunk-37DMFVLN.mjs → chunk-7SCREMTX.mjs} +4 -3
  30. package/dist/{chunk-37DMFVLN.mjs.map → chunk-7SCREMTX.mjs.map} +1 -1
  31. package/dist/{chunk-Q6J2ICKO.mjs → chunk-ADZSH3MG.mjs} +3 -72
  32. package/dist/chunk-ADZSH3MG.mjs.map +1 -0
  33. package/dist/{chunk-E3I4MT53.mjs → chunk-AQZ3T4BR.mjs} +71 -18
  34. package/dist/chunk-AQZ3T4BR.mjs.map +1 -0
  35. package/dist/{chunk-SJLXPHK5.mjs → chunk-E2LENTUH.mjs} +22 -24
  36. package/dist/chunk-E2LENTUH.mjs.map +1 -0
  37. package/dist/chunk-EBEXWN3I.mjs +17 -0
  38. package/dist/chunk-EBEXWN3I.mjs.map +1 -0
  39. package/dist/chunk-G4JR3SFV.js +28 -0
  40. package/dist/chunk-G4JR3SFV.js.map +1 -0
  41. package/dist/chunk-IK65TDQH.js +15 -0
  42. package/dist/chunk-IK65TDQH.js.map +1 -0
  43. package/dist/{chunk-GHFMKH3M.js → chunk-JEQ34Z5E.js} +62 -38
  44. package/dist/chunk-JEQ34Z5E.js.map +1 -0
  45. package/dist/{chunk-KOTKKBJT.js → chunk-NFCXUAE6.js} +1328 -1183
  46. package/dist/chunk-NFCXUAE6.js.map +1 -0
  47. package/dist/chunk-OEOK6A3P.js +17 -0
  48. package/dist/chunk-OEOK6A3P.js.map +1 -0
  49. package/dist/chunk-PW42LRSL.mjs +28 -0
  50. package/dist/chunk-PW42LRSL.mjs.map +1 -0
  51. package/dist/{chunk-U65JPKO3.mjs → chunk-R6ZYB4VN.mjs} +2 -2
  52. package/dist/chunk-T7SAW3UW.mjs +15 -0
  53. package/dist/chunk-T7SAW3UW.mjs.map +1 -0
  54. package/dist/{chunk-GKDHYB2R.js → chunk-TWBZ2GSX.js} +3 -3
  55. package/dist/{chunk-GKDHYB2R.js.map → chunk-TWBZ2GSX.js.map} +1 -1
  56. package/dist/{chunk-26MQIJNB.js → chunk-WGVNJXZO.js} +4 -3
  57. package/dist/chunk-WGVNJXZO.js.map +1 -0
  58. package/dist/{chunk-HPUV6FBW.mjs → chunk-WJC4SYRL.mjs} +2131 -1986
  59. package/dist/chunk-WJC4SYRL.mjs.map +1 -0
  60. package/dist/client/index.d.mts +3 -3
  61. package/dist/client/index.d.ts +3 -3
  62. package/dist/client/index.js +6 -5
  63. package/dist/client/index.js.map +1 -1
  64. package/dist/client/index.mjs +13 -12
  65. package/dist/components/index.d.mts +16 -6
  66. package/dist/components/index.d.ts +16 -6
  67. package/dist/components/index.js +8 -5
  68. package/dist/components/index.js.map +1 -1
  69. package/dist/components/index.mjs +9 -6
  70. package/dist/{config-3N1LSrcC.d.ts → config-B6UB7j69.d.ts} +1 -1
  71. package/dist/{config-BmufyEj6.d.mts → config-CEAq4Ozy.d.mts} +10 -1
  72. package/dist/{config-AVtuvfM1.d.ts → config-DydDHCfb.d.ts} +10 -1
  73. package/dist/{config-BSKTYDoh.d.mts → config-n-ZpPmOL.d.mts} +1 -1
  74. package/dist/contexts/index.d.mts +28 -4
  75. package/dist/contexts/index.d.ts +28 -4
  76. package/dist/contexts/index.js +10 -5
  77. package/dist/contexts/index.js.map +1 -1
  78. package/dist/contexts/index.mjs +9 -4
  79. package/dist/core/index.d.mts +6 -6
  80. package/dist/core/index.d.ts +6 -6
  81. package/dist/core/index.js +5 -5
  82. package/dist/core/index.js.map +1 -1
  83. package/dist/core/index.mjs +4 -4
  84. package/dist/features/analytics/index.d.mts +2 -2
  85. package/dist/features/analytics/index.d.ts +2 -2
  86. package/dist/features/analytics/index.js +124 -123
  87. package/dist/features/analytics/index.js.map +1 -1
  88. package/dist/features/analytics/index.mjs +6 -5
  89. package/dist/features/analytics/index.mjs.map +1 -1
  90. package/dist/features/analytics/server.d.mts +10 -2
  91. package/dist/features/analytics/server.d.ts +10 -2
  92. package/dist/features/analytics/server.js +8 -6
  93. package/dist/features/analytics/server.js.map +1 -1
  94. package/dist/features/analytics/server.mjs +6 -4
  95. package/dist/features/analytics/server.mjs.map +1 -1
  96. package/dist/features/help/index.d.mts +2 -2
  97. package/dist/features/help/index.d.ts +2 -2
  98. package/dist/features/help/index.js +39 -38
  99. package/dist/features/help/index.js.map +1 -1
  100. package/dist/features/help/index.mjs +5 -4
  101. package/dist/features/help/index.mjs.map +1 -1
  102. package/dist/features/tokenusage/index.d.mts +2 -2
  103. package/dist/features/tokenusage/index.d.ts +2 -2
  104. package/dist/features/tokenusage/index.js +127 -126
  105. package/dist/features/tokenusage/index.js.map +1 -1
  106. package/dist/features/tokenusage/index.mjs +6 -5
  107. package/dist/features/tokenusage/index.mjs.map +1 -1
  108. package/dist/index.d.mts +5 -5
  109. package/dist/index.d.ts +5 -5
  110. package/dist/index.js +8 -6
  111. package/dist/index.js.map +1 -1
  112. package/dist/index.mjs +11 -9
  113. package/dist/next-config/index.d.mts +43 -0
  114. package/dist/next-config/index.d.ts +43 -0
  115. package/dist/next-config/index.js +230 -0
  116. package/dist/next-config/index.js.map +1 -0
  117. package/dist/next-config/index.mjs +230 -0
  118. package/dist/next-config/index.mjs.map +1 -0
  119. package/dist/{request-FXF63NSQ.mjs → request-3IUMNVOS.mjs} +2 -2
  120. package/dist/request-LZBAOT3Y.js +8 -0
  121. package/dist/request-LZBAOT3Y.js.map +1 -0
  122. package/dist/server/cachedGet.d.mts +28 -0
  123. package/dist/server/cachedGet.d.ts +28 -0
  124. package/dist/server/cachedGet.js +60 -0
  125. package/dist/server/cachedGet.js.map +1 -0
  126. package/dist/server/cachedGet.mjs +60 -0
  127. package/dist/server/cachedGet.mjs.map +1 -0
  128. package/dist/server/cachedGet.stub.d.mts +7 -0
  129. package/dist/server/cachedGet.stub.d.ts +7 -0
  130. package/dist/server/cachedGet.stub.js +17 -0
  131. package/dist/server/cachedGet.stub.js.map +1 -0
  132. package/dist/server/cachedGet.stub.mjs +17 -0
  133. package/dist/server/cachedGet.stub.mjs.map +1 -0
  134. package/dist/server/index.d.mts +27 -25
  135. package/dist/server/index.d.ts +27 -25
  136. package/dist/server/index.js +13 -6
  137. package/dist/server/index.js.map +1 -1
  138. package/dist/server/index.mjs +15 -8
  139. package/dist/testing/index.js.map +1 -1
  140. package/dist/testing/index.mjs.map +1 -1
  141. package/dist/{types-D0uLYV2P.d.mts → types-Bq_UA8Lg.d.mts} +1 -1
  142. package/dist/{types-Cn153-mH.d.ts → types-bsm8Fp55.d.ts} +1 -1
  143. package/dist/{usePageUrlGenerator-B-3FRKBD.d.ts → usePageUrlGenerator-J_ECv-oQ.d.ts} +1 -1
  144. package/dist/{usePageUrlGenerator-CCJ_cdQy.d.mts → usePageUrlGenerator-uKBjAKqC.d.mts} +1 -1
  145. package/package.json +12 -1
  146. package/src/components/forms/__tests__/EditorSheet.test.tsx +25 -1
  147. package/src/components/forms/__tests__/useEditorDialog.test.ts +164 -1
  148. package/src/components/forms/useEditorDialog.ts +69 -2
  149. package/src/contexts/SessionContext.tsx +20 -0
  150. package/src/contexts/SocketContext.tsx +30 -3
  151. package/src/contexts/ViewportContext.tsx +17 -2
  152. package/src/contexts/__tests__/SessionContext.test.tsx +58 -0
  153. package/src/contexts/__tests__/SocketContext.session.test.tsx +77 -0
  154. package/src/contexts/index.ts +1 -0
  155. package/src/core/abstracts/AbstractService.ts +4 -6
  156. package/src/core/abstracts/__tests__/AbstractService.locale.test.ts +64 -0
  157. package/src/features/analytics/components/server/AnalyticsAdminPage.tsx +5 -1
  158. package/src/features/analytics/components/server/AnalyticsJourneyPage.tsx +5 -1
  159. package/src/features/notification/contexts/NotificationContext.tsx +5 -2
  160. package/src/features/notification/contexts/__tests__/NotificationContext.spec.tsx +22 -0
  161. package/src/features/user/contexts/CurrentUserContext.tsx +7 -5
  162. package/src/features/user/contexts/__tests__/CurrentUserContext.spec.tsx +63 -3
  163. package/src/hooks/__tests__/useSocket.render.test.ts +22 -0
  164. package/src/hooks/useSocket.ts +0 -1
  165. package/src/i18n/__tests__/config.test.ts +27 -0
  166. package/src/i18n/config.ts +17 -0
  167. package/src/i18n/index.ts +2 -0
  168. package/src/next-config/__tests__/createNextConfig.test.ts +268 -0
  169. package/src/next-config/csp.ts +128 -0
  170. package/src/next-config/headers.ts +61 -0
  171. package/src/next-config/index.ts +114 -0
  172. package/src/server/JsonApiServer.ts +3 -1
  173. package/src/server/ServerSession.ts +29 -1
  174. package/src/server/__tests__/JsonApiServer.test.ts +41 -0
  175. package/src/server/__tests__/ServerSession.read.test.ts +67 -0
  176. package/src/server/__tests__/cache.test.ts +48 -0
  177. package/src/server/__tests__/cachedGet.test.ts +125 -0
  178. package/src/server/__tests__/request.test.ts +96 -1
  179. package/src/server/cache.ts +21 -4
  180. package/src/server/cacheDigest.ts +10 -0
  181. package/src/server/cacheProfiles.ts +15 -0
  182. package/src/server/cachedGet.stub.ts +15 -0
  183. package/src/server/cachedGet.ts +80 -0
  184. package/src/server/request.ts +33 -32
  185. package/src/shadcnui/ui/__tests__/sidebar.menu-skeleton.test.tsx +50 -0
  186. package/src/shadcnui/ui/__tests__/sidebar.session.test.tsx +133 -0
  187. package/src/shadcnui/ui/sidebar.tsx +121 -18
  188. package/src/testing/matchers/jsonApiMatchers.ts +1 -0
  189. package/src/unified/JsonApiRequest.ts +4 -1
  190. package/src/unified/__tests__/JsonApiGet.cache.test.ts +51 -0
  191. package/src/utils/__tests__/map-thenable.test.ts +29 -0
  192. package/src/utils/__tests__/use-mobile.test.tsx +102 -1
  193. package/src/utils/map-thenable.ts +15 -0
  194. package/src/utils/use-mobile.tsx +13 -4
  195. package/dist/BlockNoteEditor-36VL2TNM.js.map +0 -1
  196. package/dist/JsonApiRequest-TE5WD3WS.js +0 -26
  197. package/dist/chunk-26MQIJNB.js.map +0 -1
  198. package/dist/chunk-4Z45NYPR.js.map +0 -1
  199. package/dist/chunk-5TRFNKJS.js.map +0 -1
  200. package/dist/chunk-7B4E42R5.mjs.map +0 -1
  201. package/dist/chunk-CAKOFJZD.js.map +0 -1
  202. package/dist/chunk-E3I4MT53.mjs.map +0 -1
  203. package/dist/chunk-GHFMKH3M.js.map +0 -1
  204. package/dist/chunk-HPUV6FBW.mjs.map +0 -1
  205. package/dist/chunk-KOTKKBJT.js.map +0 -1
  206. package/dist/chunk-Q6J2ICKO.mjs.map +0 -1
  207. package/dist/chunk-SJLXPHK5.mjs.map +0 -1
  208. package/dist/request-ZTX6I63X.js +0 -8
  209. package/dist/request-ZTX6I63X.js.map +0 -1
  210. /package/dist/{BlockNoteViewer-KRTAFTUX.mjs.map → BlockNoteViewer-DQYT6IJW.mjs.map} +0 -0
  211. /package/dist/{JsonApiRequest-UHOWNI3O.mjs.map → JsonApiRequest-MEP6AXDT.mjs.map} +0 -0
  212. /package/dist/{chunk-U65JPKO3.mjs.map → chunk-R6ZYB4VN.mjs.map} +0 -0
  213. /package/dist/{request-FXF63NSQ.mjs.map → request-3IUMNVOS.mjs.map} +0 -0
@@ -1,10 +1,11 @@
1
1
  import { A as ApiData } from '../ApiData-DPKNfY-9.mjs';
2
- import { a as ModuleWithPermissions, A as Action } from '../types-D0uLYV2P.mjs';
2
+ export { a as ServerSession, S as SessionSnapshot } from '../ServerSession-DK1z0_Ql.mjs';
3
3
  import { A as ApiRequestDataTypeInterface } from '../ApiRequestDataTypeInterface-CYEcRUrh.mjs';
4
4
  import { A as ApiResponseInterface } from '../ApiResponseInterface-rsXRL_Hn.mjs';
5
+ import { M as ModuleWithPermissions } from '../types-Bq_UA8Lg.mjs';
5
6
  export { A as ServerAuthService, C as ServerCompanyService, a as ServerContentService, F as ServerFeatureService, N as ServerNotificationService, P as ServerPushService, R as ServerRoleService, S as ServerS3Service, U as ServerUserService } from '../s3.service-DAp8FbuG.mjs';
6
- import 'lucide-react';
7
7
  import '../ApiDataInterface-BcZeXy5X.mjs';
8
+ import 'lucide-react';
8
9
  import '../AbstractService-Ckm2X5fW.mjs';
9
10
  import '../feature.interface-CXb1-vNq.mjs';
10
11
  import '../user.interface-CSaGWFbg.mjs';
@@ -12,21 +13,36 @@ import '../auth.interface-Df4vXbNz.mjs';
12
13
  import '../notification.interface-P_pNfzZQ.mjs';
13
14
 
14
15
  type CacheProfile = "seconds" | "minutes" | "hours" | "days" | "weeks" | "max" | "default";
16
+ /** The built-in `cacheLife` profile names. A module `cache` value outside this list is treated as a tag. */
17
+ declare const CACHE_PROFILES: readonly CacheProfile[];
18
+
15
19
  /**
16
20
  * Revalidate a cache tag to invalidate cached data.
17
21
  * Next.js 16+ requires a profile parameter.
18
22
  *
23
+ * With `"max"` the tagged entries are marked stale and served stale-while-revalidate
24
+ * (a one-year window): the next request still gets the old data while fresh data loads
25
+ * in the background. It is not an immediate invalidation. A Server Action that must
26
+ * read its own write uses `updateCacheTag` instead.
27
+ *
19
28
  * @param tag - The cache tag to invalidate
20
- * @param profile - The cache profile (defaults to "max" for immediate invalidation)
29
+ * @param profile - The cache profile whose `expire` bounds how long stale data may be served (defaults to "max")
21
30
  */
22
31
  declare function invalidateCacheTag(tag: string, profile?: CacheProfile): Promise<void>;
23
32
  /**
24
33
  * Revalidate multiple cache tags.
25
34
  *
26
35
  * @param tags - Array of cache tags to invalidate
27
- * @param profile - The cache profile (defaults to "max" for immediate invalidation)
36
+ * @param profile - The cache profile, see `invalidateCacheTag` (defaults to "max", stale-while-revalidate)
28
37
  */
29
38
  declare function invalidateCacheTags(tags: string[], profile?: CacheProfile): Promise<void>;
39
+ /**
40
+ * Expire a cache tag immediately, so the same request reads fresh data (read-your-own-writes).
41
+ * Wraps `updateTag`, which works in Server Actions only. Route Handlers use `invalidateCacheTag`.
42
+ *
43
+ * @param tag - The cache tag to expire
44
+ */
45
+ declare function updateCacheTag(tag: string): Promise<void>;
30
46
 
31
47
  interface ServerRequestParams {
32
48
  method: string;
@@ -42,29 +58,15 @@ interface ServerRequestParams {
42
58
  additionalHeaders?: Record<string, string>;
43
59
  }
44
60
  /**
45
- * Server-side request with Next.js caching support.
46
- * Uses fetch's native caching options for Next.js compatibility.
61
+ * Server-side request.
62
+ *
63
+ * - A GET with a `cache` value goes through `cachedServerGet`, a token-free `"use cache"`
64
+ * function. The token is never sent on that path.
65
+ * - Everything else (uncached GET, POST, PUT, PATCH, DELETE) is a plain uncached `fetch`
66
+ * that sends the token.
47
67
  */
48
68
  declare function serverRequest(params: ServerRequestParams): Promise<ApiData>;
49
69
 
50
- declare class ServerSession {
51
- static isLogged(): Promise<boolean>;
52
- static companyId(): Promise<string>;
53
- static userId(): Promise<string>;
54
- static checkPermission<M extends ModuleWithPermissions>(params: {
55
- module: M;
56
- action: Action;
57
- data?: any;
58
- }): Promise<void>;
59
- static hasRole(roleId: string): Promise<boolean>;
60
- static hasFeature(featureId: string): Promise<boolean>;
61
- static hasPermissionToModule<M extends ModuleWithPermissions>(params: {
62
- module: M;
63
- action: Action;
64
- data?: any;
65
- }): Promise<boolean>;
66
- }
67
-
68
70
  /**
69
71
  * Get the authentication token from cookies (server-side)
70
72
  */
@@ -133,4 +135,4 @@ declare function ServerJsonApiDelete(params: {
133
135
  responseType?: ApiRequestDataTypeInterface;
134
136
  }): Promise<ApiResponseInterface>;
135
137
 
136
- export { type CacheProfile, ServerJsonApiDelete, ServerJsonApiGet, ServerJsonApiPatch, ServerJsonApiPost, ServerJsonApiPut, type ServerRequestParams, ServerSession, configureServerJsonApi, getServerApiUrl, getServerAppUrl, getServerToken, getServerTrackablePages, invalidateCacheTag, invalidateCacheTags, serverRequest };
138
+ export { CACHE_PROFILES, type CacheProfile, ServerJsonApiDelete, ServerJsonApiGet, ServerJsonApiPatch, ServerJsonApiPost, ServerJsonApiPut, type ServerRequestParams, configureServerJsonApi, getServerApiUrl, getServerAppUrl, getServerToken, getServerTrackablePages, invalidateCacheTag, invalidateCacheTags, serverRequest, updateCacheTag };
@@ -1,10 +1,11 @@
1
1
  import { A as ApiData } from '../ApiData-DPKNfY-9.js';
2
- import { a as ModuleWithPermissions, A as Action } from '../types-Cn153-mH.js';
2
+ export { a as ServerSession, S as SessionSnapshot } from '../ServerSession-DFNNNkg7.js';
3
3
  import { A as ApiRequestDataTypeInterface } from '../ApiRequestDataTypeInterface-CYEcRUrh.js';
4
4
  import { A as ApiResponseInterface } from '../ApiResponseInterface-CWLvSCvS.js';
5
+ import { M as ModuleWithPermissions } from '../types-bsm8Fp55.js';
5
6
  export { A as ServerAuthService, C as ServerCompanyService, a as ServerContentService, F as ServerFeatureService, N as ServerNotificationService, P as ServerPushService, R as ServerRoleService, S as ServerS3Service, U as ServerUserService } from '../s3.service-CbUa6a-8.js';
6
- import 'lucide-react';
7
7
  import '../ApiDataInterface-BcZeXy5X.js';
8
+ import 'lucide-react';
8
9
  import '../AbstractService-V3VGQMhL.js';
9
10
  import '../feature.interface-BO25VLlx.js';
10
11
  import '../user.interface-CrmwJLYW.js';
@@ -12,21 +13,36 @@ import '../auth.interface-BzI4onI_.js';
12
13
  import '../notification.interface-BNCvnVCW.js';
13
14
 
14
15
  type CacheProfile = "seconds" | "minutes" | "hours" | "days" | "weeks" | "max" | "default";
16
+ /** The built-in `cacheLife` profile names. A module `cache` value outside this list is treated as a tag. */
17
+ declare const CACHE_PROFILES: readonly CacheProfile[];
18
+
15
19
  /**
16
20
  * Revalidate a cache tag to invalidate cached data.
17
21
  * Next.js 16+ requires a profile parameter.
18
22
  *
23
+ * With `"max"` the tagged entries are marked stale and served stale-while-revalidate
24
+ * (a one-year window): the next request still gets the old data while fresh data loads
25
+ * in the background. It is not an immediate invalidation. A Server Action that must
26
+ * read its own write uses `updateCacheTag` instead.
27
+ *
19
28
  * @param tag - The cache tag to invalidate
20
- * @param profile - The cache profile (defaults to "max" for immediate invalidation)
29
+ * @param profile - The cache profile whose `expire` bounds how long stale data may be served (defaults to "max")
21
30
  */
22
31
  declare function invalidateCacheTag(tag: string, profile?: CacheProfile): Promise<void>;
23
32
  /**
24
33
  * Revalidate multiple cache tags.
25
34
  *
26
35
  * @param tags - Array of cache tags to invalidate
27
- * @param profile - The cache profile (defaults to "max" for immediate invalidation)
36
+ * @param profile - The cache profile, see `invalidateCacheTag` (defaults to "max", stale-while-revalidate)
28
37
  */
29
38
  declare function invalidateCacheTags(tags: string[], profile?: CacheProfile): Promise<void>;
39
+ /**
40
+ * Expire a cache tag immediately, so the same request reads fresh data (read-your-own-writes).
41
+ * Wraps `updateTag`, which works in Server Actions only. Route Handlers use `invalidateCacheTag`.
42
+ *
43
+ * @param tag - The cache tag to expire
44
+ */
45
+ declare function updateCacheTag(tag: string): Promise<void>;
30
46
 
31
47
  interface ServerRequestParams {
32
48
  method: string;
@@ -42,29 +58,15 @@ interface ServerRequestParams {
42
58
  additionalHeaders?: Record<string, string>;
43
59
  }
44
60
  /**
45
- * Server-side request with Next.js caching support.
46
- * Uses fetch's native caching options for Next.js compatibility.
61
+ * Server-side request.
62
+ *
63
+ * - A GET with a `cache` value goes through `cachedServerGet`, a token-free `"use cache"`
64
+ * function. The token is never sent on that path.
65
+ * - Everything else (uncached GET, POST, PUT, PATCH, DELETE) is a plain uncached `fetch`
66
+ * that sends the token.
47
67
  */
48
68
  declare function serverRequest(params: ServerRequestParams): Promise<ApiData>;
49
69
 
50
- declare class ServerSession {
51
- static isLogged(): Promise<boolean>;
52
- static companyId(): Promise<string>;
53
- static userId(): Promise<string>;
54
- static checkPermission<M extends ModuleWithPermissions>(params: {
55
- module: M;
56
- action: Action;
57
- data?: any;
58
- }): Promise<void>;
59
- static hasRole(roleId: string): Promise<boolean>;
60
- static hasFeature(featureId: string): Promise<boolean>;
61
- static hasPermissionToModule<M extends ModuleWithPermissions>(params: {
62
- module: M;
63
- action: Action;
64
- data?: any;
65
- }): Promise<boolean>;
66
- }
67
-
68
70
  /**
69
71
  * Get the authentication token from cookies (server-side)
70
72
  */
@@ -133,4 +135,4 @@ declare function ServerJsonApiDelete(params: {
133
135
  responseType?: ApiRequestDataTypeInterface;
134
136
  }): Promise<ApiResponseInterface>;
135
137
 
136
- export { type CacheProfile, ServerJsonApiDelete, ServerJsonApiGet, ServerJsonApiPatch, ServerJsonApiPost, ServerJsonApiPut, type ServerRequestParams, ServerSession, configureServerJsonApi, getServerApiUrl, getServerAppUrl, getServerToken, getServerTrackablePages, invalidateCacheTag, invalidateCacheTags, serverRequest };
138
+ export { CACHE_PROFILES, type CacheProfile, ServerJsonApiDelete, ServerJsonApiGet, ServerJsonApiPatch, ServerJsonApiPost, ServerJsonApiPut, type ServerRequestParams, configureServerJsonApi, getServerApiUrl, getServerAppUrl, getServerToken, getServerTrackablePages, invalidateCacheTag, invalidateCacheTags, serverRequest, updateCacheTag };
@@ -11,15 +11,19 @@
11
11
 
12
12
 
13
13
 
14
- var _chunkGHFMKH3Mjs = require('../chunk-GHFMKH3M.js');
15
14
 
16
-
17
- var _chunk5TRFNKJSjs = require('../chunk-5TRFNKJS.js');
15
+ var _chunkJEQ34Z5Ejs = require('../chunk-JEQ34Z5E.js');
18
16
 
19
17
 
20
18
  var _chunkYUO55Q5Ajs = require('../chunk-YUO55Q5A.js');
21
19
 
22
20
 
21
+ var _chunk6TUB7Y6Tjs = require('../chunk-6TUB7Y6T.js');
22
+
23
+
24
+ var _chunkIK65TDQHjs = require('../chunk-IK65TDQH.js');
25
+ require('../chunk-G4JR3SFV.js');
26
+
23
27
 
24
28
 
25
29
 
@@ -28,10 +32,11 @@ var _chunkYUO55Q5Ajs = require('../chunk-YUO55Q5A.js');
28
32
 
29
33
 
30
34
 
31
- var _chunkCAKOFJZDjs = require('../chunk-CAKOFJZD.js');
32
- require('../chunk-26MQIJNB.js');
35
+
36
+ var _chunk6OFANJTEjs = require('../chunk-6OFANJTE.js');
33
37
  require('../chunk-LXKSUWAV.js');
34
38
  require('../chunk-JTPRJNT2.js');
39
+ require('../chunk-WGVNJXZO.js');
35
40
  require('../chunk-7QVYU63E.js');
36
41
 
37
42
 
@@ -57,5 +62,7 @@ require('../chunk-7QVYU63E.js');
57
62
 
58
63
 
59
64
 
60
- exports.ServerAuthService = _chunkCAKOFJZDjs.AuthService; exports.ServerCompanyService = _chunkCAKOFJZDjs.CompanyService; exports.ServerContentService = _chunkCAKOFJZDjs.ContentService; exports.ServerFeatureService = _chunkCAKOFJZDjs.FeatureService; exports.ServerJsonApiDelete = _chunkGHFMKH3Mjs.ServerJsonApiDelete; exports.ServerJsonApiGet = _chunkGHFMKH3Mjs.ServerJsonApiGet; exports.ServerJsonApiPatch = _chunkGHFMKH3Mjs.ServerJsonApiPatch; exports.ServerJsonApiPost = _chunkGHFMKH3Mjs.ServerJsonApiPost; exports.ServerJsonApiPut = _chunkGHFMKH3Mjs.ServerJsonApiPut; exports.ServerNotificationService = _chunkCAKOFJZDjs.NotificationService; exports.ServerPushService = _chunkCAKOFJZDjs.PushService; exports.ServerRoleService = _chunkCAKOFJZDjs.RoleService; exports.ServerS3Service = _chunkCAKOFJZDjs.S3Service; exports.ServerSession = _chunkGHFMKH3Mjs.ServerSession; exports.ServerUserService = _chunkCAKOFJZDjs.UserService; exports.configureServerJsonApi = _chunkGHFMKH3Mjs.configureServerJsonApi; exports.getServerApiUrl = _chunkGHFMKH3Mjs.getServerApiUrl; exports.getServerAppUrl = _chunkGHFMKH3Mjs.getServerAppUrl; exports.getServerToken = _chunkYUO55Q5Ajs.getServerToken; exports.getServerTrackablePages = _chunkGHFMKH3Mjs.getServerTrackablePages; exports.invalidateCacheTag = _chunkGHFMKH3Mjs.invalidateCacheTag; exports.invalidateCacheTags = _chunkGHFMKH3Mjs.invalidateCacheTags; exports.serverRequest = _chunk5TRFNKJSjs.serverRequest;
65
+
66
+
67
+ exports.CACHE_PROFILES = _chunkIK65TDQHjs.CACHE_PROFILES; exports.ServerAuthService = _chunk6OFANJTEjs.AuthService; exports.ServerCompanyService = _chunk6OFANJTEjs.CompanyService; exports.ServerContentService = _chunk6OFANJTEjs.ContentService; exports.ServerFeatureService = _chunk6OFANJTEjs.FeatureService; exports.ServerJsonApiDelete = _chunkJEQ34Z5Ejs.ServerJsonApiDelete; exports.ServerJsonApiGet = _chunkJEQ34Z5Ejs.ServerJsonApiGet; exports.ServerJsonApiPatch = _chunkJEQ34Z5Ejs.ServerJsonApiPatch; exports.ServerJsonApiPost = _chunkJEQ34Z5Ejs.ServerJsonApiPost; exports.ServerJsonApiPut = _chunkJEQ34Z5Ejs.ServerJsonApiPut; exports.ServerNotificationService = _chunk6OFANJTEjs.NotificationService; exports.ServerPushService = _chunk6OFANJTEjs.PushService; exports.ServerRoleService = _chunk6OFANJTEjs.RoleService; exports.ServerS3Service = _chunk6OFANJTEjs.S3Service; exports.ServerSession = _chunkJEQ34Z5Ejs.ServerSession; exports.ServerUserService = _chunk6OFANJTEjs.UserService; exports.configureServerJsonApi = _chunkJEQ34Z5Ejs.configureServerJsonApi; exports.getServerApiUrl = _chunkJEQ34Z5Ejs.getServerApiUrl; exports.getServerAppUrl = _chunkJEQ34Z5Ejs.getServerAppUrl; exports.getServerToken = _chunkYUO55Q5Ajs.getServerToken; exports.getServerTrackablePages = _chunkJEQ34Z5Ejs.getServerTrackablePages; exports.invalidateCacheTag = _chunkJEQ34Z5Ejs.invalidateCacheTag; exports.invalidateCacheTags = _chunkJEQ34Z5Ejs.invalidateCacheTags; exports.serverRequest = _chunk6TUB7Y6Tjs.serverRequest; exports.updateCacheTag = _chunkJEQ34Z5Ejs.updateCacheTag;
61
68
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/server/index.js"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,uDAA6B;AAC7B;AACE;AACF,uDAA6B;AAC7B;AACE;AACF,uDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,uDAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,u6CAAC","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/server/index.js"}
1
+ {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/server/index.js"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,uDAA6B;AAC7B;AACE;AACF,uDAA6B;AAC7B;AACE;AACF,uDAA6B;AAC7B;AACE;AACF,uDAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,uDAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,2hDAAC","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/server/index.js"}
@@ -10,14 +10,19 @@ import {
10
10
  getServerAppUrl,
11
11
  getServerTrackablePages,
12
12
  invalidateCacheTag,
13
- invalidateCacheTags
14
- } from "../chunk-7B4E42R5.mjs";
15
- import {
16
- serverRequest
17
- } from "../chunk-SJLXPHK5.mjs";
13
+ invalidateCacheTags,
14
+ updateCacheTag
15
+ } from "../chunk-3CZ2GK5R.mjs";
18
16
  import {
19
17
  getServerToken
20
18
  } from "../chunk-F5UNXZ3J.mjs";
19
+ import {
20
+ serverRequest
21
+ } from "../chunk-E2LENTUH.mjs";
22
+ import {
23
+ CACHE_PROFILES
24
+ } from "../chunk-T7SAW3UW.mjs";
25
+ import "../chunk-PW42LRSL.mjs";
21
26
  import {
22
27
  AuthService,
23
28
  CompanyService,
@@ -28,12 +33,13 @@ import {
28
33
  RoleService,
29
34
  S3Service,
30
35
  UserService
31
- } from "../chunk-E3I4MT53.mjs";
32
- import "../chunk-37DMFVLN.mjs";
36
+ } from "../chunk-AQZ3T4BR.mjs";
33
37
  import "../chunk-AUXK7QSA.mjs";
34
38
  import "../chunk-PI56A4DG.mjs";
39
+ import "../chunk-7SCREMTX.mjs";
35
40
  import "../chunk-PAWJFY3S.mjs";
36
41
  export {
42
+ CACHE_PROFILES,
37
43
  AuthService as ServerAuthService,
38
44
  CompanyService as ServerCompanyService,
39
45
  ContentService as ServerContentService,
@@ -56,6 +62,7 @@ export {
56
62
  getServerTrackablePages,
57
63
  invalidateCacheTag,
58
64
  invalidateCacheTags,
59
- serverRequest
65
+ serverRequest,
66
+ updateCacheTag
60
67
  };
61
68
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/testing/index.js","../../src/testing/providers/MockJsonApiProvider.tsx","../../src/testing/factories/createMockModule.ts","../../src/testing/factories/createMockResponse.ts","../../src/testing/factories/createMockService.ts","../../src/testing/factories/createMockApiData.ts","../../src/testing/matchers/jsonApiMatchers.ts","../../src/testing/utils/renderWithProviders.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/testing/index.js","sourcesContent":[null,"\"use client\";\n\nimport React from \"react\";\nimport { JsonApiConfig, JsonApiContext } from \"../../client/context/JsonApiContext\";\n\nexport interface MockJsonApiProviderProps {\n children: React.ReactNode;\n config?: Partial<JsonApiConfig>;\n}\n\nconst defaultMockConfig: JsonApiConfig = {\n apiUrl: \"https://api.test.com\",\n tokenGetter: async () => \"mock-token-for-testing\",\n languageGetter: async () => \"en\",\n defaultHeaders: {},\n onError: () => {},\n cacheConfig: {\n defaultProfile: \"default\",\n },\n};\n\n/**\n * A test-friendly provider that wraps components with mock JSON:API context.\n *\n * @example\n * ```tsx\n * import { MockJsonApiProvider } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * render(\n * <MockJsonApiProvider>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n *\n * @example With custom config\n * ```tsx\n * render(\n * <MockJsonApiProvider config={{ apiUrl: 'https://custom.api.com' }}>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n */\nexport function MockJsonApiProvider({ children, config }: MockJsonApiProviderProps) {\n const mergedConfig: JsonApiConfig = {\n ...defaultMockConfig,\n ...config,\n };\n\n return <JsonApiContext.Provider value={mergedConfig}>{children}</JsonApiContext.Provider>;\n}\n\nexport { defaultMockConfig };\n","import { ApiRequestDataTypeInterface } from \"../../core/interfaces/ApiRequestDataTypeInterface\";\n\nexport interface CreateMockModuleOptions {\n name: string;\n cache?: string;\n inclusions?: ApiRequestDataTypeInterface[\"inclusions\"];\n}\n\n/**\n * Creates a mock module definition for testing.\n *\n * @example\n * ```ts\n * import { createMockModule } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticleModule = createMockModule({ name: 'articles' });\n * ```\n */\nexport function createMockModule(options: CreateMockModuleOptions): ApiRequestDataTypeInterface {\n // Create a mock model class\n class MockModel {\n id = \"mock-id\";\n type = options.name;\n }\n\n return {\n name: options.name,\n cache: options.cache,\n inclusions: options.inclusions,\n model: MockModel,\n };\n}\n","import { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockResponseOptions {\n data?: ApiDataInterface | ApiDataInterface[] | null;\n ok?: boolean;\n response?: number;\n error?: string;\n meta?: Record<string, any>;\n self?: string;\n next?: string;\n prev?: string;\n}\n\n/**\n * Creates a mock API response for testing.\n *\n * @example\n * ```ts\n * import { createMockResponse, createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockData = createMockApiData({ type: 'articles', id: '1' });\n * const response = createMockResponse({ data: mockData, ok: true });\n * ```\n *\n * @example With pagination\n * ```ts\n * const response = createMockResponse({\n * data: [mockData],\n * ok: true,\n * next: '/articles?page=2',\n * prev: '/articles?page=0',\n * });\n * ```\n */\nexport function createMockResponse(options: CreateMockResponseOptions = {}): ApiResponseInterface {\n const {\n data = null,\n ok = true,\n response = ok ? 200 : 500,\n error = ok ? \"\" : \"Error\",\n meta,\n self,\n next,\n prev,\n } = options;\n\n const mockResponse: ApiResponseInterface = {\n ok,\n response,\n data: data as ApiDataInterface | ApiDataInterface[],\n error,\n meta,\n self,\n next,\n prev,\n };\n\n // Add pagination methods if next/prev provided\n if (next) {\n mockResponse.nextPage = async () => createMockResponse({ ...options, next: undefined, prev: self });\n }\n\n if (prev) {\n mockResponse.prevPage = async () => createMockResponse({ ...options, prev: undefined, next: self });\n }\n\n return mockResponse;\n}\n\n/**\n * Creates a mock error response for testing error scenarios.\n *\n * @example\n * ```ts\n * import { createMockErrorResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorResponse = createMockErrorResponse(404, 'Not Found');\n * ```\n */\nexport function createMockErrorResponse(statusCode: number, errorMessage: string): ApiResponseInterface {\n return createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n data: null,\n });\n}\n","import { vi, type Mock } from \"vitest\";\nimport { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { createMockResponse } from \"./createMockResponse\";\n\nexport type MockApiMethod = Mock<(...args: any[]) => Promise<ApiResponseInterface>>;\n\nexport interface MockService {\n get: MockApiMethod;\n post: MockApiMethod;\n put: MockApiMethod;\n patch: MockApiMethod;\n delete: MockApiMethod;\n}\n\nexport interface CreateMockServiceOptions {\n defaultResponse?: ApiResponseInterface;\n}\n\n/**\n * Creates a mock service with Vitest mock functions for all HTTP methods.\n *\n * @example\n * ```ts\n * import { createMockService, createMockResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockService = createMockService();\n * mockService.get.mockResolvedValue(createMockResponse({ data: mockData }));\n *\n * // Use in test\n * expect(mockService.get).toHaveBeenCalled();\n * ```\n *\n * @example With default response\n * ```ts\n * const mockService = createMockService({\n * defaultResponse: createMockResponse({ ok: true, data: [] }),\n * });\n * ```\n */\nexport function createMockService(options: CreateMockServiceOptions = {}): MockService {\n const defaultResponse = options.defaultResponse ?? createMockResponse({ ok: true });\n\n return {\n get: vi.fn().mockResolvedValue(defaultResponse),\n post: vi.fn().mockResolvedValue(defaultResponse),\n put: vi.fn().mockResolvedValue(defaultResponse),\n patch: vi.fn().mockResolvedValue(defaultResponse),\n delete: vi.fn().mockResolvedValue(defaultResponse),\n };\n}\n\n/**\n * Creates a mock service that returns errors for all methods.\n *\n * @example\n * ```ts\n * import { createMockErrorService } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorService = createMockErrorService(500, 'Internal Server Error');\n * ```\n */\nexport function createMockErrorService(statusCode: number = 500, errorMessage: string = \"Error\"): MockService {\n const errorResponse = createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n });\n\n return {\n get: vi.fn().mockResolvedValue(errorResponse),\n post: vi.fn().mockResolvedValue(errorResponse),\n put: vi.fn().mockResolvedValue(errorResponse),\n patch: vi.fn().mockResolvedValue(errorResponse),\n delete: vi.fn().mockResolvedValue(errorResponse),\n };\n}\n","import { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockApiDataOptions {\n type: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n included?: any[];\n createdAt?: Date;\n updatedAt?: Date;\n self?: string;\n}\n\n/**\n * Creates a mock ApiDataInterface object for testing.\n *\n * @example\n * ```ts\n * import { createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test Article', body: 'Content here' },\n * });\n * ```\n *\n * @example With relationships\n * ```ts\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test' },\n * relationships: {\n * author: { data: { type: 'users', id: '42' } },\n * },\n * });\n * ```\n */\nexport function createMockApiData(options: CreateMockApiDataOptions): ApiDataInterface {\n const {\n type,\n id = `mock-${type}-${Math.random().toString(36).substring(7)}`,\n attributes = {},\n relationships = {},\n included = [],\n createdAt = new Date(),\n updatedAt = new Date(),\n self,\n } = options;\n\n const jsonApiData = {\n type,\n id,\n attributes: {\n ...attributes,\n createdAt: createdAt.toISOString(),\n updatedAt: updatedAt.toISOString(),\n },\n relationships,\n };\n\n const mockData: ApiDataInterface = {\n get included() {\n return included;\n },\n get type() {\n return type;\n },\n get id() {\n return id;\n },\n get createdAt() {\n return createdAt;\n },\n get updatedAt() {\n return updatedAt;\n },\n get self() {\n return self;\n },\n get jsonApi() {\n return jsonApiData;\n },\n generateApiUrl: (params?: any) => {\n const baseUrl = `/${type}/${id}`;\n if (params) {\n const searchParams = new URLSearchParams(params);\n return `${baseUrl}?${searchParams.toString()}`;\n }\n return baseUrl;\n },\n dehydrate: () => ({\n jsonApi: jsonApiData,\n included,\n allData: [jsonApiData],\n }),\n rehydrate: function (_data: any) {\n return this;\n },\n createJsonApi: (data: any) => ({\n type,\n id,\n attributes: data,\n }),\n get identifier() {\n const identifierFields = [\"name\"];\n return identifierFields\n .map((field) => attributes[field])\n .filter((v) => v != null && v !== \"\")\n .join(\" \");\n },\n };\n\n // Add attribute accessors to the mock object\n Object.keys(attributes).forEach((key) => {\n Object.defineProperty(mockData, key, {\n get: () => attributes[key],\n enumerable: true,\n });\n });\n\n return mockData;\n}\n\n/**\n * Creates an array of mock ApiDataInterface objects.\n *\n * @example\n * ```ts\n * import { createMockApiDataList } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticles = createMockApiDataList('articles', 5, (index) => ({\n * title: `Article ${index + 1}`,\n * }));\n * ```\n */\nexport function createMockApiDataList(\n type: string,\n count: number,\n attributesFactory?: (index: number) => Record<string, any>,\n): ApiDataInterface[] {\n return Array.from({ length: count }, (_, index) =>\n createMockApiData({\n type,\n id: `${index + 1}`,\n attributes: attributesFactory?.(index) ?? {},\n }),\n );\n}\n","import { expect } from \"vitest\";\n\ninterface JsonApiResponse {\n data?:\n | {\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }\n | Array<{\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }>;\n}\n\n/**\n * Custom Vitest matchers for JSON:API assertions.\n *\n * @example\n * ```ts\n * import { jsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n * import { expect } from 'vitest';\n *\n * expect.extend(jsonApiMatchers);\n *\n * // Then use in tests:\n * expect(response).toBeValidJsonApi();\n * expect(response).toHaveJsonApiType('articles');\n * expect(response).toHaveJsonApiAttribute('title', 'My Article');\n * expect(response).toHaveJsonApiRelationship('author');\n * ```\n */\nexport const jsonApiMatchers = {\n /**\n * Asserts that the response has a valid JSON:API structure with type and id.\n */\n toBeValidJsonApi(received: JsonApiResponse) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const hasType = typeof data?.type === \"string\" && data.type.length > 0;\n const hasId = typeof data?.id === \"string\" && data.id.length > 0;\n const isValid = hasType && hasId;\n\n return {\n pass: isValid,\n message: () =>\n isValid\n ? `Expected response not to be valid JSON:API, but it has type \"${data?.type}\" and id \"${data?.id}\"`\n : `Expected response to be valid JSON:API with type and id, but got type: ${JSON.stringify(data?.type)}, id: ${JSON.stringify(data?.id)}`,\n };\n },\n\n /**\n * Asserts that the response data has the expected JSON:API type.\n */\n toHaveJsonApiType(received: JsonApiResponse, expectedType: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const actualType = data?.type;\n const pass = actualType === expectedType;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have JSON:API type \"${expectedType}\"`\n : `Expected response to have JSON:API type \"${expectedType}\", but got \"${actualType}\"`,\n };\n },\n\n /**\n * Asserts that the response data has an attribute with the expected value.\n */\n toHaveJsonApiAttribute(received: JsonApiResponse, attributeName: string, expectedValue?: any) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const attributes = data?.attributes ?? {};\n const hasAttribute = attributeName in attributes;\n const actualValue = attributes[attributeName];\n\n if (expectedValue === undefined) {\n // Just check existence\n return {\n pass: hasAttribute,\n message: () =>\n hasAttribute\n ? `Expected response not to have JSON:API attribute \"${attributeName}\"`\n : `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found. Available attributes: ${Object.keys(attributes).join(\", \") || \"none\"}`,\n };\n }\n\n const valuesMatch = actualValue === expectedValue;\n return {\n pass: hasAttribute && valuesMatch,\n message: () =>\n hasAttribute && valuesMatch\n ? `Expected response not to have JSON:API attribute \"${attributeName}\" with value \"${expectedValue}\"`\n : !hasAttribute\n ? `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found`\n : `Expected JSON:API attribute \"${attributeName}\" to be \"${expectedValue}\", but got \"${actualValue}\"`,\n };\n },\n\n /**\n * Asserts that the response data has the specified relationship.\n */\n toHaveJsonApiRelationship(received: JsonApiResponse, relationshipName: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const relationships = data?.relationships ?? {};\n const hasRelationship = relationshipName in relationships;\n\n return {\n pass: hasRelationship,\n message: () =>\n hasRelationship\n ? `Expected response not to have JSON:API relationship \"${relationshipName}\"`\n : `Expected response to have JSON:API relationship \"${relationshipName}\", but it was not found. Available relationships: ${Object.keys(relationships).join(\", \") || \"none\"}`,\n };\n },\n\n /**\n * Asserts that the response data array has the expected length.\n */\n toHaveJsonApiLength(received: JsonApiResponse, expectedLength: number) {\n const data = received?.data;\n const isArray = Array.isArray(data);\n const actualLength = isArray ? data.length : data ? 1 : 0;\n const pass = actualLength === expectedLength;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have ${expectedLength} items`\n : `Expected response to have ${expectedLength} items, but got ${actualLength}`,\n };\n },\n};\n\n// Type declarations for the custom matchers\n// Vitest 5: Assertion<R, T> and AsymmetricMatchersContaining both extend\n// Matchers<R, T>, so the matchers are declared once here and return R.\ndeclare module \"vitest\" {\n interface Matchers<R extends void | Promise<void> = void | Promise<void>, T = unknown> {\n toBeValidJsonApi(): R;\n toHaveJsonApiType(expectedType: string): R;\n toHaveJsonApiAttribute(attributeName: string, expectedValue?: any): R;\n toHaveJsonApiRelationship(relationshipName: string): R;\n toHaveJsonApiLength(expectedLength: number): R;\n }\n}\n\n/**\n * Extends Vitest's expect with JSON:API matchers.\n * Call this in your test setup file.\n *\n * @example\n * ```ts\n * // vitest.setup.ts\n * import { extendExpectWithJsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * extendExpectWithJsonApiMatchers();\n * ```\n */\nexport function extendExpectWithJsonApiMatchers(): void {\n expect.extend(jsonApiMatchers);\n}\n","\"use client\";\n\nimport React, { ReactElement } from \"react\";\nimport { render, RenderOptions, RenderResult } from \"@testing-library/react\";\nimport {\n MockJsonApiProvider,\n MockJsonApiProviderProps as _MockJsonApiProviderProps,\n} from \"../providers/MockJsonApiProvider\";\nimport { JsonApiConfig } from \"../../client/context/JsonApiContext\";\n\nexport interface RenderWithProvidersOptions extends Omit<RenderOptions, \"wrapper\"> {\n /**\n * Custom JSON:API configuration to pass to the mock provider.\n */\n jsonApiConfig?: Partial<JsonApiConfig>;\n\n /**\n * Additional wrapper component to wrap around the providers.\n */\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n}\n\n/**\n * Renders a component wrapped with all necessary providers for testing.\n *\n * @example\n * ```tsx\n * import { renderWithProviders } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const { getByText } = renderWithProviders(<MyComponent />);\n * expect(getByText('Hello')).toBeInTheDocument();\n * ```\n *\n * @example With custom config\n * ```tsx\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * jsonApiConfig: { apiUrl: 'https://custom.api.com' },\n * });\n * ```\n *\n * @example With additional wrapper\n * ```tsx\n * const CustomWrapper = ({ children }) => (\n * <ThemeProvider>{children}</ThemeProvider>\n * );\n *\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * wrapper: CustomWrapper,\n * });\n * ```\n */\nexport function renderWithProviders(ui: ReactElement, options: RenderWithProvidersOptions = {}): RenderResult {\n const { jsonApiConfig, wrapper: AdditionalWrapper, ...renderOptions } = options;\n\n function AllProviders({ children }: { children: React.ReactNode }) {\n const content = <MockJsonApiProvider config={jsonApiConfig}>{children}</MockJsonApiProvider>;\n\n if (AdditionalWrapper) {\n return <AdditionalWrapper>{content}</AdditionalWrapper>;\n }\n\n return content;\n }\n\n return render(ui, { wrapper: AllProviders, ...renderOptions });\n}\n\n/**\n * Re-export render utilities from Testing Library for convenience.\n */\nexport { render, screen, waitFor, fireEvent, within } from \"@testing-library/react\";\nexport { userEvent } from \"@testing-library/user-event\";\n"]}
1
+ {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/testing/index.js","../../src/testing/providers/MockJsonApiProvider.tsx","../../src/testing/factories/createMockModule.ts","../../src/testing/factories/createMockResponse.ts","../../src/testing/factories/createMockService.ts","../../src/testing/factories/createMockApiData.ts","../../src/testing/matchers/jsonApiMatchers.ts","../../src/testing/utils/renderWithProviders.tsx"],"names":[],"mappings":"AAAA;AACE;AACF,uDAA6B;AAC7B;AACE;AACF,uDAA6B;AAC7B;AACA;AC2CS,+CAAA;AAxCT,IAAM,kBAAA,EAAmC;AAAA,EACvC,MAAA,EAAQ,sBAAA;AAAA,EACR,WAAA,kBAAa,qCAAA,MAAA,CAAA,EAAA,GAAY,wBAAA,EAAZ,aAAA,CAAA;AAAA,EACb,cAAA,kBAAgB,qCAAA,MAAA,CAAA,EAAA,GAAY,IAAA,EAAZ,gBAAA,CAAA;AAAA,EAChB,cAAA,EAAgB,CAAC,CAAA;AAAA,EACjB,OAAA,kBAAS,qCAAA,CAAA,EAAA,GAAM;AAAA,EAAC,CAAA,EAAP,SAAA,CAAA;AAAA,EACT,WAAA,EAAa;AAAA,IACX,cAAA,EAAgB;AAAA,EAClB;AACF,CAAA;AAyBO,SAAS,mBAAA,CAAoB,EAAE,QAAA,EAAU,OAAO,CAAA,EAA6B;AAClF,EAAA,MAAM,aAAA,EAA8B;AAAA,IAClC,GAAG,iBAAA;AAAA,IACH,GAAG;AAAA,EACL,CAAA;AAEA,EAAA,uBAAO,6BAAA,+BAAC,CAAe,QAAA,EAAf,EAAwB,KAAA,EAAO,YAAA,EAAe,SAAA,CAAS,CAAA;AACjE;AAPgB,qCAAA,mBAAA,EAAA,qBAAA,CAAA;ADhBhB;AACA;AEXO,SAAS,gBAAA,CAAiB,OAAA,EAA+D;AAAA,EAE9F,MAAM,UAAU;AAAA,IApBlB,OAoBkB;AAAA,MAAA,qCAAA,IAAA,EAAA,WAAA,CAAA;AAAA,IAAA;AAAA,mBACd,GAAA,EAAK,UAAA;AAAA,oBACL,KAAA,EAAO,OAAA,CAAQ,KAAA;AAAA,EACjB;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAA,CAAQ,IAAA;AAAA,IACd,KAAA,EAAO,OAAA,CAAQ,KAAA;AAAA,IACf,UAAA,EAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,KAAA,EAAO;AAAA,EACT,CAAA;AACF;AAbgB,qCAAA,gBAAA,EAAA,kBAAA,CAAA;AF4BhB;AACA;AGZO,SAAS,kBAAA,CAAmB,QAAA,EAAqC,CAAC,CAAA,EAAyB;AAChG,EAAA,MAAM;AAAA,IACJ,KAAA,EAAO,IAAA;AAAA,IACP,GAAA,EAAK,IAAA;AAAA,IACL,SAAA,EAAW,GAAA,EAAK,IAAA,EAAM,GAAA;AAAA,IACtB,MAAA,EAAQ,GAAA,EAAK,GAAA,EAAK,OAAA;AAAA,IAClB,IAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA;AAAA,EACF,EAAA,EAAI,OAAA;AAEJ,EAAA,MAAM,aAAA,EAAqC;AAAA,IACzC,EAAA;AAAA,IACA,QAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA;AAAA,EACF,CAAA;AAGA,EAAA,GAAA,CAAI,IAAA,EAAM;AACR,IAAA,YAAA,CAAa,SAAA,EAAW,MAAA,CAAA,EAAA,GAAY,kBAAA,CAAmB,EAAE,GAAG,OAAA,EAAS,IAAA,EAAM,KAAA,CAAA,EAAW,IAAA,EAAM,KAAK,CAAC,CAAA;AAAA,EACpG;AAEA,EAAA,GAAA,CAAI,IAAA,EAAM;AACR,IAAA,YAAA,CAAa,SAAA,EAAW,MAAA,CAAA,EAAA,GAAY,kBAAA,CAAmB,EAAE,GAAG,OAAA,EAAS,IAAA,EAAM,KAAA,CAAA,EAAW,IAAA,EAAM,KAAK,CAAC,CAAA;AAAA,EACpG;AAEA,EAAA,OAAO,YAAA;AACT;AAjCgB,qCAAA,kBAAA,EAAA,oBAAA,CAAA;AA6CT,SAAS,uBAAA,CAAwB,UAAA,EAAoB,YAAA,EAA4C;AACtG,EAAA,OAAO,kBAAA,CAAmB;AAAA,IACxB,EAAA,EAAI,KAAA;AAAA,IACJ,QAAA,EAAU,UAAA;AAAA,IACV,KAAA,EAAO,YAAA;AAAA,IACP,IAAA,EAAM;AAAA,EACR,CAAC,CAAA;AACH;AAPgB,qCAAA,uBAAA,EAAA,yBAAA,CAAA;AHOhB;AACA;AIxFA,gCAA8B;AAuCvB,SAAS,iBAAA,CAAkB,QAAA,EAAoC,CAAC,CAAA,EAAgB;AACrF,EAAA,MAAM,gBAAA,mBAAkB,OAAA,CAAQ,eAAA,UAAmB,kBAAA,CAAmB,EAAE,EAAA,EAAI,KAAK,CAAC,GAAA;AAElF,EAAA,OAAO;AAAA,IACL,GAAA,EAAK,UAAA,CAAG,EAAA,CAAG,CAAA,CAAE,iBAAA,CAAkB,eAAe,CAAA;AAAA,IAC9C,IAAA,EAAM,UAAA,CAAG,EAAA,CAAG,CAAA,CAAE,iBAAA,CAAkB,eAAe,CAAA;AAAA,IAC/C,GAAA,EAAK,UAAA,CAAG,EAAA,CAAG,CAAA,CAAE,iBAAA,CAAkB,eAAe,CAAA;AAAA,IAC9C,KAAA,EAAO,UAAA,CAAG,EAAA,CAAG,CAAA,CAAE,iBAAA,CAAkB,eAAe,CAAA;AAAA,IAChD,MAAA,EAAQ,UAAA,CAAG,EAAA,CAAG,CAAA,CAAE,iBAAA,CAAkB,eAAe;AAAA,EACnD,CAAA;AACF;AAVgB,qCAAA,iBAAA,EAAA,mBAAA,CAAA;AAsBT,SAAS,sBAAA,CAAuB,WAAA,EAAqB,GAAA,EAAK,aAAA,EAAuB,OAAA,EAAsB;AAC5G,EAAA,MAAM,cAAA,EAAgB,kBAAA,CAAmB;AAAA,IACvC,EAAA,EAAI,KAAA;AAAA,IACJ,QAAA,EAAU,UAAA;AAAA,IACV,KAAA,EAAO;AAAA,EACT,CAAC,CAAA;AAED,EAAA,OAAO;AAAA,IACL,GAAA,EAAK,UAAA,CAAG,EAAA,CAAG,CAAA,CAAE,iBAAA,CAAkB,aAAa,CAAA;AAAA,IAC5C,IAAA,EAAM,UAAA,CAAG,EAAA,CAAG,CAAA,CAAE,iBAAA,CAAkB,aAAa,CAAA;AAAA,IAC7C,GAAA,EAAK,UAAA,CAAG,EAAA,CAAG,CAAA,CAAE,iBAAA,CAAkB,aAAa,CAAA;AAAA,IAC5C,KAAA,EAAO,UAAA,CAAG,EAAA,CAAG,CAAA,CAAE,iBAAA,CAAkB,aAAa,CAAA;AAAA,IAC9C,MAAA,EAAQ,UAAA,CAAG,EAAA,CAAG,CAAA,CAAE,iBAAA,CAAkB,aAAa;AAAA,EACjD,CAAA;AACF;AAdgB,qCAAA,sBAAA,EAAA,wBAAA,CAAA;AJuDhB;AACA;AK9EO,SAAS,iBAAA,CAAkB,OAAA,EAAqD;AACrF,EAAA,MAAM;AAAA,IACJ,IAAA;AAAA,IACA,GAAA,EAAK,CAAA,KAAA,EAAQ,IAAI,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,CAAO,CAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,SAAA,CAAU,CAAC,CAAC,CAAA,CAAA;AAC9C,IAAA;AACG,IAAA;AACL,IAAA;AACS,IAAA;AACA,IAAA;AACrB,IAAA;AACE,EAAA;AAEgB,EAAA;AAClB,IAAA;AACA,IAAA;AACY,IAAA;AACP,MAAA;AAC8B,MAAA;AACA,MAAA;AACnC,IAAA;AACA,IAAA;AACF,EAAA;AAEmC,EAAA;AAClB,IAAA;AACN,MAAA;AACT,IAAA;AACW,IAAA;AACF,MAAA;AACT,IAAA;AACS,IAAA;AACA,MAAA;AACT,IAAA;AACgB,IAAA;AACP,MAAA;AACT,IAAA;AACgB,IAAA;AACP,MAAA;AACT,IAAA;AACW,IAAA;AACF,MAAA;AACT,IAAA;AACc,IAAA;AACL,MAAA;AACT,IAAA;AACkC,IAAA;AACF,MAAA;AAClB,MAAA;AACqC,QAAA;AACH,QAAA;AAC9C,MAAA;AACO,MAAA;AANO,IAAA;AAQE,IAAA;AACP,MAAA;AACT,MAAA;AACqB,MAAA;AAHZ,IAAA;AAKsB,IAAA;AACxB,MAAA;AADE,IAAA;AAGoB,IAAA;AAC7B,MAAA;AACA,MAAA;AACY,MAAA;AAHC,IAAA;AAKE,IAAA;AACiB,MAAA;AAG7B,MAAA;AAEL,IAAA;AACF,EAAA;AAGyC,EAAA;AACF,IAAA;AAC9B,MAAA;AACO,MAAA;AACb,IAAA;AACF,EAAA;AAEM,EAAA;AACT;AApFgB;AAsGM;AACP,EAAA;AAAqB,IAAA;AACd,IAAA;AAChB,MAAA;AACgB,MAAA;AAC2B,MAAA;AAC5C,IAAA;AACH,EAAA;AACF;AAZgB;ALsEiD;AACA;AMhN1C;AAmCQ;AAAA;AAAA;AAAA;AAIe,EAAA;AACkB,IAAA;AACA,IAAA;AACN,IAAA;AAC3B,IAAA;AAEpB,IAAA;AACC,MAAA;AAGA,MAAA;AAER,IAAA;AACF,EAAA;AAAA;AAAA;AAAA;AAKmE,EAAA;AACL,IAAA;AACnC,IAAA;AACG,IAAA;AAErB,IAAA;AACL,MAAA;AAGM,MAAA;AAER,IAAA;AACF,EAAA;AAAA;AAAA;AAAA;AAK8F,EAAA;AAChC,IAAA;AACpB,IAAA;AACF,IAAA;AACM,IAAA;AAEX,IAAA;AAExB,MAAA;AACC,QAAA;AAGA,QAAA;AAER,MAAA;AACF,IAAA;AAEoC,IAAA;AAC7B,IAAA;AACiB,MAAA;AAEJ,MAAA;AAKpB,IAAA;AACF,EAAA;AAAA;AAAA;AAAA;AAK+E,EAAA;AACjB,IAAA;AACd,IAAA;AACF,IAAA;AAErC,IAAA;AACC,MAAA;AAGA,MAAA;AAER,IAAA;AACF,EAAA;AAAA;AAAA;AAAA;AAKuE,EAAA;AAC9C,IAAA;AACW,IAAA;AACsB,IAAA;AAC1B,IAAA;AAEvB,IAAA;AACL,MAAA;AAGM,MAAA;AAER,IAAA;AACF,EAAA;AACF;AA4BwD;AACzB,EAAA;AAC/B;AAFgB;ANyHiD;AACA;AO5Rb;AAmEP;AACnB;AAhBN;AAJ0F;AACtD,EAAA;AAEa,EAAA;AAC5B,IAAA;AAEd,IAAA;AACM,MAAA;AAC7B,IAAA;AAEO,IAAA;AACT,EAAA;AARS,EAAA;AAUoD,EAAA;AAC/D;AAdgB;AP8PiD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/testing/index.js","sourcesContent":[null,"\"use client\";\n\nimport React from \"react\";\nimport { JsonApiConfig, JsonApiContext } from \"../../client/context/JsonApiContext\";\n\nexport interface MockJsonApiProviderProps {\n children: React.ReactNode;\n config?: Partial<JsonApiConfig>;\n}\n\nconst defaultMockConfig: JsonApiConfig = {\n apiUrl: \"https://api.test.com\",\n tokenGetter: async () => \"mock-token-for-testing\",\n languageGetter: async () => \"en\",\n defaultHeaders: {},\n onError: () => {},\n cacheConfig: {\n defaultProfile: \"default\",\n },\n};\n\n/**\n * A test-friendly provider that wraps components with mock JSON:API context.\n *\n * @example\n * ```tsx\n * import { MockJsonApiProvider } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * render(\n * <MockJsonApiProvider>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n *\n * @example With custom config\n * ```tsx\n * render(\n * <MockJsonApiProvider config={{ apiUrl: 'https://custom.api.com' }}>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n */\nexport function MockJsonApiProvider({ children, config }: MockJsonApiProviderProps) {\n const mergedConfig: JsonApiConfig = {\n ...defaultMockConfig,\n ...config,\n };\n\n return <JsonApiContext.Provider value={mergedConfig}>{children}</JsonApiContext.Provider>;\n}\n\nexport { defaultMockConfig };\n","import { ApiRequestDataTypeInterface } from \"../../core/interfaces/ApiRequestDataTypeInterface\";\n\nexport interface CreateMockModuleOptions {\n name: string;\n cache?: string;\n inclusions?: ApiRequestDataTypeInterface[\"inclusions\"];\n}\n\n/**\n * Creates a mock module definition for testing.\n *\n * @example\n * ```ts\n * import { createMockModule } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticleModule = createMockModule({ name: 'articles' });\n * ```\n */\nexport function createMockModule(options: CreateMockModuleOptions): ApiRequestDataTypeInterface {\n // Create a mock model class\n class MockModel {\n id = \"mock-id\";\n type = options.name;\n }\n\n return {\n name: options.name,\n cache: options.cache,\n inclusions: options.inclusions,\n model: MockModel,\n };\n}\n","import { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockResponseOptions {\n data?: ApiDataInterface | ApiDataInterface[] | null;\n ok?: boolean;\n response?: number;\n error?: string;\n meta?: Record<string, any>;\n self?: string;\n next?: string;\n prev?: string;\n}\n\n/**\n * Creates a mock API response for testing.\n *\n * @example\n * ```ts\n * import { createMockResponse, createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockData = createMockApiData({ type: 'articles', id: '1' });\n * const response = createMockResponse({ data: mockData, ok: true });\n * ```\n *\n * @example With pagination\n * ```ts\n * const response = createMockResponse({\n * data: [mockData],\n * ok: true,\n * next: '/articles?page=2',\n * prev: '/articles?page=0',\n * });\n * ```\n */\nexport function createMockResponse(options: CreateMockResponseOptions = {}): ApiResponseInterface {\n const {\n data = null,\n ok = true,\n response = ok ? 200 : 500,\n error = ok ? \"\" : \"Error\",\n meta,\n self,\n next,\n prev,\n } = options;\n\n const mockResponse: ApiResponseInterface = {\n ok,\n response,\n data: data as ApiDataInterface | ApiDataInterface[],\n error,\n meta,\n self,\n next,\n prev,\n };\n\n // Add pagination methods if next/prev provided\n if (next) {\n mockResponse.nextPage = async () => createMockResponse({ ...options, next: undefined, prev: self });\n }\n\n if (prev) {\n mockResponse.prevPage = async () => createMockResponse({ ...options, prev: undefined, next: self });\n }\n\n return mockResponse;\n}\n\n/**\n * Creates a mock error response for testing error scenarios.\n *\n * @example\n * ```ts\n * import { createMockErrorResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorResponse = createMockErrorResponse(404, 'Not Found');\n * ```\n */\nexport function createMockErrorResponse(statusCode: number, errorMessage: string): ApiResponseInterface {\n return createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n data: null,\n });\n}\n","import { vi, type Mock } from \"vitest\";\nimport { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { createMockResponse } from \"./createMockResponse\";\n\nexport type MockApiMethod = Mock<(...args: any[]) => Promise<ApiResponseInterface>>;\n\nexport interface MockService {\n get: MockApiMethod;\n post: MockApiMethod;\n put: MockApiMethod;\n patch: MockApiMethod;\n delete: MockApiMethod;\n}\n\nexport interface CreateMockServiceOptions {\n defaultResponse?: ApiResponseInterface;\n}\n\n/**\n * Creates a mock service with Vitest mock functions for all HTTP methods.\n *\n * @example\n * ```ts\n * import { createMockService, createMockResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockService = createMockService();\n * mockService.get.mockResolvedValue(createMockResponse({ data: mockData }));\n *\n * // Use in test\n * expect(mockService.get).toHaveBeenCalled();\n * ```\n *\n * @example With default response\n * ```ts\n * const mockService = createMockService({\n * defaultResponse: createMockResponse({ ok: true, data: [] }),\n * });\n * ```\n */\nexport function createMockService(options: CreateMockServiceOptions = {}): MockService {\n const defaultResponse = options.defaultResponse ?? createMockResponse({ ok: true });\n\n return {\n get: vi.fn().mockResolvedValue(defaultResponse),\n post: vi.fn().mockResolvedValue(defaultResponse),\n put: vi.fn().mockResolvedValue(defaultResponse),\n patch: vi.fn().mockResolvedValue(defaultResponse),\n delete: vi.fn().mockResolvedValue(defaultResponse),\n };\n}\n\n/**\n * Creates a mock service that returns errors for all methods.\n *\n * @example\n * ```ts\n * import { createMockErrorService } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorService = createMockErrorService(500, 'Internal Server Error');\n * ```\n */\nexport function createMockErrorService(statusCode: number = 500, errorMessage: string = \"Error\"): MockService {\n const errorResponse = createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n });\n\n return {\n get: vi.fn().mockResolvedValue(errorResponse),\n post: vi.fn().mockResolvedValue(errorResponse),\n put: vi.fn().mockResolvedValue(errorResponse),\n patch: vi.fn().mockResolvedValue(errorResponse),\n delete: vi.fn().mockResolvedValue(errorResponse),\n };\n}\n","import { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockApiDataOptions {\n type: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n included?: any[];\n createdAt?: Date;\n updatedAt?: Date;\n self?: string;\n}\n\n/**\n * Creates a mock ApiDataInterface object for testing.\n *\n * @example\n * ```ts\n * import { createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test Article', body: 'Content here' },\n * });\n * ```\n *\n * @example With relationships\n * ```ts\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test' },\n * relationships: {\n * author: { data: { type: 'users', id: '42' } },\n * },\n * });\n * ```\n */\nexport function createMockApiData(options: CreateMockApiDataOptions): ApiDataInterface {\n const {\n type,\n id = `mock-${type}-${Math.random().toString(36).substring(7)}`,\n attributes = {},\n relationships = {},\n included = [],\n createdAt = new Date(),\n updatedAt = new Date(),\n self,\n } = options;\n\n const jsonApiData = {\n type,\n id,\n attributes: {\n ...attributes,\n createdAt: createdAt.toISOString(),\n updatedAt: updatedAt.toISOString(),\n },\n relationships,\n };\n\n const mockData: ApiDataInterface = {\n get included() {\n return included;\n },\n get type() {\n return type;\n },\n get id() {\n return id;\n },\n get createdAt() {\n return createdAt;\n },\n get updatedAt() {\n return updatedAt;\n },\n get self() {\n return self;\n },\n get jsonApi() {\n return jsonApiData;\n },\n generateApiUrl: (params?: any) => {\n const baseUrl = `/${type}/${id}`;\n if (params) {\n const searchParams = new URLSearchParams(params);\n return `${baseUrl}?${searchParams.toString()}`;\n }\n return baseUrl;\n },\n dehydrate: () => ({\n jsonApi: jsonApiData,\n included,\n allData: [jsonApiData],\n }),\n rehydrate: function (_data: any) {\n return this;\n },\n createJsonApi: (data: any) => ({\n type,\n id,\n attributes: data,\n }),\n get identifier() {\n const identifierFields = [\"name\"];\n return identifierFields\n .map((field) => attributes[field])\n .filter((v) => v != null && v !== \"\")\n .join(\" \");\n },\n };\n\n // Add attribute accessors to the mock object\n Object.keys(attributes).forEach((key) => {\n Object.defineProperty(mockData, key, {\n get: () => attributes[key],\n enumerable: true,\n });\n });\n\n return mockData;\n}\n\n/**\n * Creates an array of mock ApiDataInterface objects.\n *\n * @example\n * ```ts\n * import { createMockApiDataList } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticles = createMockApiDataList('articles', 5, (index) => ({\n * title: `Article ${index + 1}`,\n * }));\n * ```\n */\nexport function createMockApiDataList(\n type: string,\n count: number,\n attributesFactory?: (index: number) => Record<string, any>,\n): ApiDataInterface[] {\n return Array.from({ length: count }, (_, index) =>\n createMockApiData({\n type,\n id: `${index + 1}`,\n attributes: attributesFactory?.(index) ?? {},\n }),\n );\n}\n","import { expect } from \"vitest\";\n\ninterface JsonApiResponse {\n data?:\n | {\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }\n | Array<{\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }>;\n}\n\n/**\n * Custom Vitest matchers for JSON:API assertions.\n *\n * @example\n * ```ts\n * import { jsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n * import { expect } from 'vitest';\n *\n * expect.extend(jsonApiMatchers);\n *\n * // Then use in tests:\n * expect(response).toBeValidJsonApi();\n * expect(response).toHaveJsonApiType('articles');\n * expect(response).toHaveJsonApiAttribute('title', 'My Article');\n * expect(response).toHaveJsonApiRelationship('author');\n * ```\n */\nexport const jsonApiMatchers = {\n /**\n * Asserts that the response has a valid JSON:API structure with type and id.\n */\n toBeValidJsonApi(received: JsonApiResponse) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const hasType = typeof data?.type === \"string\" && data.type.length > 0;\n const hasId = typeof data?.id === \"string\" && data.id.length > 0;\n const isValid = hasType && hasId;\n\n return {\n pass: isValid,\n message: () =>\n isValid\n ? `Expected response not to be valid JSON:API, but it has type \"${data?.type}\" and id \"${data?.id}\"`\n : `Expected response to be valid JSON:API with type and id, but got type: ${JSON.stringify(data?.type)}, id: ${JSON.stringify(data?.id)}`,\n };\n },\n\n /**\n * Asserts that the response data has the expected JSON:API type.\n */\n toHaveJsonApiType(received: JsonApiResponse, expectedType: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const actualType = data?.type;\n const pass = actualType === expectedType;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have JSON:API type \"${expectedType}\"`\n : `Expected response to have JSON:API type \"${expectedType}\", but got \"${actualType}\"`,\n };\n },\n\n /**\n * Asserts that the response data has an attribute with the expected value.\n */\n toHaveJsonApiAttribute(received: JsonApiResponse, attributeName: string, expectedValue?: any) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const attributes = data?.attributes ?? {};\n const hasAttribute = attributeName in attributes;\n const actualValue = attributes[attributeName];\n\n if (expectedValue === undefined) {\n // Just check existence\n return {\n pass: hasAttribute,\n message: () =>\n hasAttribute\n ? `Expected response not to have JSON:API attribute \"${attributeName}\"`\n : `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found. Available attributes: ${Object.keys(attributes).join(\", \") || \"none\"}`,\n };\n }\n\n const valuesMatch = actualValue === expectedValue;\n return {\n pass: hasAttribute && valuesMatch,\n message: () =>\n hasAttribute && valuesMatch\n ? `Expected response not to have JSON:API attribute \"${attributeName}\" with value \"${expectedValue}\"`\n : !hasAttribute\n ? `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found`\n : `Expected JSON:API attribute \"${attributeName}\" to be \"${expectedValue}\", but got \"${actualValue}\"`,\n };\n },\n\n /**\n * Asserts that the response data has the specified relationship.\n */\n toHaveJsonApiRelationship(received: JsonApiResponse, relationshipName: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const relationships = data?.relationships ?? {};\n const hasRelationship = relationshipName in relationships;\n\n return {\n pass: hasRelationship,\n message: () =>\n hasRelationship\n ? `Expected response not to have JSON:API relationship \"${relationshipName}\"`\n : `Expected response to have JSON:API relationship \"${relationshipName}\", but it was not found. Available relationships: ${Object.keys(relationships).join(\", \") || \"none\"}`,\n };\n },\n\n /**\n * Asserts that the response data array has the expected length.\n */\n toHaveJsonApiLength(received: JsonApiResponse, expectedLength: number) {\n const data = received?.data;\n const isArray = Array.isArray(data);\n const actualLength = isArray ? data.length : data ? 1 : 0;\n const pass = actualLength === expectedLength;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have ${expectedLength} items`\n : `Expected response to have ${expectedLength} items, but got ${actualLength}`,\n };\n },\n};\n\n// Type declarations for the custom matchers\n// Vitest 5: Assertion<R, T> and AsymmetricMatchersContaining both extend\n// Matchers<R, T>, so the matchers are declared once here and return R.\ndeclare module \"vitest\" {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- T must match vitest's Matchers<R, T> for declaration merging (TS2428)\n interface Matchers<R extends void | Promise<void> = void | Promise<void>, T = unknown> {\n toBeValidJsonApi(): R;\n toHaveJsonApiType(expectedType: string): R;\n toHaveJsonApiAttribute(attributeName: string, expectedValue?: any): R;\n toHaveJsonApiRelationship(relationshipName: string): R;\n toHaveJsonApiLength(expectedLength: number): R;\n }\n}\n\n/**\n * Extends Vitest's expect with JSON:API matchers.\n * Call this in your test setup file.\n *\n * @example\n * ```ts\n * // vitest.setup.ts\n * import { extendExpectWithJsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * extendExpectWithJsonApiMatchers();\n * ```\n */\nexport function extendExpectWithJsonApiMatchers(): void {\n expect.extend(jsonApiMatchers);\n}\n","\"use client\";\n\nimport React, { ReactElement } from \"react\";\nimport { render, RenderOptions, RenderResult } from \"@testing-library/react\";\nimport {\n MockJsonApiProvider,\n MockJsonApiProviderProps as _MockJsonApiProviderProps,\n} from \"../providers/MockJsonApiProvider\";\nimport { JsonApiConfig } from \"../../client/context/JsonApiContext\";\n\nexport interface RenderWithProvidersOptions extends Omit<RenderOptions, \"wrapper\"> {\n /**\n * Custom JSON:API configuration to pass to the mock provider.\n */\n jsonApiConfig?: Partial<JsonApiConfig>;\n\n /**\n * Additional wrapper component to wrap around the providers.\n */\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n}\n\n/**\n * Renders a component wrapped with all necessary providers for testing.\n *\n * @example\n * ```tsx\n * import { renderWithProviders } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const { getByText } = renderWithProviders(<MyComponent />);\n * expect(getByText('Hello')).toBeInTheDocument();\n * ```\n *\n * @example With custom config\n * ```tsx\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * jsonApiConfig: { apiUrl: 'https://custom.api.com' },\n * });\n * ```\n *\n * @example With additional wrapper\n * ```tsx\n * const CustomWrapper = ({ children }) => (\n * <ThemeProvider>{children}</ThemeProvider>\n * );\n *\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * wrapper: CustomWrapper,\n * });\n * ```\n */\nexport function renderWithProviders(ui: ReactElement, options: RenderWithProvidersOptions = {}): RenderResult {\n const { jsonApiConfig, wrapper: AdditionalWrapper, ...renderOptions } = options;\n\n function AllProviders({ children }: { children: React.ReactNode }) {\n const content = <MockJsonApiProvider config={jsonApiConfig}>{children}</MockJsonApiProvider>;\n\n if (AdditionalWrapper) {\n return <AdditionalWrapper>{content}</AdditionalWrapper>;\n }\n\n return content;\n }\n\n return render(ui, { wrapper: AllProviders, ...renderOptions });\n}\n\n/**\n * Re-export render utilities from Testing Library for convenience.\n */\nexport { render, screen, waitFor, fireEvent, within } from \"@testing-library/react\";\nexport { userEvent } from \"@testing-library/user-event\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/testing/providers/MockJsonApiProvider.tsx","../../src/testing/factories/createMockModule.ts","../../src/testing/factories/createMockResponse.ts","../../src/testing/factories/createMockService.ts","../../src/testing/factories/createMockApiData.ts","../../src/testing/matchers/jsonApiMatchers.ts","../../src/testing/utils/renderWithProviders.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport { JsonApiConfig, JsonApiContext } from \"../../client/context/JsonApiContext\";\n\nexport interface MockJsonApiProviderProps {\n children: React.ReactNode;\n config?: Partial<JsonApiConfig>;\n}\n\nconst defaultMockConfig: JsonApiConfig = {\n apiUrl: \"https://api.test.com\",\n tokenGetter: async () => \"mock-token-for-testing\",\n languageGetter: async () => \"en\",\n defaultHeaders: {},\n onError: () => {},\n cacheConfig: {\n defaultProfile: \"default\",\n },\n};\n\n/**\n * A test-friendly provider that wraps components with mock JSON:API context.\n *\n * @example\n * ```tsx\n * import { MockJsonApiProvider } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * render(\n * <MockJsonApiProvider>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n *\n * @example With custom config\n * ```tsx\n * render(\n * <MockJsonApiProvider config={{ apiUrl: 'https://custom.api.com' }}>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n */\nexport function MockJsonApiProvider({ children, config }: MockJsonApiProviderProps) {\n const mergedConfig: JsonApiConfig = {\n ...defaultMockConfig,\n ...config,\n };\n\n return <JsonApiContext.Provider value={mergedConfig}>{children}</JsonApiContext.Provider>;\n}\n\nexport { defaultMockConfig };\n","import { ApiRequestDataTypeInterface } from \"../../core/interfaces/ApiRequestDataTypeInterface\";\n\nexport interface CreateMockModuleOptions {\n name: string;\n cache?: string;\n inclusions?: ApiRequestDataTypeInterface[\"inclusions\"];\n}\n\n/**\n * Creates a mock module definition for testing.\n *\n * @example\n * ```ts\n * import { createMockModule } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticleModule = createMockModule({ name: 'articles' });\n * ```\n */\nexport function createMockModule(options: CreateMockModuleOptions): ApiRequestDataTypeInterface {\n // Create a mock model class\n class MockModel {\n id = \"mock-id\";\n type = options.name;\n }\n\n return {\n name: options.name,\n cache: options.cache,\n inclusions: options.inclusions,\n model: MockModel,\n };\n}\n","import { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockResponseOptions {\n data?: ApiDataInterface | ApiDataInterface[] | null;\n ok?: boolean;\n response?: number;\n error?: string;\n meta?: Record<string, any>;\n self?: string;\n next?: string;\n prev?: string;\n}\n\n/**\n * Creates a mock API response for testing.\n *\n * @example\n * ```ts\n * import { createMockResponse, createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockData = createMockApiData({ type: 'articles', id: '1' });\n * const response = createMockResponse({ data: mockData, ok: true });\n * ```\n *\n * @example With pagination\n * ```ts\n * const response = createMockResponse({\n * data: [mockData],\n * ok: true,\n * next: '/articles?page=2',\n * prev: '/articles?page=0',\n * });\n * ```\n */\nexport function createMockResponse(options: CreateMockResponseOptions = {}): ApiResponseInterface {\n const {\n data = null,\n ok = true,\n response = ok ? 200 : 500,\n error = ok ? \"\" : \"Error\",\n meta,\n self,\n next,\n prev,\n } = options;\n\n const mockResponse: ApiResponseInterface = {\n ok,\n response,\n data: data as ApiDataInterface | ApiDataInterface[],\n error,\n meta,\n self,\n next,\n prev,\n };\n\n // Add pagination methods if next/prev provided\n if (next) {\n mockResponse.nextPage = async () => createMockResponse({ ...options, next: undefined, prev: self });\n }\n\n if (prev) {\n mockResponse.prevPage = async () => createMockResponse({ ...options, prev: undefined, next: self });\n }\n\n return mockResponse;\n}\n\n/**\n * Creates a mock error response for testing error scenarios.\n *\n * @example\n * ```ts\n * import { createMockErrorResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorResponse = createMockErrorResponse(404, 'Not Found');\n * ```\n */\nexport function createMockErrorResponse(statusCode: number, errorMessage: string): ApiResponseInterface {\n return createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n data: null,\n });\n}\n","import { vi, type Mock } from \"vitest\";\nimport { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { createMockResponse } from \"./createMockResponse\";\n\nexport type MockApiMethod = Mock<(...args: any[]) => Promise<ApiResponseInterface>>;\n\nexport interface MockService {\n get: MockApiMethod;\n post: MockApiMethod;\n put: MockApiMethod;\n patch: MockApiMethod;\n delete: MockApiMethod;\n}\n\nexport interface CreateMockServiceOptions {\n defaultResponse?: ApiResponseInterface;\n}\n\n/**\n * Creates a mock service with Vitest mock functions for all HTTP methods.\n *\n * @example\n * ```ts\n * import { createMockService, createMockResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockService = createMockService();\n * mockService.get.mockResolvedValue(createMockResponse({ data: mockData }));\n *\n * // Use in test\n * expect(mockService.get).toHaveBeenCalled();\n * ```\n *\n * @example With default response\n * ```ts\n * const mockService = createMockService({\n * defaultResponse: createMockResponse({ ok: true, data: [] }),\n * });\n * ```\n */\nexport function createMockService(options: CreateMockServiceOptions = {}): MockService {\n const defaultResponse = options.defaultResponse ?? createMockResponse({ ok: true });\n\n return {\n get: vi.fn().mockResolvedValue(defaultResponse),\n post: vi.fn().mockResolvedValue(defaultResponse),\n put: vi.fn().mockResolvedValue(defaultResponse),\n patch: vi.fn().mockResolvedValue(defaultResponse),\n delete: vi.fn().mockResolvedValue(defaultResponse),\n };\n}\n\n/**\n * Creates a mock service that returns errors for all methods.\n *\n * @example\n * ```ts\n * import { createMockErrorService } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorService = createMockErrorService(500, 'Internal Server Error');\n * ```\n */\nexport function createMockErrorService(statusCode: number = 500, errorMessage: string = \"Error\"): MockService {\n const errorResponse = createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n });\n\n return {\n get: vi.fn().mockResolvedValue(errorResponse),\n post: vi.fn().mockResolvedValue(errorResponse),\n put: vi.fn().mockResolvedValue(errorResponse),\n patch: vi.fn().mockResolvedValue(errorResponse),\n delete: vi.fn().mockResolvedValue(errorResponse),\n };\n}\n","import { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockApiDataOptions {\n type: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n included?: any[];\n createdAt?: Date;\n updatedAt?: Date;\n self?: string;\n}\n\n/**\n * Creates a mock ApiDataInterface object for testing.\n *\n * @example\n * ```ts\n * import { createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test Article', body: 'Content here' },\n * });\n * ```\n *\n * @example With relationships\n * ```ts\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test' },\n * relationships: {\n * author: { data: { type: 'users', id: '42' } },\n * },\n * });\n * ```\n */\nexport function createMockApiData(options: CreateMockApiDataOptions): ApiDataInterface {\n const {\n type,\n id = `mock-${type}-${Math.random().toString(36).substring(7)}`,\n attributes = {},\n relationships = {},\n included = [],\n createdAt = new Date(),\n updatedAt = new Date(),\n self,\n } = options;\n\n const jsonApiData = {\n type,\n id,\n attributes: {\n ...attributes,\n createdAt: createdAt.toISOString(),\n updatedAt: updatedAt.toISOString(),\n },\n relationships,\n };\n\n const mockData: ApiDataInterface = {\n get included() {\n return included;\n },\n get type() {\n return type;\n },\n get id() {\n return id;\n },\n get createdAt() {\n return createdAt;\n },\n get updatedAt() {\n return updatedAt;\n },\n get self() {\n return self;\n },\n get jsonApi() {\n return jsonApiData;\n },\n generateApiUrl: (params?: any) => {\n const baseUrl = `/${type}/${id}`;\n if (params) {\n const searchParams = new URLSearchParams(params);\n return `${baseUrl}?${searchParams.toString()}`;\n }\n return baseUrl;\n },\n dehydrate: () => ({\n jsonApi: jsonApiData,\n included,\n allData: [jsonApiData],\n }),\n rehydrate: function (_data: any) {\n return this;\n },\n createJsonApi: (data: any) => ({\n type,\n id,\n attributes: data,\n }),\n get identifier() {\n const identifierFields = [\"name\"];\n return identifierFields\n .map((field) => attributes[field])\n .filter((v) => v != null && v !== \"\")\n .join(\" \");\n },\n };\n\n // Add attribute accessors to the mock object\n Object.keys(attributes).forEach((key) => {\n Object.defineProperty(mockData, key, {\n get: () => attributes[key],\n enumerable: true,\n });\n });\n\n return mockData;\n}\n\n/**\n * Creates an array of mock ApiDataInterface objects.\n *\n * @example\n * ```ts\n * import { createMockApiDataList } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticles = createMockApiDataList('articles', 5, (index) => ({\n * title: `Article ${index + 1}`,\n * }));\n * ```\n */\nexport function createMockApiDataList(\n type: string,\n count: number,\n attributesFactory?: (index: number) => Record<string, any>,\n): ApiDataInterface[] {\n return Array.from({ length: count }, (_, index) =>\n createMockApiData({\n type,\n id: `${index + 1}`,\n attributes: attributesFactory?.(index) ?? {},\n }),\n );\n}\n","import { expect } from \"vitest\";\n\ninterface JsonApiResponse {\n data?:\n | {\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }\n | Array<{\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }>;\n}\n\n/**\n * Custom Vitest matchers for JSON:API assertions.\n *\n * @example\n * ```ts\n * import { jsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n * import { expect } from 'vitest';\n *\n * expect.extend(jsonApiMatchers);\n *\n * // Then use in tests:\n * expect(response).toBeValidJsonApi();\n * expect(response).toHaveJsonApiType('articles');\n * expect(response).toHaveJsonApiAttribute('title', 'My Article');\n * expect(response).toHaveJsonApiRelationship('author');\n * ```\n */\nexport const jsonApiMatchers = {\n /**\n * Asserts that the response has a valid JSON:API structure with type and id.\n */\n toBeValidJsonApi(received: JsonApiResponse) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const hasType = typeof data?.type === \"string\" && data.type.length > 0;\n const hasId = typeof data?.id === \"string\" && data.id.length > 0;\n const isValid = hasType && hasId;\n\n return {\n pass: isValid,\n message: () =>\n isValid\n ? `Expected response not to be valid JSON:API, but it has type \"${data?.type}\" and id \"${data?.id}\"`\n : `Expected response to be valid JSON:API with type and id, but got type: ${JSON.stringify(data?.type)}, id: ${JSON.stringify(data?.id)}`,\n };\n },\n\n /**\n * Asserts that the response data has the expected JSON:API type.\n */\n toHaveJsonApiType(received: JsonApiResponse, expectedType: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const actualType = data?.type;\n const pass = actualType === expectedType;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have JSON:API type \"${expectedType}\"`\n : `Expected response to have JSON:API type \"${expectedType}\", but got \"${actualType}\"`,\n };\n },\n\n /**\n * Asserts that the response data has an attribute with the expected value.\n */\n toHaveJsonApiAttribute(received: JsonApiResponse, attributeName: string, expectedValue?: any) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const attributes = data?.attributes ?? {};\n const hasAttribute = attributeName in attributes;\n const actualValue = attributes[attributeName];\n\n if (expectedValue === undefined) {\n // Just check existence\n return {\n pass: hasAttribute,\n message: () =>\n hasAttribute\n ? `Expected response not to have JSON:API attribute \"${attributeName}\"`\n : `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found. Available attributes: ${Object.keys(attributes).join(\", \") || \"none\"}`,\n };\n }\n\n const valuesMatch = actualValue === expectedValue;\n return {\n pass: hasAttribute && valuesMatch,\n message: () =>\n hasAttribute && valuesMatch\n ? `Expected response not to have JSON:API attribute \"${attributeName}\" with value \"${expectedValue}\"`\n : !hasAttribute\n ? `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found`\n : `Expected JSON:API attribute \"${attributeName}\" to be \"${expectedValue}\", but got \"${actualValue}\"`,\n };\n },\n\n /**\n * Asserts that the response data has the specified relationship.\n */\n toHaveJsonApiRelationship(received: JsonApiResponse, relationshipName: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const relationships = data?.relationships ?? {};\n const hasRelationship = relationshipName in relationships;\n\n return {\n pass: hasRelationship,\n message: () =>\n hasRelationship\n ? `Expected response not to have JSON:API relationship \"${relationshipName}\"`\n : `Expected response to have JSON:API relationship \"${relationshipName}\", but it was not found. Available relationships: ${Object.keys(relationships).join(\", \") || \"none\"}`,\n };\n },\n\n /**\n * Asserts that the response data array has the expected length.\n */\n toHaveJsonApiLength(received: JsonApiResponse, expectedLength: number) {\n const data = received?.data;\n const isArray = Array.isArray(data);\n const actualLength = isArray ? data.length : data ? 1 : 0;\n const pass = actualLength === expectedLength;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have ${expectedLength} items`\n : `Expected response to have ${expectedLength} items, but got ${actualLength}`,\n };\n },\n};\n\n// Type declarations for the custom matchers\n// Vitest 5: Assertion<R, T> and AsymmetricMatchersContaining both extend\n// Matchers<R, T>, so the matchers are declared once here and return R.\ndeclare module \"vitest\" {\n interface Matchers<R extends void | Promise<void> = void | Promise<void>, T = unknown> {\n toBeValidJsonApi(): R;\n toHaveJsonApiType(expectedType: string): R;\n toHaveJsonApiAttribute(attributeName: string, expectedValue?: any): R;\n toHaveJsonApiRelationship(relationshipName: string): R;\n toHaveJsonApiLength(expectedLength: number): R;\n }\n}\n\n/**\n * Extends Vitest's expect with JSON:API matchers.\n * Call this in your test setup file.\n *\n * @example\n * ```ts\n * // vitest.setup.ts\n * import { extendExpectWithJsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * extendExpectWithJsonApiMatchers();\n * ```\n */\nexport function extendExpectWithJsonApiMatchers(): void {\n expect.extend(jsonApiMatchers);\n}\n","\"use client\";\n\nimport React, { ReactElement } from \"react\";\nimport { render, RenderOptions, RenderResult } from \"@testing-library/react\";\nimport {\n MockJsonApiProvider,\n MockJsonApiProviderProps as _MockJsonApiProviderProps,\n} from \"../providers/MockJsonApiProvider\";\nimport { JsonApiConfig } from \"../../client/context/JsonApiContext\";\n\nexport interface RenderWithProvidersOptions extends Omit<RenderOptions, \"wrapper\"> {\n /**\n * Custom JSON:API configuration to pass to the mock provider.\n */\n jsonApiConfig?: Partial<JsonApiConfig>;\n\n /**\n * Additional wrapper component to wrap around the providers.\n */\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n}\n\n/**\n * Renders a component wrapped with all necessary providers for testing.\n *\n * @example\n * ```tsx\n * import { renderWithProviders } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const { getByText } = renderWithProviders(<MyComponent />);\n * expect(getByText('Hello')).toBeInTheDocument();\n * ```\n *\n * @example With custom config\n * ```tsx\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * jsonApiConfig: { apiUrl: 'https://custom.api.com' },\n * });\n * ```\n *\n * @example With additional wrapper\n * ```tsx\n * const CustomWrapper = ({ children }) => (\n * <ThemeProvider>{children}</ThemeProvider>\n * );\n *\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * wrapper: CustomWrapper,\n * });\n * ```\n */\nexport function renderWithProviders(ui: ReactElement, options: RenderWithProvidersOptions = {}): RenderResult {\n const { jsonApiConfig, wrapper: AdditionalWrapper, ...renderOptions } = options;\n\n function AllProviders({ children }: { children: React.ReactNode }) {\n const content = <MockJsonApiProvider config={jsonApiConfig}>{children}</MockJsonApiProvider>;\n\n if (AdditionalWrapper) {\n return <AdditionalWrapper>{content}</AdditionalWrapper>;\n }\n\n return content;\n }\n\n return render(ui, { wrapper: AllProviders, ...renderOptions });\n}\n\n/**\n * Re-export render utilities from Testing Library for convenience.\n */\nexport { render, screen, waitFor, fireEvent, within } from \"@testing-library/react\";\nexport { userEvent } from \"@testing-library/user-event\";\n"],"mappings":"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","names":["render","jsx"]}
1
+ {"version":3,"sources":["../../src/testing/providers/MockJsonApiProvider.tsx","../../src/testing/factories/createMockModule.ts","../../src/testing/factories/createMockResponse.ts","../../src/testing/factories/createMockService.ts","../../src/testing/factories/createMockApiData.ts","../../src/testing/matchers/jsonApiMatchers.ts","../../src/testing/utils/renderWithProviders.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport { JsonApiConfig, JsonApiContext } from \"../../client/context/JsonApiContext\";\n\nexport interface MockJsonApiProviderProps {\n children: React.ReactNode;\n config?: Partial<JsonApiConfig>;\n}\n\nconst defaultMockConfig: JsonApiConfig = {\n apiUrl: \"https://api.test.com\",\n tokenGetter: async () => \"mock-token-for-testing\",\n languageGetter: async () => \"en\",\n defaultHeaders: {},\n onError: () => {},\n cacheConfig: {\n defaultProfile: \"default\",\n },\n};\n\n/**\n * A test-friendly provider that wraps components with mock JSON:API context.\n *\n * @example\n * ```tsx\n * import { MockJsonApiProvider } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * render(\n * <MockJsonApiProvider>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n *\n * @example With custom config\n * ```tsx\n * render(\n * <MockJsonApiProvider config={{ apiUrl: 'https://custom.api.com' }}>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n */\nexport function MockJsonApiProvider({ children, config }: MockJsonApiProviderProps) {\n const mergedConfig: JsonApiConfig = {\n ...defaultMockConfig,\n ...config,\n };\n\n return <JsonApiContext.Provider value={mergedConfig}>{children}</JsonApiContext.Provider>;\n}\n\nexport { defaultMockConfig };\n","import { ApiRequestDataTypeInterface } from \"../../core/interfaces/ApiRequestDataTypeInterface\";\n\nexport interface CreateMockModuleOptions {\n name: string;\n cache?: string;\n inclusions?: ApiRequestDataTypeInterface[\"inclusions\"];\n}\n\n/**\n * Creates a mock module definition for testing.\n *\n * @example\n * ```ts\n * import { createMockModule } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticleModule = createMockModule({ name: 'articles' });\n * ```\n */\nexport function createMockModule(options: CreateMockModuleOptions): ApiRequestDataTypeInterface {\n // Create a mock model class\n class MockModel {\n id = \"mock-id\";\n type = options.name;\n }\n\n return {\n name: options.name,\n cache: options.cache,\n inclusions: options.inclusions,\n model: MockModel,\n };\n}\n","import { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockResponseOptions {\n data?: ApiDataInterface | ApiDataInterface[] | null;\n ok?: boolean;\n response?: number;\n error?: string;\n meta?: Record<string, any>;\n self?: string;\n next?: string;\n prev?: string;\n}\n\n/**\n * Creates a mock API response for testing.\n *\n * @example\n * ```ts\n * import { createMockResponse, createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockData = createMockApiData({ type: 'articles', id: '1' });\n * const response = createMockResponse({ data: mockData, ok: true });\n * ```\n *\n * @example With pagination\n * ```ts\n * const response = createMockResponse({\n * data: [mockData],\n * ok: true,\n * next: '/articles?page=2',\n * prev: '/articles?page=0',\n * });\n * ```\n */\nexport function createMockResponse(options: CreateMockResponseOptions = {}): ApiResponseInterface {\n const {\n data = null,\n ok = true,\n response = ok ? 200 : 500,\n error = ok ? \"\" : \"Error\",\n meta,\n self,\n next,\n prev,\n } = options;\n\n const mockResponse: ApiResponseInterface = {\n ok,\n response,\n data: data as ApiDataInterface | ApiDataInterface[],\n error,\n meta,\n self,\n next,\n prev,\n };\n\n // Add pagination methods if next/prev provided\n if (next) {\n mockResponse.nextPage = async () => createMockResponse({ ...options, next: undefined, prev: self });\n }\n\n if (prev) {\n mockResponse.prevPage = async () => createMockResponse({ ...options, prev: undefined, next: self });\n }\n\n return mockResponse;\n}\n\n/**\n * Creates a mock error response for testing error scenarios.\n *\n * @example\n * ```ts\n * import { createMockErrorResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorResponse = createMockErrorResponse(404, 'Not Found');\n * ```\n */\nexport function createMockErrorResponse(statusCode: number, errorMessage: string): ApiResponseInterface {\n return createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n data: null,\n });\n}\n","import { vi, type Mock } from \"vitest\";\nimport { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { createMockResponse } from \"./createMockResponse\";\n\nexport type MockApiMethod = Mock<(...args: any[]) => Promise<ApiResponseInterface>>;\n\nexport interface MockService {\n get: MockApiMethod;\n post: MockApiMethod;\n put: MockApiMethod;\n patch: MockApiMethod;\n delete: MockApiMethod;\n}\n\nexport interface CreateMockServiceOptions {\n defaultResponse?: ApiResponseInterface;\n}\n\n/**\n * Creates a mock service with Vitest mock functions for all HTTP methods.\n *\n * @example\n * ```ts\n * import { createMockService, createMockResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockService = createMockService();\n * mockService.get.mockResolvedValue(createMockResponse({ data: mockData }));\n *\n * // Use in test\n * expect(mockService.get).toHaveBeenCalled();\n * ```\n *\n * @example With default response\n * ```ts\n * const mockService = createMockService({\n * defaultResponse: createMockResponse({ ok: true, data: [] }),\n * });\n * ```\n */\nexport function createMockService(options: CreateMockServiceOptions = {}): MockService {\n const defaultResponse = options.defaultResponse ?? createMockResponse({ ok: true });\n\n return {\n get: vi.fn().mockResolvedValue(defaultResponse),\n post: vi.fn().mockResolvedValue(defaultResponse),\n put: vi.fn().mockResolvedValue(defaultResponse),\n patch: vi.fn().mockResolvedValue(defaultResponse),\n delete: vi.fn().mockResolvedValue(defaultResponse),\n };\n}\n\n/**\n * Creates a mock service that returns errors for all methods.\n *\n * @example\n * ```ts\n * import { createMockErrorService } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorService = createMockErrorService(500, 'Internal Server Error');\n * ```\n */\nexport function createMockErrorService(statusCode: number = 500, errorMessage: string = \"Error\"): MockService {\n const errorResponse = createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n });\n\n return {\n get: vi.fn().mockResolvedValue(errorResponse),\n post: vi.fn().mockResolvedValue(errorResponse),\n put: vi.fn().mockResolvedValue(errorResponse),\n patch: vi.fn().mockResolvedValue(errorResponse),\n delete: vi.fn().mockResolvedValue(errorResponse),\n };\n}\n","import { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockApiDataOptions {\n type: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n included?: any[];\n createdAt?: Date;\n updatedAt?: Date;\n self?: string;\n}\n\n/**\n * Creates a mock ApiDataInterface object for testing.\n *\n * @example\n * ```ts\n * import { createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test Article', body: 'Content here' },\n * });\n * ```\n *\n * @example With relationships\n * ```ts\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test' },\n * relationships: {\n * author: { data: { type: 'users', id: '42' } },\n * },\n * });\n * ```\n */\nexport function createMockApiData(options: CreateMockApiDataOptions): ApiDataInterface {\n const {\n type,\n id = `mock-${type}-${Math.random().toString(36).substring(7)}`,\n attributes = {},\n relationships = {},\n included = [],\n createdAt = new Date(),\n updatedAt = new Date(),\n self,\n } = options;\n\n const jsonApiData = {\n type,\n id,\n attributes: {\n ...attributes,\n createdAt: createdAt.toISOString(),\n updatedAt: updatedAt.toISOString(),\n },\n relationships,\n };\n\n const mockData: ApiDataInterface = {\n get included() {\n return included;\n },\n get type() {\n return type;\n },\n get id() {\n return id;\n },\n get createdAt() {\n return createdAt;\n },\n get updatedAt() {\n return updatedAt;\n },\n get self() {\n return self;\n },\n get jsonApi() {\n return jsonApiData;\n },\n generateApiUrl: (params?: any) => {\n const baseUrl = `/${type}/${id}`;\n if (params) {\n const searchParams = new URLSearchParams(params);\n return `${baseUrl}?${searchParams.toString()}`;\n }\n return baseUrl;\n },\n dehydrate: () => ({\n jsonApi: jsonApiData,\n included,\n allData: [jsonApiData],\n }),\n rehydrate: function (_data: any) {\n return this;\n },\n createJsonApi: (data: any) => ({\n type,\n id,\n attributes: data,\n }),\n get identifier() {\n const identifierFields = [\"name\"];\n return identifierFields\n .map((field) => attributes[field])\n .filter((v) => v != null && v !== \"\")\n .join(\" \");\n },\n };\n\n // Add attribute accessors to the mock object\n Object.keys(attributes).forEach((key) => {\n Object.defineProperty(mockData, key, {\n get: () => attributes[key],\n enumerable: true,\n });\n });\n\n return mockData;\n}\n\n/**\n * Creates an array of mock ApiDataInterface objects.\n *\n * @example\n * ```ts\n * import { createMockApiDataList } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticles = createMockApiDataList('articles', 5, (index) => ({\n * title: `Article ${index + 1}`,\n * }));\n * ```\n */\nexport function createMockApiDataList(\n type: string,\n count: number,\n attributesFactory?: (index: number) => Record<string, any>,\n): ApiDataInterface[] {\n return Array.from({ length: count }, (_, index) =>\n createMockApiData({\n type,\n id: `${index + 1}`,\n attributes: attributesFactory?.(index) ?? {},\n }),\n );\n}\n","import { expect } from \"vitest\";\n\ninterface JsonApiResponse {\n data?:\n | {\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }\n | Array<{\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }>;\n}\n\n/**\n * Custom Vitest matchers for JSON:API assertions.\n *\n * @example\n * ```ts\n * import { jsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n * import { expect } from 'vitest';\n *\n * expect.extend(jsonApiMatchers);\n *\n * // Then use in tests:\n * expect(response).toBeValidJsonApi();\n * expect(response).toHaveJsonApiType('articles');\n * expect(response).toHaveJsonApiAttribute('title', 'My Article');\n * expect(response).toHaveJsonApiRelationship('author');\n * ```\n */\nexport const jsonApiMatchers = {\n /**\n * Asserts that the response has a valid JSON:API structure with type and id.\n */\n toBeValidJsonApi(received: JsonApiResponse) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const hasType = typeof data?.type === \"string\" && data.type.length > 0;\n const hasId = typeof data?.id === \"string\" && data.id.length > 0;\n const isValid = hasType && hasId;\n\n return {\n pass: isValid,\n message: () =>\n isValid\n ? `Expected response not to be valid JSON:API, but it has type \"${data?.type}\" and id \"${data?.id}\"`\n : `Expected response to be valid JSON:API with type and id, but got type: ${JSON.stringify(data?.type)}, id: ${JSON.stringify(data?.id)}`,\n };\n },\n\n /**\n * Asserts that the response data has the expected JSON:API type.\n */\n toHaveJsonApiType(received: JsonApiResponse, expectedType: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const actualType = data?.type;\n const pass = actualType === expectedType;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have JSON:API type \"${expectedType}\"`\n : `Expected response to have JSON:API type \"${expectedType}\", but got \"${actualType}\"`,\n };\n },\n\n /**\n * Asserts that the response data has an attribute with the expected value.\n */\n toHaveJsonApiAttribute(received: JsonApiResponse, attributeName: string, expectedValue?: any) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const attributes = data?.attributes ?? {};\n const hasAttribute = attributeName in attributes;\n const actualValue = attributes[attributeName];\n\n if (expectedValue === undefined) {\n // Just check existence\n return {\n pass: hasAttribute,\n message: () =>\n hasAttribute\n ? `Expected response not to have JSON:API attribute \"${attributeName}\"`\n : `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found. Available attributes: ${Object.keys(attributes).join(\", \") || \"none\"}`,\n };\n }\n\n const valuesMatch = actualValue === expectedValue;\n return {\n pass: hasAttribute && valuesMatch,\n message: () =>\n hasAttribute && valuesMatch\n ? `Expected response not to have JSON:API attribute \"${attributeName}\" with value \"${expectedValue}\"`\n : !hasAttribute\n ? `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found`\n : `Expected JSON:API attribute \"${attributeName}\" to be \"${expectedValue}\", but got \"${actualValue}\"`,\n };\n },\n\n /**\n * Asserts that the response data has the specified relationship.\n */\n toHaveJsonApiRelationship(received: JsonApiResponse, relationshipName: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const relationships = data?.relationships ?? {};\n const hasRelationship = relationshipName in relationships;\n\n return {\n pass: hasRelationship,\n message: () =>\n hasRelationship\n ? `Expected response not to have JSON:API relationship \"${relationshipName}\"`\n : `Expected response to have JSON:API relationship \"${relationshipName}\", but it was not found. Available relationships: ${Object.keys(relationships).join(\", \") || \"none\"}`,\n };\n },\n\n /**\n * Asserts that the response data array has the expected length.\n */\n toHaveJsonApiLength(received: JsonApiResponse, expectedLength: number) {\n const data = received?.data;\n const isArray = Array.isArray(data);\n const actualLength = isArray ? data.length : data ? 1 : 0;\n const pass = actualLength === expectedLength;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have ${expectedLength} items`\n : `Expected response to have ${expectedLength} items, but got ${actualLength}`,\n };\n },\n};\n\n// Type declarations for the custom matchers\n// Vitest 5: Assertion<R, T> and AsymmetricMatchersContaining both extend\n// Matchers<R, T>, so the matchers are declared once here and return R.\ndeclare module \"vitest\" {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- T must match vitest's Matchers<R, T> for declaration merging (TS2428)\n interface Matchers<R extends void | Promise<void> = void | Promise<void>, T = unknown> {\n toBeValidJsonApi(): R;\n toHaveJsonApiType(expectedType: string): R;\n toHaveJsonApiAttribute(attributeName: string, expectedValue?: any): R;\n toHaveJsonApiRelationship(relationshipName: string): R;\n toHaveJsonApiLength(expectedLength: number): R;\n }\n}\n\n/**\n * Extends Vitest's expect with JSON:API matchers.\n * Call this in your test setup file.\n *\n * @example\n * ```ts\n * // vitest.setup.ts\n * import { extendExpectWithJsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * extendExpectWithJsonApiMatchers();\n * ```\n */\nexport function extendExpectWithJsonApiMatchers(): void {\n expect.extend(jsonApiMatchers);\n}\n","\"use client\";\n\nimport React, { ReactElement } from \"react\";\nimport { render, RenderOptions, RenderResult } from \"@testing-library/react\";\nimport {\n MockJsonApiProvider,\n MockJsonApiProviderProps as _MockJsonApiProviderProps,\n} from \"../providers/MockJsonApiProvider\";\nimport { JsonApiConfig } from \"../../client/context/JsonApiContext\";\n\nexport interface RenderWithProvidersOptions extends Omit<RenderOptions, \"wrapper\"> {\n /**\n * Custom JSON:API configuration to pass to the mock provider.\n */\n jsonApiConfig?: Partial<JsonApiConfig>;\n\n /**\n * Additional wrapper component to wrap around the providers.\n */\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n}\n\n/**\n * Renders a component wrapped with all necessary providers for testing.\n *\n * @example\n * ```tsx\n * import { renderWithProviders } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const { getByText } = renderWithProviders(<MyComponent />);\n * expect(getByText('Hello')).toBeInTheDocument();\n * ```\n *\n * @example With custom config\n * ```tsx\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * jsonApiConfig: { apiUrl: 'https://custom.api.com' },\n * });\n * ```\n *\n * @example With additional wrapper\n * ```tsx\n * const CustomWrapper = ({ children }) => (\n * <ThemeProvider>{children}</ThemeProvider>\n * );\n *\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * wrapper: CustomWrapper,\n * });\n * ```\n */\nexport function renderWithProviders(ui: ReactElement, options: RenderWithProvidersOptions = {}): RenderResult {\n const { jsonApiConfig, wrapper: AdditionalWrapper, ...renderOptions } = options;\n\n function AllProviders({ children }: { children: React.ReactNode }) {\n const content = <MockJsonApiProvider config={jsonApiConfig}>{children}</MockJsonApiProvider>;\n\n if (AdditionalWrapper) {\n return <AdditionalWrapper>{content}</AdditionalWrapper>;\n }\n\n return content;\n }\n\n return render(ui, { wrapper: AllProviders, ...renderOptions });\n}\n\n/**\n * Re-export render utilities from Testing Library for convenience.\n */\nexport { render, screen, waitFor, fireEvent, within } from \"@testing-library/react\";\nexport { userEvent } from \"@testing-library/user-event\";\n"],"mappings":"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","names":["render","jsx"]}
@@ -98,4 +98,4 @@ type ModuleFactory = (params: {
98
98
  }>;
99
99
  }) => ModuleWithPermissions;
100
100
 
101
- export { Action as A, type ModuleFactory as M, type PageUrl as P, type ModuleWithPermissions as a, type PermissionCheck as b, type ModulePermissionDefinition as c, type ModuleDefinition as d, type PermissionConfig as e, type PermissionModule as f, type PermissionUser as g };
101
+ export { Action as A, type ModuleWithPermissions as M, type PageUrl as P, type ModuleFactory as a, type PermissionCheck as b, type ModulePermissionDefinition as c, type ModuleDefinition as d, type PermissionConfig as e, type PermissionModule as f, type PermissionUser as g };
@@ -98,4 +98,4 @@ type ModuleFactory = (params: {
98
98
  }>;
99
99
  }) => ModuleWithPermissions;
100
100
 
101
- export { Action as A, type ModuleFactory as M, type PageUrl as P, type ModuleWithPermissions as a, type PermissionCheck as b, type ModulePermissionDefinition as c, type ModuleDefinition as d, type PermissionConfig as e, type PermissionModule as f, type PermissionUser as g };
101
+ export { Action as A, type ModuleWithPermissions as M, type PageUrl as P, type ModuleFactory as a, type PermissionCheck as b, type ModulePermissionDefinition as c, type ModuleDefinition as d, type PermissionConfig as e, type PermissionModule as f, type PermissionUser as g };
@@ -1,4 +1,4 @@
1
- import { P as PageUrl } from './types-Cn153-mH.js';
1
+ import { P as PageUrl } from './types-bsm8Fp55.js';
2
2
 
3
3
  declare function usePageUrlGenerator(): (params: {
4
4
  page?: PageUrl | string;
@@ -1,4 +1,4 @@
1
- import { P as PageUrl } from './types-D0uLYV2P.mjs';
1
+ import { P as PageUrl } from './types-Bq_UA8Lg.mjs';
2
2
 
3
3
  declare function usePageUrlGenerator(): (params: {
4
4
  page?: PageUrl | string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carlonicora/nextjs-jsonapi",
3
- "version": "3.28.2",
3
+ "version": "4.0.0",
4
4
  "description": "Next.js JSON:API client with server/client support and caching",
5
5
  "author": "Carlo Nicora",
6
6
  "license": "GPL-3.0-or-later",
@@ -27,6 +27,12 @@
27
27
  "import": "./dist/server/index.mjs",
28
28
  "require": "./dist/server/index.js"
29
29
  },
30
+ "./cached-get": {
31
+ "types": "./dist/server/cachedGet.d.ts",
32
+ "react-server": "./dist/server/cachedGet.mjs",
33
+ "import": "./dist/server/cachedGet.stub.mjs",
34
+ "require": "./dist/server/cachedGet.stub.js"
35
+ },
30
36
  "./client": {
31
37
  "types": "./dist/client/index.d.ts",
32
38
  "import": "./dist/client/index.mjs",
@@ -77,6 +83,11 @@
77
83
  "types": "./dist/features/analytics/server.d.ts",
78
84
  "import": "./dist/features/analytics/server.mjs",
79
85
  "require": "./dist/features/analytics/server.js"
86
+ },
87
+ "./next-config": {
88
+ "types": "./dist/next-config/index.d.ts",
89
+ "import": "./dist/next-config/index.mjs",
90
+ "require": "./dist/next-config/index.js"
80
91
  }
81
92
  },
82
93
  "scripts": {