@carlonicora/nextjs-jsonapi 1.138.1 → 1.139.1

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 (57) hide show
  1. package/dist/{BlockNoteEditor-N5V74BJF.js → BlockNoteEditor-B5BEXRRO.js} +19 -19
  2. package/dist/{BlockNoteEditor-N5V74BJF.js.map → BlockNoteEditor-B5BEXRRO.js.map} +1 -1
  3. package/dist/{BlockNoteEditor-E6ULBTZD.mjs → BlockNoteEditor-WXYPQVVY.mjs} +4 -4
  4. package/dist/billing/index.js +357 -357
  5. package/dist/billing/index.mjs +3 -3
  6. package/dist/{chunk-W73JBOIR.js → chunk-AWOOIQLF.js} +14 -2
  7. package/dist/chunk-AWOOIQLF.js.map +1 -0
  8. package/dist/{chunk-DVOBOFCF.mjs → chunk-GF4OWZKE.mjs} +13 -1
  9. package/dist/chunk-GF4OWZKE.mjs.map +1 -0
  10. package/dist/{chunk-L5CPWDCM.mjs → chunk-LFEI3ASB.mjs} +19 -13
  11. package/dist/chunk-LFEI3ASB.mjs.map +1 -0
  12. package/dist/{chunk-M5IAN7IR.mjs → chunk-PKSCKISS.mjs} +2 -2
  13. package/dist/{chunk-FLZ55M3V.js → chunk-W2Z3KQH6.js} +742 -736
  14. package/dist/chunk-W2Z3KQH6.js.map +1 -0
  15. package/dist/{chunk-C2LEIBUK.js → chunk-XN6CXBNO.js} +7 -7
  16. package/dist/{chunk-C2LEIBUK.js.map → chunk-XN6CXBNO.js.map} +1 -1
  17. package/dist/client/index.d.mts +2 -2
  18. package/dist/client/index.d.ts +2 -2
  19. package/dist/client/index.js +4 -4
  20. package/dist/client/index.mjs +3 -3
  21. package/dist/components/index.d.mts +1 -1
  22. package/dist/components/index.d.ts +1 -1
  23. package/dist/components/index.js +4 -4
  24. package/dist/components/index.mjs +3 -3
  25. package/dist/contexts/index.js +4 -4
  26. package/dist/contexts/index.mjs +3 -3
  27. package/dist/core/index.d.mts +2 -2
  28. package/dist/core/index.d.ts +2 -2
  29. package/dist/core/index.js +6 -2
  30. package/dist/core/index.js.map +1 -1
  31. package/dist/core/index.mjs +5 -1
  32. package/dist/features/help/index.js +37 -37
  33. package/dist/features/help/index.mjs +3 -3
  34. package/dist/index.d.mts +2 -2
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.js +7 -3
  37. package/dist/index.js.map +1 -1
  38. package/dist/index.mjs +6 -2
  39. package/dist/{s3.service-gcEjq8gF.d.ts → s3.service-BrmeMjtk.d.ts} +3 -1
  40. package/dist/{s3.service-CBqyDZyz.d.mts → s3.service-CXKV_OT-.d.mts} +3 -1
  41. package/dist/server/index.d.mts +1 -1
  42. package/dist/server/index.d.ts +1 -1
  43. package/dist/server/index.js +3 -3
  44. package/dist/server/index.mjs +1 -1
  45. package/dist/{useDataListRetriever-BqJSFBck.d.mts → useDataListRetriever-WEXL4bqB.d.mts} +1 -0
  46. package/dist/{useDataListRetriever-BqJSFBck.d.ts → useDataListRetriever-WEXL4bqB.d.ts} +1 -0
  47. package/package.json +1 -1
  48. package/src/components/forms/EntityMultiSelector.tsx +9 -11
  49. package/src/core/abstracts/AbstractService.ts +15 -0
  50. package/src/hooks/__tests__/useDataListRetriever.test.ts +23 -0
  51. package/src/hooks/useDataListRetriever.ts +12 -2
  52. package/dist/chunk-DVOBOFCF.mjs.map +0 -1
  53. package/dist/chunk-FLZ55M3V.js.map +0 -1
  54. package/dist/chunk-L5CPWDCM.mjs.map +0 -1
  55. package/dist/chunk-W73JBOIR.js.map +0 -1
  56. /package/dist/{BlockNoteEditor-E6ULBTZD.mjs.map → BlockNoteEditor-WXYPQVVY.mjs.map} +0 -0
  57. /package/dist/{chunk-M5IAN7IR.mjs.map → chunk-PKSCKISS.mjs.map} +0 -0
@@ -15,7 +15,7 @@ var _chunkIOLU4ASDjs = require('../chunk-IOLU4ASD.js');
15
15
 
16
16
 
17
17
 
18
- var _chunkW73JBOIRjs = require('../chunk-W73JBOIR.js');
18
+ var _chunkAWOOIQLFjs = require('../chunk-AWOOIQLF.js');
19
19
  require('../chunk-LXKSUWAV.js');
20
20
  require('../chunk-IBS6NI7D.js');
21
21
 
@@ -86,7 +86,7 @@ var ServerSession = class {
86
86
  if (!rawModules) return false;
87
87
  const modules = JSON.parse(_pako2.default.ungzip(Buffer.from(rawModules, "base64"), { to: "string" }));
88
88
  const selectedModule = modules.find((module) => module.id === params.module.moduleId);
89
- return _chunkW73JBOIRjs.checkPermissionsFromServer.call(void 0, {
89
+ return _chunkAWOOIQLFjs.checkPermissionsFromServer.call(void 0, {
90
90
  module: params.module,
91
91
  action: params.action,
92
92
  data: params.data,
@@ -296,5 +296,5 @@ _chunk7QVYU63Ejs.__name.call(void 0, ServerJsonApiDelete, "ServerJsonApiDelete")
296
296
 
297
297
 
298
298
 
299
- exports.ServerAuthService = _chunkW73JBOIRjs.AuthService; exports.ServerCompanyService = _chunkW73JBOIRjs.CompanyService; exports.ServerContentService = _chunkW73JBOIRjs.ContentService; exports.ServerFeatureService = _chunkW73JBOIRjs.FeatureService; exports.ServerJsonApiDelete = ServerJsonApiDelete; exports.ServerJsonApiGet = ServerJsonApiGet; exports.ServerJsonApiPatch = ServerJsonApiPatch; exports.ServerJsonApiPost = ServerJsonApiPost; exports.ServerJsonApiPut = ServerJsonApiPut; exports.ServerNotificationService = _chunkW73JBOIRjs.NotificationService; exports.ServerPushService = _chunkW73JBOIRjs.PushService; exports.ServerRoleService = _chunkW73JBOIRjs.RoleService; exports.ServerS3Service = _chunkW73JBOIRjs.S3Service; exports.ServerSession = ServerSession; exports.ServerUserService = _chunkW73JBOIRjs.UserService; exports.configureServerJsonApi = configureServerJsonApi; exports.getServerApiUrl = getServerApiUrl; exports.getServerAppUrl = getServerAppUrl; exports.getServerToken = _chunkYUO55Q5Ajs.getServerToken; exports.getServerTrackablePages = getServerTrackablePages; exports.invalidateCacheTag = invalidateCacheTag; exports.invalidateCacheTags = invalidateCacheTags; exports.serverRequest = _chunkIOLU4ASDjs.serverRequest;
299
+ exports.ServerAuthService = _chunkAWOOIQLFjs.AuthService; exports.ServerCompanyService = _chunkAWOOIQLFjs.CompanyService; exports.ServerContentService = _chunkAWOOIQLFjs.ContentService; exports.ServerFeatureService = _chunkAWOOIQLFjs.FeatureService; exports.ServerJsonApiDelete = ServerJsonApiDelete; exports.ServerJsonApiGet = ServerJsonApiGet; exports.ServerJsonApiPatch = ServerJsonApiPatch; exports.ServerJsonApiPost = ServerJsonApiPost; exports.ServerJsonApiPut = ServerJsonApiPut; exports.ServerNotificationService = _chunkAWOOIQLFjs.NotificationService; exports.ServerPushService = _chunkAWOOIQLFjs.PushService; exports.ServerRoleService = _chunkAWOOIQLFjs.RoleService; exports.ServerS3Service = _chunkAWOOIQLFjs.S3Service; exports.ServerSession = ServerSession; exports.ServerUserService = _chunkAWOOIQLFjs.UserService; exports.configureServerJsonApi = configureServerJsonApi; exports.getServerApiUrl = getServerApiUrl; exports.getServerAppUrl = getServerAppUrl; exports.getServerToken = _chunkYUO55Q5Ajs.getServerToken; exports.getServerTrackablePages = getServerTrackablePages; exports.invalidateCacheTag = invalidateCacheTag; exports.invalidateCacheTags = invalidateCacheTags; exports.serverRequest = _chunkIOLU4ASDjs.serverRequest;
300
300
  //# sourceMappingURL=index.js.map
@@ -15,7 +15,7 @@ import {
15
15
  S3Service,
16
16
  UserService,
17
17
  checkPermissionsFromServer
18
- } from "../chunk-DVOBOFCF.mjs";
18
+ } from "../chunk-GF4OWZKE.mjs";
19
19
  import "../chunk-AUXK7QSA.mjs";
20
20
  import "../chunk-C7C7VY4F.mjs";
21
21
  import {
@@ -9,6 +9,7 @@ type DataListRetriever<T> = {
9
9
  isLoaded: boolean;
10
10
  data: T[] | undefined;
11
11
  total?: number;
12
+ meta?: Record<string, any>;
12
13
  next?: (onlyNewRecords?: boolean) => Promise<void>;
13
14
  previous?: (onlyNewRecords?: boolean) => Promise<void>;
14
15
  search: (search: string) => Promise<void>;
@@ -9,6 +9,7 @@ type DataListRetriever<T> = {
9
9
  isLoaded: boolean;
10
10
  data: T[] | undefined;
11
11
  total?: number;
12
+ meta?: Record<string, any>;
12
13
  next?: (onlyNewRecords?: boolean) => Promise<void>;
13
14
  previous?: (onlyNewRecords?: boolean) => Promise<void>;
14
15
  search: (search: string) => Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carlonicora/nextjs-jsonapi",
3
- "version": "1.138.1",
3
+ "version": "1.139.1",
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",
@@ -63,6 +63,7 @@ export function EntityMultiSelector<T extends { id: string }>({
63
63
  const [searchTerm, setSearchTerm] = useState("");
64
64
  const [options, setOptions] = useState<OptionData<T>[]>([]);
65
65
  const searchInputRef = useRef<HTMLInputElement>(null);
66
+ const searchTermRef = useRef<string>("");
66
67
 
67
68
  // Stabilize callback props in refs to prevent infinite re-render loops.
68
69
  // These functions are passed inline by consumers (e.g. getLabel={(w) => w.name})
@@ -110,11 +111,10 @@ export function EntityMultiSelector<T extends { id: string }>({
110
111
 
111
112
  const updateSearch = useCallback(
112
113
  (searchedTerm: string) => {
113
- if (searchedTerm.trim()) {
114
- data.addAdditionalParameter("search", searchedTerm.trim());
115
- } else {
116
- data.removeAdditionalParameter("search");
117
- }
114
+ const trimmed = searchedTerm.trim();
115
+ if (trimmed === searchTermRef.current) return;
116
+ searchTermRef.current = trimmed;
117
+ data.search(trimmed);
118
118
  },
119
119
  [data],
120
120
  );
@@ -202,17 +202,15 @@ export function EntityMultiSelector<T extends { id: string }>({
202
202
  [form, id, options],
203
203
  );
204
204
 
205
+ // No client-side filtering: the search term is sent to the API (debounced), so filtering
206
+ // the response again by label would hide matches found on other fields (e.g. email).
205
207
  const sortedOptions = useMemo(() => {
206
- const filtered = searchTerm.trim()
207
- ? options.filter((o) => o.label.toLowerCase().includes(searchTerm.trim().toLowerCase()))
208
- : options;
209
-
210
- return [...filtered].sort((a, b) => {
208
+ return [...options].sort((a, b) => {
211
209
  const aSelected = selectedIds.has(a.id) ? 0 : 1;
212
210
  const bSelected = selectedIds.has(b.id) ? 0 : 1;
213
211
  return aSelected - bSelected;
214
212
  });
215
- }, [options, selectedIds, searchTerm]);
213
+ }, [options, selectedIds]);
216
214
 
217
215
  const triggerSummary = useMemo(() => {
218
216
  if (selectedValues.length === 0) return null;
@@ -36,6 +36,19 @@ export function clearLastApiTotal(): void {
36
36
  lastApiTotal = undefined;
37
37
  }
38
38
 
39
+ // Store the last full top-level `meta` object from any list API call - accessible by
40
+ // hooks that need aggregate meta beyond `total` (e.g. per-list counts). Same
41
+ // module-global design as lastApiTotal above.
42
+ let lastApiMeta: Record<string, any> | undefined = undefined;
43
+
44
+ export function getLastApiMeta(): Record<string, any> | undefined {
45
+ return lastApiMeta;
46
+ }
47
+
48
+ export function clearLastApiMeta(): void {
49
+ lastApiMeta = undefined;
50
+ }
51
+
39
52
  let globalErrorHandler: ((status: number, message: string) => void) | null = null;
40
53
 
41
54
  /**
@@ -258,6 +271,8 @@ export abstract class AbstractService {
258
271
  lastApiTotal = apiResponse.meta.total;
259
272
  if (params.total) params.total.total = apiResponse.meta.total;
260
273
  }
274
+ // Store the full top-level meta too, so hooks can read aggregates beyond `total`.
275
+ lastApiMeta = apiResponse.meta;
261
276
 
262
277
  return apiResponse.data as T;
263
278
  }
@@ -288,6 +288,29 @@ describe("useDataListRetriever", () => {
288
288
  });
289
289
  });
290
290
 
291
+ it("should forward an explicit search additional parameter to the retriever", async () => {
292
+ const retriever = vi.fn().mockResolvedValue([]);
293
+
294
+ const { result } = renderHook(() =>
295
+ useDataListRetriever({
296
+ retriever,
297
+ module: mockModule,
298
+ }),
299
+ );
300
+
301
+ await waitFor(() => {
302
+ expect(result.current.isLoaded).toBe(true);
303
+ });
304
+
305
+ act(() => {
306
+ result.current.addAdditionalParameter("search", "mario");
307
+ });
308
+
309
+ await waitFor(() => {
310
+ expect(retriever).toHaveBeenCalledWith(expect.objectContaining({ search: "mario" }));
311
+ });
312
+ });
313
+
291
314
  it("should remove additional parameter", async () => {
292
315
  const retriever = vi.fn().mockResolvedValue([]);
293
316
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { ClientAbstractService } from "../core/abstracts/ClientAbstractService";
5
- import { getLastApiTotal } from "../core/abstracts/AbstractService";
5
+ import { getLastApiMeta, getLastApiTotal } from "../core/abstracts/AbstractService";
6
6
 
7
7
  export type PageInfo = {
8
8
  startItem: number;
@@ -16,6 +16,7 @@ export type DataListRetriever<T> = {
16
16
  isLoaded: boolean;
17
17
  data: T[] | undefined;
18
18
  total?: number;
19
+ meta?: Record<string, any>;
19
20
  next?: (onlyNewRecords?: boolean) => Promise<void>;
20
21
  previous?: (onlyNewRecords?: boolean) => Promise<void>;
21
22
  search: (search: string) => Promise<void>;
@@ -39,6 +40,7 @@ export function useDataListRetriever<T>(params: {
39
40
  }): DataListRetriever<T> {
40
41
  const [data, setData] = useState<T[] | undefined>(undefined);
41
42
  const [total, setTotal] = useState<number | undefined>(undefined);
43
+ const [meta, setMeta] = useState<Record<string, any> | undefined>(undefined);
42
44
  const [nextPage, setNextPage] = useState<string | undefined>(undefined);
43
45
  const [previousPage, setPreviousPage] = useState<string | undefined>(undefined);
44
46
  const [isLoaded, setIsLoaded] = useState(false);
@@ -194,7 +196,9 @@ export function useDataListRetriever<T>(params: {
194
196
  ...additionalParamsRef.current,
195
197
  };
196
198
 
197
- retrieverParams.search = currentSearchTerm;
199
+ // An explicit `search` passed through addAdditionalParameter wins: overwriting it
200
+ // with the internal term (only ever set by `search()`) silently dropped it.
201
+ if (additionalParamsRef.current.search === undefined) retrieverParams.search = currentSearchTerm;
198
202
  retrieverParams.next = nextRef;
199
203
  retrieverParams.previous = previousRef;
200
204
  retrieverParams.self = selfRef;
@@ -218,6 +222,11 @@ export function useDataListRetriever<T>(params: {
218
222
  if (apiTotal !== undefined) {
219
223
  setTotal(apiTotal);
220
224
  }
225
+ // Full top-level meta (aggregates beyond `total`, e.g. per-list counts)
226
+ const apiMeta = getLastApiMeta();
227
+ if (apiMeta !== undefined) {
228
+ setMeta(apiMeta);
229
+ }
221
230
  }
222
231
  } catch (error) {
223
232
  if (thisRequestId === requestIdRef.current) {
@@ -359,6 +368,7 @@ export function useDataListRetriever<T>(params: {
359
368
  isLoaded: isLoaded,
360
369
  data: data as T[],
361
370
  total,
371
+ meta,
362
372
  next: nextPage ? loadNext : undefined,
363
373
  previous: previousPage ? loadPrevious : undefined,
364
374
  search: search,