@boostercloud/framework-provider-azure 4.0.0 → 4.0.2

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.
@@ -16,6 +16,7 @@ async function replaceOrDeleteItem(cosmosDb, container, config, id, partitionKey
16
16
  await cosmosDb.database(config.resourceNames.applicationStack).container(container).item(id, partitionKey).delete();
17
17
  }
18
18
  }
19
+ const DEFAULT_PAGE_SIZE = 100;
19
20
  async function search(cosmosDb, config, containerName, filters, limit, afterCursor, paginatedVersion = false, order, projections = '*') {
20
21
  const logger = (0, framework_common_helpers_1.getLogger)(config, 'query-helper#search');
21
22
  const filterExpression = buildFilterExpression(filters);
@@ -38,20 +39,22 @@ async function search(cosmosDb, config, containerName, filters, limit, afterCurs
38
39
  const hasLegacyCursor = typeof (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) === 'string' && /^\d+$/.test(afterCursor.id);
39
40
  // Use Cosmos DB's continuation token pagination
40
41
  const feedOptions = {};
41
- if (limit) {
42
- feedOptions.maxItemCount = limit;
43
- }
44
42
  // Extract continuation token from the cursor (backward compatibility)
45
43
  if (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.continuationToken) {
46
44
  feedOptions.continuationToken = afterCursor.continuationToken;
47
45
  }
48
- else if (!canUseContinuationToken || hasLegacyCursor) {
46
+ // Azure Cosmos DB requires maxItemCount when using continuation tokens
47
+ // Always set maxItemCount in the continuation token path to ensure consistent page sizes
48
+ if (limit || (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.continuationToken) || canUseContinuationToken) {
49
+ feedOptions.maxItemCount = limit !== null && limit !== void 0 ? limit : DEFAULT_PAGE_SIZE;
50
+ }
51
+ if (!(afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.continuationToken) && (!canUseContinuationToken || hasLegacyCursor)) {
49
52
  // Legacy cursor format - fallback to OFFSET for backward compatibility
50
- const offset = (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) ? parseInt(afterCursor.id) : 0;
51
- let legacyQuery = `${finalQuery} OFFSET ${offset}`;
52
- if (limit) {
53
- legacyQuery += ` LIMIT ${limit} `;
54
- }
53
+ const parsedLegacyId = (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) ? parseInt(afterCursor.id, 10) : NaN;
54
+ const offset = Number.isFinite(parsedLegacyId) ? parsedLegacyId : 0;
55
+ // Azure Cosmos DB requires LIMIT when using OFFSET
56
+ const effectiveLimit = limit !== null && limit !== void 0 ? limit : DEFAULT_PAGE_SIZE;
57
+ const legacyQuery = `${finalQuery} OFFSET ${offset} LIMIT ${effectiveLimit} `;
55
58
  const legacyQuerySpec = { ...querySpec, query: legacyQuery };
56
59
  const { resources } = await container.items.query(legacyQuerySpec).fetchAll();
57
60
  const processedResources = processResources(resources);
@@ -59,20 +62,24 @@ async function search(cosmosDb, config, containerName, filters, limit, afterCurs
59
62
  items: processedResources !== null && processedResources !== void 0 ? processedResources : [],
60
63
  count: processedResources.length,
61
64
  cursor: {
62
- id: (offset + processedResources.length).toString(),
65
+ id: (offset + effectiveLimit).toString(),
63
66
  },
64
67
  };
65
68
  }
66
69
  const queryIterator = container.items.query(querySpec, feedOptions);
67
70
  const { resources, continuationToken } = await queryIterator.fetchNext();
68
71
  const finalResources = processResources(resources || []);
72
+ // cursor.id advances by the page size (limit) to maintain consistent page-based offsets
73
+ // that frontends rely on (e.g., limit=5 produces cursors 5, 10 ,15, ...)
74
+ const parsedId = (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) ? parseInt(afterCursor.id, 10) : NaN;
75
+ const previousOffset = Number.isFinite(parsedId) ? parsedId : 0;
76
+ const effectiveLimit = limit !== null && limit !== void 0 ? limit : DEFAULT_PAGE_SIZE;
69
77
  let cursor;
70
78
  if (continuationToken) {
71
- cursor = { continuationToken };
79
+ cursor = { continuationToken, id: (previousOffset + effectiveLimit).toString() };
72
80
  }
73
81
  else if (finalResources.length > 0) {
74
- const currentOffset = (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) && !isNaN(parseInt(afterCursor.id)) ? parseInt(afterCursor.id) : 0;
75
- cursor = { id: (currentOffset + finalResources.length).toString() }; // Use the length of the results to calculate the next id
82
+ cursor = { id: (previousOffset + effectiveLimit).toString() };
76
83
  }
77
84
  return {
78
85
  items: finalResources,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boostercloud/framework-provider-azure",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "Handle Booster's integration with Azure",
5
5
  "keywords": [
6
6
  "framework-provider-azure"
@@ -25,16 +25,16 @@
25
25
  "dependencies": {
26
26
  "@azure/cosmos": "^4.3.0",
27
27
  "@azure/functions": "^4.0.0",
28
- "@azure/identity": "~4.7.0",
28
+ "@azure/identity": "~4.13.0",
29
29
  "@azure/event-hubs": "5.11.1",
30
- "@boostercloud/framework-common-helpers": "^4.0.0",
31
- "@boostercloud/framework-types": "^4.0.0",
30
+ "@boostercloud/framework-common-helpers": "^4.0.2",
31
+ "@boostercloud/framework-types": "^4.0.2",
32
32
  "tslib": "^2.4.0",
33
33
  "@effect-ts/core": "^0.60.4",
34
34
  "@azure/web-pubsub": "~1.1.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@boostercloud/eslint-config": "^4.0.0",
37
+ "@boostercloud/eslint-config": "^4.0.2",
38
38
  "@types/chai": "4.2.18",
39
39
  "@types/chai-as-promised": "7.1.4",
40
40
  "@types/faker": "5.1.5",