@graphql-box/connection-resolver 5.3.1 → 5.4.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 (67) hide show
  1. package/dist/cjs/index.cjs +1 -1
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/esm/index.mjs +1 -1
  4. package/dist/esm/index.mjs.map +1 -1
  5. package/dist/production.analysis.txt +143 -143
  6. package/dist/types/cjs/__testUtils__/generatePageResponse.d.cts.map +1 -1
  7. package/dist/types/cjs/helpers/getCount.d.cts.map +1 -1
  8. package/dist/types/cjs/helpers/getStartAndEndIndexes.d.cts +1 -1
  9. package/dist/types/cjs/helpers/getStartAndEndIndexes.d.cts.map +1 -1
  10. package/dist/types/cjs/helpers/getStartAndEndPageNumbers.d.cts +2 -2
  11. package/dist/types/cjs/helpers/getStartAndEndPageNumbers.d.cts.map +1 -1
  12. package/dist/types/cjs/helpers/hasPreviousNextPage.d.cts.map +1 -1
  13. package/dist/types/cjs/helpers/isFirstPage.d.cts +1 -1
  14. package/dist/types/cjs/helpers/isFirstPage.d.cts.map +1 -1
  15. package/dist/types/cjs/helpers/makeEdges.d.cts.map +1 -1
  16. package/dist/types/cjs/helpers/removeConnectionInputOptions.d.cts.map +1 -1
  17. package/dist/types/cjs/helpers/requestAndCachePages.d.cts.map +1 -1
  18. package/dist/types/cjs/helpers/resolveConnection.d.cts +1 -1
  19. package/dist/types/cjs/helpers/resolveConnection.d.cts.map +1 -1
  20. package/dist/types/cjs/helpers/retrieveCachedConnection.d.cts.map +1 -1
  21. package/dist/types/cjs/helpers/retrieveEntry.d.cts.map +1 -1
  22. package/dist/types/cjs/helpers/validateCursor.d.cts.map +1 -1
  23. package/dist/types/cjs/main/index.d.cts.map +1 -1
  24. package/dist/types/esm/__testUtils__/generatePageResponse.d.ts.map +1 -1
  25. package/dist/types/esm/helpers/getCount.d.ts.map +1 -1
  26. package/dist/types/esm/helpers/getStartAndEndIndexes.d.ts +1 -1
  27. package/dist/types/esm/helpers/getStartAndEndIndexes.d.ts.map +1 -1
  28. package/dist/types/esm/helpers/getStartAndEndPageNumbers.d.ts +2 -2
  29. package/dist/types/esm/helpers/getStartAndEndPageNumbers.d.ts.map +1 -1
  30. package/dist/types/esm/helpers/hasPreviousNextPage.d.ts.map +1 -1
  31. package/dist/types/esm/helpers/isFirstPage.d.ts +1 -1
  32. package/dist/types/esm/helpers/isFirstPage.d.ts.map +1 -1
  33. package/dist/types/esm/helpers/makeEdges.d.ts.map +1 -1
  34. package/dist/types/esm/helpers/removeConnectionInputOptions.d.ts.map +1 -1
  35. package/dist/types/esm/helpers/requestAndCachePages.d.ts.map +1 -1
  36. package/dist/types/esm/helpers/resolveConnection.d.ts +1 -1
  37. package/dist/types/esm/helpers/resolveConnection.d.ts.map +1 -1
  38. package/dist/types/esm/helpers/retrieveCachedConnection.d.ts.map +1 -1
  39. package/dist/types/esm/helpers/retrieveEntry.d.ts.map +1 -1
  40. package/dist/types/esm/helpers/validateCursor.d.ts.map +1 -1
  41. package/dist/types/esm/main/index.d.ts.map +1 -1
  42. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  43. package/package.json +16 -17
  44. package/src/__testUtils__/generateCursorCache.ts +4 -4
  45. package/src/__testUtils__/generatePageResponse.ts +1 -1
  46. package/src/helpers/cacheCursors.ts +2 -2
  47. package/src/helpers/getCount.ts +3 -0
  48. package/src/helpers/getInRangeCachedEdges.ts +1 -1
  49. package/src/helpers/getIndexesOnCurrentPage.test.ts +2 -2
  50. package/src/helpers/getPageNumbersToRequest.ts +1 -1
  51. package/src/helpers/getStartAndEndCursors.ts +1 -1
  52. package/src/helpers/getStartAndEndIndexes.ts +28 -28
  53. package/src/helpers/getStartAndEndPageNumbers.ts +4 -4
  54. package/src/helpers/hasPreviousNextPage.ts +1 -2
  55. package/src/helpers/isCursorLast.test.ts +2 -2
  56. package/src/helpers/makeEntry.ts +1 -1
  57. package/src/helpers/requestAndCachePages.ts +2 -2
  58. package/src/helpers/requestOutstandingPages.ts +1 -1
  59. package/src/helpers/resolveConnection.ts +8 -1
  60. package/src/helpers/retrieveCachedConnection.test.ts +32 -32
  61. package/src/helpers/retrieveCachedConnection.ts +6 -7
  62. package/src/helpers/retrieveEntry.ts +1 -1
  63. package/src/helpers/validateCursor.test.ts +4 -4
  64. package/src/helpers/validateCursor.ts +11 -6
  65. package/src/main/index.test.ts +11 -11
  66. package/src/main/index.ts +5 -5
  67. package/src/types.ts +4 -4
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@graphql-box/connection-resolver",
3
3
  "description": "The GraphQL Box connection resolver module.",
4
- "version": "5.3.1",
4
+ "version": "5.4.1",
5
5
  "author": "Dylan Aubrey",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/badbatch/graphql-box",
@@ -15,6 +15,9 @@
15
15
  "main": "./dist/cjs/index.cjs",
16
16
  "module": "./dist/esm/index.mjs",
17
17
  "types": "./dist/types/cjs/index.d.cts",
18
+ "imports": {
19
+ "#*": "./src/*"
20
+ },
18
21
  "exports": {
19
22
  ".": {
20
23
  "types": {
@@ -29,27 +32,23 @@
29
32
  "access": "public"
30
33
  },
31
34
  "dependencies": {
32
- "@cachemap/core": "^5.0.9",
33
- "js-base64": "^3.7.5",
34
- "type-fest": "^4.5.0",
35
- "@graphql-box/core": "5.3.1"
35
+ "@cachemap/core": "^5.2.2",
36
+ "@types/lodash-es": "^4.17.12",
37
+ "core-js": "^3.39.0",
38
+ "js-base64": "^3.7.7",
39
+ "lodash-es": "^4.17.21",
40
+ "type-fest": "^4.30.0",
41
+ "@graphql-box/core": "5.4.1"
36
42
  },
37
43
  "peerDependencies": {
38
- "@babel/runtime": "<8",
39
- "core-js": "<4",
40
- "graphql": "<17",
41
- "lodash-es": "<5"
44
+ "graphql": "<17"
42
45
  },
43
46
  "devDependencies": {
44
- "@babel/runtime": "^7.20.13",
45
- "@cachemap/map": "^5.0.6",
47
+ "@cachemap/map": "^5.0.8",
46
48
  "@jest/globals": "^29.3.1",
47
- "@types/lodash-es": "^4.14.191",
48
- "core-js": "^3.27.2",
49
- "cts-types": "^0.0.6",
50
- "del-cli": "^5.1.0",
51
- "graphql": "^16.8.1",
52
- "lodash-es": "^4.17.21"
49
+ "cts-types": "^0.0.8",
50
+ "del-cli": "^6.0.0",
51
+ "graphql": "^16.9.0"
53
52
  },
54
53
  "keywords": [
55
54
  "client",
@@ -32,7 +32,7 @@ export const generateCursorCache = async ({
32
32
 
33
33
  await Promise.all(
34
34
  pages.map(async page => {
35
- const isLastPage = page === pages[pages.length - 1];
35
+ const isLastPage = page === pages.at(-1);
36
36
  let resultsOnCurrentPage: number;
37
37
 
38
38
  if (isLastPage) {
@@ -43,18 +43,18 @@ export const generateCursorCache = async ({
43
43
  }
44
44
 
45
45
  const edges = Array.from({ length: resultsOnCurrentPage }, (_v, index) => index).map(index => {
46
- const id = encode(`${index}::${page}`);
46
+ const id = encode(`${String(index)}::${String(page)}`);
47
47
  return { cursor: `${id}::${group}`, node: { id } };
48
48
  });
49
49
 
50
50
  await cacheCursors(cursorCache, { edges, group, headers, page, totalPages, totalResults });
51
- })
51
+ }),
52
52
  );
53
53
  } else {
54
54
  await cursorCache.set(
55
55
  `${group}-metadata`,
56
56
  { totalPages, totalResults },
57
- { cacheHeaders: { cacheControl: headers.get('cache-control') ?? undefined } }
57
+ { cacheHeaders: { cacheControl: headers.get('cache-control') ?? undefined } },
58
58
  );
59
59
  }
60
60
 
@@ -15,7 +15,7 @@ export const generatePageResponse =
15
15
  data: {
16
16
  page,
17
17
  results: Array.from({ length: resultsPerPage }, (_v, index) => index).map(index => {
18
- return { id: encode(`${index}::${page}`) };
18
+ return { id: encode(`${String(index)}::${String(page)}`) };
19
19
  }),
20
20
  totalPages,
21
21
  totalResults,
@@ -12,13 +12,13 @@ export type Params = {
12
12
 
13
13
  export const cacheCursors = async (
14
14
  cursorCache: Core,
15
- { edges, group, headers, page, totalPages, totalResults }: Params
15
+ { edges, group, headers, page, totalPages, totalResults }: Params,
16
16
  ) => {
17
17
  const cacheControl = headers.get('cache-control');
18
18
  const options = cacheControl ? { cacheHeaders: { cacheControl } } : undefined;
19
19
 
20
20
  await Promise.all(
21
- edges.map(async ({ cursor, node }, index) => cursorCache.set(cursor, { group, index, node, page }, options))
21
+ edges.map(async ({ cursor, node }, index) => cursorCache.set(cursor, { group, index, node, page }, options)),
22
22
  );
23
23
 
24
24
  await cursorCache.set(`${group}-metadata`, { totalPages, totalResults }, options);
@@ -1,3 +1,6 @@
1
1
  import { type ConnectionInputOptions } from '../types.ts';
2
2
 
3
+ // Based on how ConnectionInputOptions are generated, either first
4
+ // or last would be set.
5
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
3
6
  export const getCount = ({ first, last }: ConnectionInputOptions) => first ?? last!;
@@ -9,7 +9,7 @@ export type Context = {
9
9
 
10
10
  export const getInRangeCachedEdges = (
11
11
  cachedEdgesByPage: CachedEdges[],
12
- { endIndex, resultsPerPage, startIndex }: Context
12
+ { endIndex, resultsPerPage, startIndex }: Context,
13
13
  ) => {
14
14
  return cachedEdgesByPage.reduce<CachedEdges[]>((inRange, cachedEdgesPage, index) => {
15
15
  const currentPageStartIndex = getCurrentPageStartIndex({ pageIndex: index, startIndex });
@@ -4,7 +4,7 @@ describe('getIndexesOnCurrentPage', () => {
4
4
  describe('when current page is last page', () => {
5
5
  it('should return the correct value', () => {
6
6
  expect(
7
- getIndexesOnCurrentPage({ metadata: { totalPages: 6, totalResults: 53 }, page: 6, resultsPerPage: 10 })
7
+ getIndexesOnCurrentPage({ metadata: { totalPages: 6, totalResults: 53 }, page: 6, resultsPerPage: 10 }),
8
8
  ).toBe(2);
9
9
  });
10
10
  });
@@ -12,7 +12,7 @@ describe('getIndexesOnCurrentPage', () => {
12
12
  describe('when current page is NOT last page', () => {
13
13
  it('should return the correct value', () => {
14
14
  expect(
15
- getIndexesOnCurrentPage({ metadata: { totalPages: 6, totalResults: 53 }, page: 5, resultsPerPage: 10 })
15
+ getIndexesOnCurrentPage({ metadata: { totalPages: 6, totalResults: 53 }, page: 5, resultsPerPage: 10 }),
16
16
  ).toBe(9);
17
17
  });
18
18
  });
@@ -20,7 +20,7 @@ export type Context = {
20
20
 
21
21
  export const getPageNumbersToRequest = (
22
22
  args: ConnectionInputOptions,
23
- { endIndex, entry: { page }, metadata, resultsPerPage, startIndex }: GetPageNumbersToRequestContext & Context
23
+ { endIndex, entry: { page }, metadata, resultsPerPage, startIndex }: GetPageNumbersToRequestContext & Context,
24
24
  ) => {
25
25
  const startPageNumber = getStartPageNumber(args, { page, resultsPerPage, startIndex });
26
26
  const endPageNumber = getEndPageNumber(args, { endIndex, metadata, page, resultsPerPage });
@@ -3,6 +3,6 @@ import { type Edge } from '../types.ts';
3
3
  export const getStartCursor = (edges: Edge[]) => edges[0]?.cursor;
4
4
 
5
5
  export const getEndCursor = (edges: Edge[]) => {
6
- const lastEdge = edges[edges.length - 1];
6
+ const lastEdge = edges.at(-1);
7
7
  return lastEdge?.cursor;
8
8
  };
@@ -13,32 +13,32 @@ export type Context = {
13
13
 
14
14
  export const getStartIndex = (
15
15
  args: ConnectionInputOptions,
16
- { entry: { index, page }, resultsPerPage }: Pick<Context, 'entry' | 'resultsPerPage'>
16
+ { entry: { index, page }, resultsPerPage }: Pick<Context, 'entry' | 'resultsPerPage'>,
17
17
  ) => {
18
18
  const count = getCount(args);
19
19
 
20
20
  return getDirection(args.last) === 'forward'
21
21
  ? { absolute: index + 1, relative: index + 1 }
22
22
  : isFirstPage(page) && index - count < 0
23
- ? { absolute: 0, relative: 0 }
24
- : (() => {
25
- const absoluteStartIndex = index - count;
23
+ ? { absolute: 0, relative: 0 }
24
+ : (() => {
25
+ const absoluteStartIndex = index - count;
26
26
 
27
- if (absoluteStartIndex >= 0) {
28
- return { absolute: absoluteStartIndex, relative: absoluteStartIndex };
29
- }
27
+ if (absoluteStartIndex >= 0) {
28
+ return { absolute: absoluteStartIndex, relative: absoluteStartIndex };
29
+ }
30
30
 
31
- const indexesRemainingAfterLastPage = Math.abs(absoluteStartIndex);
32
- const pagesRemaining = indexesRemainingAfterLastPage / resultsPerPage + 1;
33
- const remainder = indexesRemainingAfterLastPage % resultsPerPage;
34
- const relativeStartIndex = remainder === 0 ? 0 : page - pagesRemaining < 0 ? 0 : resultsPerPage - remainder;
35
- return { absolute: absoluteStartIndex, relative: relativeStartIndex };
36
- })();
31
+ const indexesRemainingAfterLastPage = Math.abs(absoluteStartIndex);
32
+ const pagesRemaining = indexesRemainingAfterLastPage / resultsPerPage + 1;
33
+ const remainder = indexesRemainingAfterLastPage % resultsPerPage;
34
+ const relativeStartIndex = remainder === 0 ? 0 : page - pagesRemaining < 0 ? 0 : resultsPerPage - remainder;
35
+ return { absolute: absoluteStartIndex, relative: relativeStartIndex };
36
+ })();
37
37
  };
38
38
 
39
39
  export const getEndIndex = (
40
40
  args: ConnectionInputOptions,
41
- { entry: { index, page }, metadata: { totalPages, totalResults }, resultsPerPage }: Context
41
+ { entry: { index, page }, metadata: { totalPages, totalResults }, resultsPerPage }: Context,
42
42
  ) => {
43
43
  const count = getCount(args);
44
44
  const indexesOnLastPage = getIndexesOnLastPage({ resultsPerPage, totalResults });
@@ -46,22 +46,22 @@ export const getEndIndex = (
46
46
  return getDirection(args.last) === 'backward'
47
47
  ? { absolute: index - 1, relative: index - 1 }
48
48
  : isLastPage({ page, totalPages }) && index + count > indexesOnLastPage
49
- ? { absolute: indexesOnLastPage, relative: indexesOnLastPage }
50
- : (() => {
51
- const absoluteEndIndex = index + count;
52
- const indexesPerPage = resultsPerPage - 1;
49
+ ? { absolute: indexesOnLastPage, relative: indexesOnLastPage }
50
+ : (() => {
51
+ const absoluteEndIndex = index + count;
52
+ const indexesPerPage = resultsPerPage - 1;
53
53
 
54
- if (absoluteEndIndex <= indexesPerPage) {
55
- return { absolute: absoluteEndIndex, relative: absoluteEndIndex };
56
- }
54
+ if (absoluteEndIndex <= indexesPerPage) {
55
+ return { absolute: absoluteEndIndex, relative: absoluteEndIndex };
56
+ }
57
57
 
58
- const indexesRemainingAfterFirstPage = absoluteEndIndex - indexesPerPage;
59
- const pagesRemaining = indexesRemainingAfterFirstPage / resultsPerPage;
60
- const remainder = indexesRemainingAfterFirstPage % resultsPerPage;
58
+ const indexesRemainingAfterFirstPage = absoluteEndIndex - indexesPerPage;
59
+ const pagesRemaining = indexesRemainingAfterFirstPage / resultsPerPage;
60
+ const remainder = indexesRemainingAfterFirstPage % resultsPerPage;
61
61
 
62
- const relativeEndIndex =
63
- remainder === 0 ? indexesPerPage : page + pagesRemaining > totalPages ? indexesOnLastPage : remainder - 1;
62
+ const relativeEndIndex =
63
+ remainder === 0 ? indexesPerPage : page + pagesRemaining > totalPages ? indexesOnLastPage : remainder - 1;
64
64
 
65
- return { absolute: absoluteEndIndex, relative: relativeEndIndex };
66
- })();
65
+ return { absolute: absoluteEndIndex, relative: relativeEndIndex };
66
+ })();
67
67
  };
@@ -15,19 +15,19 @@ export type Context = {
15
15
 
16
16
  export const getStartPageNumber = (
17
17
  args: ConnectionInputOptions,
18
- { page, resultsPerPage, startIndex }: Omit<PageNumberContext, 'endIndex'> & Omit<Context, 'metadata'>
18
+ { page, resultsPerPage, startIndex }: Omit<PageNumberContext, 'endIndex'> & Omit<Context, 'metadata'>,
19
19
  ) => {
20
20
  if (getDirection(args.last) === 'forward' || startIndex.absolute >= 0) {
21
21
  return page;
22
22
  }
23
23
 
24
24
  const startPageNumber = page - Math.ceil(Math.abs(startIndex.absolute) / resultsPerPage);
25
- return startPageNumber <= 1 ? 1 : startPageNumber;
25
+ return Math.max(startPageNumber, 1);
26
26
  };
27
27
 
28
28
  export const getEndPageNumber = (
29
29
  args: ConnectionInputOptions,
30
- { endIndex, metadata: { totalPages }, page, resultsPerPage }: Omit<PageNumberContext, 'startIndex'> & Context
30
+ { endIndex, metadata: { totalPages }, page, resultsPerPage }: Omit<PageNumberContext, 'startIndex'> & Context,
31
31
  ) => {
32
32
  const indexesPerPage = resultsPerPage - 1;
33
33
 
@@ -40,5 +40,5 @@ export const getEndPageNumber = (
40
40
  }
41
41
 
42
42
  const endPageNumber = page + Math.ceil((endIndex.absolute - indexesPerPage) / resultsPerPage);
43
- return endPageNumber >= totalPages ? totalPages : endPageNumber;
43
+ return Math.min(endPageNumber, totalPages);
44
44
  };
@@ -23,6 +23,5 @@ export const hasNextPage = ({
23
23
  metadata: { totalPages, totalResults },
24
24
  resultsPerPage,
25
25
  }: HasNextPageParams) =>
26
- (isNumber(cachedEdgesByPage[cachedEdgesByPage.length - 1]?.pageNumber) &&
27
- cachedEdgesByPage[cachedEdgesByPage.length - 1]?.pageNumber !== totalPages) ||
26
+ (isNumber(cachedEdgesByPage.at(-1)?.pageNumber) && cachedEdgesByPage.at(-1)?.pageNumber !== totalPages) ||
28
27
  endIndex.relative < getIndexesOnLastPage({ resultsPerPage, totalResults });
@@ -13,7 +13,7 @@ describe('isCursorLast', () => {
13
13
  resultsPerPage: 10,
14
14
  totalPages: 6,
15
15
  totalResults: 53,
16
- })
16
+ }),
17
17
  ).toBe(true);
18
18
  });
19
19
  });
@@ -29,7 +29,7 @@ describe('isCursorLast', () => {
29
29
  resultsPerPage: 10,
30
30
  totalPages: 6,
31
31
  totalResults: 53,
32
- })
32
+ }),
33
33
  ).toBe(false);
34
34
  });
35
35
  });
@@ -9,7 +9,7 @@ export type Context = {
9
9
 
10
10
  export const makeEntry = (
11
11
  args: ConnectionInputOptions,
12
- { metadata: { totalPages, totalResults }, resultsPerPage }: Context
12
+ { metadata: { totalPages, totalResults }, resultsPerPage }: Context,
13
13
  ) => {
14
14
  if (getDirection(args.last) === 'backward') {
15
15
  return { index: getIndexesOnLastPage({ resultsPerPage, totalResults }) + 1, page: totalPages };
@@ -14,7 +14,7 @@ export type Context<Resource extends PlainObject, ResourceNode extends Node> = {
14
14
 
15
15
  export const requestAndCachePages = async <Resource extends PlainObject, ResourceNode extends Node>(
16
16
  pages: number[],
17
- { cursorCache, getters, groupCursor, makeIDCursor, resourceResolver }: Context<Resource, ResourceNode>
17
+ { cursorCache, getters, groupCursor, makeIDCursor, resourceResolver }: Context<Resource, ResourceNode>,
18
18
  ) => {
19
19
  const errors: Error[] = [];
20
20
 
@@ -48,7 +48,7 @@ export const requestAndCachePages = async <Resource extends PlainObject, Resourc
48
48
  }
49
49
 
50
50
  return { edges: [], pageNumber: page };
51
- })
51
+ }),
52
52
  );
53
53
 
54
54
  return { cachedEdges, errors };
@@ -14,7 +14,7 @@ export type RequestMissingPagesCallback = (params: { nextPage: number }) => Prom
14
14
 
15
15
  export const requestOutstandingPages = async (
16
16
  { count, direction, page, results, resultsPerPage, totalPages, totalResults }: RequestMissingPagesParams,
17
- requestCallback: RequestMissingPagesCallback
17
+ requestCallback: RequestMissingPagesCallback,
18
18
  ) => {
19
19
  const resultsOnLastPage = totalResults % totalPages;
20
20
  const outstanding = count - results;
@@ -20,7 +20,14 @@ export type Context<Resource extends PlainObject, ResourceNode extends Node> = {
20
20
 
21
21
  export const resolveConnection = async <Resource extends PlainObject, ResourceNode extends Node>(
22
22
  args: PlainObject & ConnectionInputOptions,
23
- { cursorCache, getters, groupCursor, makeIDCursor, resourceResolver, resultsPerPage }: Context<Resource, ResourceNode>
23
+ {
24
+ cursorCache,
25
+ getters,
26
+ groupCursor,
27
+ makeIDCursor,
28
+ resourceResolver,
29
+ resultsPerPage,
30
+ }: Context<Resource, ResourceNode>,
24
31
  ) => {
25
32
  const { cachedEdges, hasNextPage, hasPreviousPage, indexes, missingPages, totalResults } =
26
33
  await retrieveCachedConnection(args, {