@forestadmin-experimental/datasource-cosmos 1.6.2 → 1.6.4

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.
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.createQueryValidator = exports.QueryValidationErrorCode = exports.QueryValidationError = void 0;
27
+ const query_validation_error_1 = __importStar(require("./query-validation-error"));
28
+ exports.QueryValidationError = query_validation_error_1.default;
29
+ Object.defineProperty(exports, "QueryValidationErrorCode", { enumerable: true, get: function () { return query_validation_error_1.QueryValidationErrorCode; } });
30
+ // Characters that are dangerous in Cosmos DB SQL queries
31
+ // These patterns could be used for injection attacks
32
+ const DANGEROUS_PATTERNS = [
33
+ /[;'"\\]/, // SQL injection characters
34
+ /--/, // SQL comment
35
+ /\/\*/, // Block comment start
36
+ /\*\//, // Block comment end
37
+ /\bSELECT\b/i, // SQL keyword
38
+ /\bFROM\b/i, // SQL keyword
39
+ /\bWHERE\b/i, // SQL keyword
40
+ /\bDROP\b/i, // SQL keyword
41
+ /\bDELETE\b/i, // SQL keyword
42
+ /\bUPDATE\b/i, // SQL keyword
43
+ /\bINSERT\b/i, // SQL keyword
44
+ /\bEXEC\b/i, // SQL keyword
45
+ /\bUNION\b/i, // SQL keyword
46
+ /\0/, // Null byte
47
+ ];
48
+ // Valid field name pattern: alphanumeric, underscore, and arrow notation for nesting
49
+ // Must start with a letter or underscore
50
+ const VALID_FIELD_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*(?:->?[a-zA-Z_][a-zA-Z0-9_]*)*$/;
51
+ // Special Cosmos DB system fields that are always valid
52
+ const SYSTEM_FIELDS = new Set(['id', '_ts', '_etag', '_rid', '_self', '_attachments']);
53
+ class QueryValidator {
54
+ constructor(schemaFields, options = {}) {
55
+ this.schema = null;
56
+ this.conditionCount = 0;
57
+ this.options = {
58
+ maxFieldDepth: options.maxFieldDepth ?? 10,
59
+ validateAgainstSchema: options.validateAgainstSchema ?? schemaFields !== undefined,
60
+ allowUnknownFields: options.allowUnknownFields ?? false,
61
+ maxFieldNameLength: options.maxFieldNameLength ?? 256,
62
+ maxConditions: options.maxConditions ?? 100,
63
+ };
64
+ if (schemaFields) {
65
+ this.schema = new Map();
66
+ for (const field of schemaFields) {
67
+ this.schema.set(field, true);
68
+ // Also add parent paths as valid for nested fields
69
+ // e.g., for 'address->city', 'address' is also valid
70
+ const parts = field.split('->');
71
+ for (let i = 1; i < parts.length; i += 1) {
72
+ const parentPath = parts.slice(0, i).join('->');
73
+ this.schema.set(parentPath, true);
74
+ }
75
+ }
76
+ }
77
+ }
78
+ /**
79
+ * Validate a field name for security and correctness
80
+ */
81
+ validateFieldName(field, context = 'field') {
82
+ // Check length
83
+ if (field.length > this.options.maxFieldNameLength) {
84
+ throw new query_validation_error_1.default(`${context} name exceeds maximum length of ${this.options.maxFieldNameLength} characters`, query_validation_error_1.QueryValidationErrorCode.INVALID_FIELD_NAME, field);
85
+ }
86
+ // Check for empty field
87
+ if (!field || field.trim() === '') {
88
+ throw new query_validation_error_1.default(`${context} name cannot be empty`, query_validation_error_1.QueryValidationErrorCode.INVALID_FIELD_NAME, field);
89
+ }
90
+ // Check for dangerous patterns (potential injection)
91
+ for (const pattern of DANGEROUS_PATTERNS) {
92
+ if (pattern.test(field)) {
93
+ throw new query_validation_error_1.default(`${context} contains potentially dangerous characters or patterns`, query_validation_error_1.QueryValidationErrorCode.POTENTIAL_INJECTION, field);
94
+ }
95
+ }
96
+ // Skip further validation for system fields
97
+ if (SYSTEM_FIELDS.has(field)) {
98
+ return;
99
+ }
100
+ // Check valid field name pattern
101
+ if (!VALID_FIELD_NAME_PATTERN.test(field)) {
102
+ throw new query_validation_error_1.default(`${context} '${field}' contains invalid characters. ` +
103
+ `Field names must start with a letter or underscore and contain only ` +
104
+ `alphanumeric characters, underscores, and '->' for nesting.`, query_validation_error_1.QueryValidationErrorCode.INVALID_FIELD_NAME, field);
105
+ }
106
+ // Check nesting depth
107
+ const depth = (field.match(/->/g) || []).length + 1;
108
+ if (depth > this.options.maxFieldDepth) {
109
+ throw new query_validation_error_1.default(`${context} '${field}' exceeds maximum nesting depth of ${this.options.maxFieldDepth}`, query_validation_error_1.QueryValidationErrorCode.MAX_DEPTH_EXCEEDED, field);
110
+ }
111
+ // Validate against schema if enabled
112
+ if (this.options.validateAgainstSchema && this.schema && !this.options.allowUnknownFields) {
113
+ if (!this.schema.has(field) && !SYSTEM_FIELDS.has(field)) {
114
+ throw new query_validation_error_1.default(`${context} '${field}' is not defined in the collection schema`, query_validation_error_1.QueryValidationErrorCode.FIELD_NOT_IN_SCHEMA, field);
115
+ }
116
+ }
117
+ }
118
+ /**
119
+ * Validate a complete condition tree
120
+ */
121
+ validateConditionTree(conditionTree) {
122
+ if (!conditionTree)
123
+ return;
124
+ this.conditionCount = 0;
125
+ this.validateConditionTreeRecursive(conditionTree);
126
+ }
127
+ validateConditionTreeRecursive(conditionTree) {
128
+ // Check condition count limit
129
+ this.conditionCount += 1;
130
+ if (this.conditionCount > this.options.maxConditions) {
131
+ throw new query_validation_error_1.default(`Condition tree exceeds maximum of ${this.options.maxConditions} conditions`, query_validation_error_1.QueryValidationErrorCode.MAX_DEPTH_EXCEEDED);
132
+ }
133
+ if (conditionTree.aggregator !== undefined) {
134
+ const { conditions } = conditionTree;
135
+ if (conditions) {
136
+ for (const condition of conditions) {
137
+ this.validateConditionTreeRecursive(condition);
138
+ }
139
+ }
140
+ return;
141
+ }
142
+ if (conditionTree.operator !== undefined) {
143
+ const { field, value } = conditionTree;
144
+ this.validateFieldName(field, 'Filter field');
145
+ this.validateValue(value, field);
146
+ }
147
+ }
148
+ /**
149
+ * Validate a value for potential injection
150
+ */
151
+ validateValue(value, field) {
152
+ if (value === null || value === undefined) {
153
+ return;
154
+ }
155
+ // Check string values for injection attempts
156
+ if (typeof value === 'string') {
157
+ // Only check for null bytes in string values - other characters are safe
158
+ // when used with parameterized queries
159
+ if (value.includes('\0')) {
160
+ throw new query_validation_error_1.default(`Value for field '${field}' contains null bytes`, query_validation_error_1.QueryValidationErrorCode.POTENTIAL_INJECTION, field);
161
+ }
162
+ }
163
+ // Recursively check array values
164
+ if (Array.isArray(value)) {
165
+ for (const item of value) {
166
+ this.validateValue(item, field);
167
+ }
168
+ }
169
+ // Check object values (for complex filters)
170
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
171
+ for (const key of Object.keys(value)) {
172
+ this.validateFieldName(key, `Object key in value for '${field}'`);
173
+ this.validateValue(value[key], `${field}.${key}`);
174
+ }
175
+ }
176
+ }
177
+ /**
178
+ * Validate sort fields
179
+ */
180
+ validateSort(sort) {
181
+ if (!sort || sort.length === 0)
182
+ return;
183
+ for (const sortClause of sort) {
184
+ this.validateFieldName(sortClause.field, 'Sort field');
185
+ // Ensure ascending is a boolean
186
+ if (typeof sortClause.ascending !== 'boolean') {
187
+ throw new query_validation_error_1.default(`Sort direction for '${sortClause.field}' must be a boolean`, query_validation_error_1.QueryValidationErrorCode.INVALID_SORT_FIELD, sortClause.field);
188
+ }
189
+ }
190
+ }
191
+ /**
192
+ * Validate projection fields
193
+ */
194
+ validateProjection(projection) {
195
+ if (!projection || projection.length === 0)
196
+ return;
197
+ for (const field of projection) {
198
+ this.validateFieldName(field, 'Projection field');
199
+ }
200
+ }
201
+ /**
202
+ * Validate all query parameters at once
203
+ */
204
+ validateQuery(conditionTree, sort, projection) {
205
+ this.validateConditionTree(conditionTree);
206
+ this.validateSort(sort);
207
+ this.validateProjection(projection);
208
+ }
209
+ }
210
+ exports.default = QueryValidator;
211
+ /**
212
+ * Create a validator instance for a given schema
213
+ */
214
+ function createQueryValidator(schemaFields, options) {
215
+ return new QueryValidator(schemaFields, options);
216
+ }
217
+ exports.createQueryValidator = createQueryValidator;
218
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnktdmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL3F1ZXJ5LXZhbGlkYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQU9BLG1GQUEwRjtBQUVqRiwrQkFGRixnQ0FBb0IsQ0FFRTtBQUFFLHlHQUZBLGlEQUF3QixPQUVBO0FBa0N2RCx5REFBeUQ7QUFDekQscURBQXFEO0FBQ3JELE1BQU0sa0JBQWtCLEdBQUc7SUFDekIsU0FBUyxFQUFFLDJCQUEyQjtJQUN0QyxJQUFJLEVBQUUsY0FBYztJQUNwQixNQUFNLEVBQUUsc0JBQXNCO0lBQzlCLE1BQU0sRUFBRSxvQkFBb0I7SUFDNUIsYUFBYSxFQUFFLGNBQWM7SUFDN0IsV0FBVyxFQUFFLGNBQWM7SUFDM0IsWUFBWSxFQUFFLGNBQWM7SUFDNUIsV0FBVyxFQUFFLGNBQWM7SUFDM0IsYUFBYSxFQUFFLGNBQWM7SUFDN0IsYUFBYSxFQUFFLGNBQWM7SUFDN0IsYUFBYSxFQUFFLGNBQWM7SUFDN0IsV0FBVyxFQUFFLGNBQWM7SUFDM0IsWUFBWSxFQUFFLGNBQWM7SUFDNUIsSUFBSSxFQUFFLFlBQVk7Q0FDbkIsQ0FBQztBQUVGLHFGQUFxRjtBQUNyRix5Q0FBeUM7QUFDekMsTUFBTSx3QkFBd0IsR0FBRyx3REFBd0QsQ0FBQztBQUUxRix3REFBd0Q7QUFDeEQsTUFBTSxhQUFhLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUM7QUFFdkYsTUFBcUIsY0FBYztJQUtqQyxZQUFZLFlBQXVCLEVBQUUsVUFBaUMsRUFBRTtRQUhoRSxXQUFNLEdBQWdDLElBQUksQ0FBQztRQUMzQyxtQkFBYyxHQUFHLENBQUMsQ0FBQztRQUd6QixJQUFJLENBQUMsT0FBTyxHQUFHO1lBQ2IsYUFBYSxF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
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Retry handler for Cosmos DB rate limiting (429 errors)
3
+ *
4
+ * Cosmos DB returns 429 (Too Many Requests) when RU/s limits are exceeded.
5
+ * The response includes a 'x-ms-retry-after-ms' header indicating how long to wait.
6
+ * This handler implements exponential backoff with respect to Cosmos DB's retry-after hints.
7
+ */
8
+ export interface RetryOptions {
9
+ /**
10
+ * Maximum number of retry attempts
11
+ * Default: 9 (aligns with Azure SDK default)
12
+ */
13
+ maxRetries?: number;
14
+ /**
15
+ * Initial delay in milliseconds before first retry
16
+ * Default: 1000 (1 second)
17
+ */
18
+ initialDelayMs?: number;
19
+ /**
20
+ * Maximum delay in milliseconds between retries
21
+ * Default: 30000 (30 seconds)
22
+ */
23
+ maxDelayMs?: number;
24
+ /**
25
+ * Multiplier for exponential backoff
26
+ * Default: 2
27
+ */
28
+ backoffMultiplier?: number;
29
+ /**
30
+ * Add random jitter to prevent thundering herd
31
+ * Default: true
32
+ */
33
+ useJitter?: boolean;
34
+ /**
35
+ * Optional callback for retry events (useful for logging/monitoring)
36
+ */
37
+ onRetry?: (attempt: number, delayMs: number, error: Error) => void;
38
+ }
39
+ export interface RetryableError extends Error {
40
+ code?: number | string;
41
+ headers?: {
42
+ 'x-ms-retry-after-ms'?: string;
43
+ [key: string]: string | undefined;
44
+ };
45
+ }
46
+ /**
47
+ * Check if an error is a retryable rate limit error (429)
48
+ */
49
+ export declare function isRateLimitError(error: unknown): error is RetryableError;
50
+ /**
51
+ * Check if an error is a retryable transient error (e.g., network issues, service unavailable)
52
+ */
53
+ export declare function isTransientError(error: unknown): boolean;
54
+ /**
55
+ * Extract retry-after delay from Cosmos DB error response
56
+ */
57
+ export declare function getRetryAfterMs(error: RetryableError): number | null;
58
+ /**
59
+ * Calculate delay for the next retry attempt using exponential backoff
60
+ */
61
+ export declare function calculateBackoffDelay(attempt: number, options: Required<Omit<RetryOptions, 'onRetry'>>, retryAfterMs?: number | null): number;
62
+ /**
63
+ * Execute an async operation with retry logic for rate limiting
64
+ *
65
+ * @param operation The async operation to execute
66
+ * @param options Retry configuration options
67
+ * @returns The result of the operation
68
+ * @throws The last error if all retries are exhausted
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const result = await withRetry(
73
+ * () => container.items.create(item),
74
+ * { maxRetries: 5, onRetry: (attempt, delay) => console.log(`Retry ${attempt}`) }
75
+ * );
76
+ * ```
77
+ */
78
+ export declare function withRetry<T>(operation: () => Promise<T>, options?: RetryOptions): Promise<T>;
79
+ /**
80
+ * Create a retry wrapper with pre-configured options
81
+ *
82
+ * @param defaultOptions Default retry options to use
83
+ * @returns A withRetry function with the default options applied
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const retryWithDefaults = createRetryWrapper({ maxRetries: 5 });
88
+ * const result = await retryWithDefaults(() => container.items.create(item));
89
+ * ```
90
+ */
91
+ export declare function createRetryWrapper(defaultOptions: RetryOptions): <T>(operation: () => Promise<T>, overrideOptions?: RetryOptions) => Promise<T>;
92
+ /**
93
+ * Configure the shared retry options for all Cosmos DB operations
94
+ * @param options Retry configuration
95
+ */
96
+ export declare function configureRetryOptions(options: RetryOptions): void;
97
+ /**
98
+ * Get the current shared retry options
99
+ */
100
+ export declare function getSharedRetryOptions(): RetryOptions;
101
+ //# sourceMappingURL=retry-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-handler.d.ts","sourceRoot":"","sources":["../../src/utils/retry-handler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACpE;AAED,MAAM,WAAW,cAAe,SAAQ,KAAK;IAC3C,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE;QACR,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;KACnC,CAAC;CACH;AAaD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAmBxE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAoBxD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAwBpE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,EAChD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,MAAM,CA6BR;AAWD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,CAAC,CAAC,CA4CZ;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,cAAc,EAAE,YAAY,GAC3B,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,CAGhF;AAQD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAEjE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,YAAY,CAEpD"}
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ /**
3
+ * Retry handler for Cosmos DB rate limiting (429 errors)
4
+ *
5
+ * Cosmos DB returns 429 (Too Many Requests) when RU/s limits are exceeded.
6
+ * The response includes a 'x-ms-retry-after-ms' header indicating how long to wait.
7
+ * This handler implements exponential backoff with respect to Cosmos DB's retry-after hints.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.getSharedRetryOptions = exports.configureRetryOptions = exports.createRetryWrapper = exports.withRetry = exports.calculateBackoffDelay = exports.getRetryAfterMs = exports.isTransientError = exports.isRateLimitError = void 0;
11
+ /**
12
+ * Default retry configuration
13
+ */
14
+ const DEFAULT_OPTIONS = {
15
+ maxRetries: 9,
16
+ initialDelayMs: 1000,
17
+ maxDelayMs: 30000,
18
+ backoffMultiplier: 2,
19
+ useJitter: true,
20
+ };
21
+ /**
22
+ * Check if an error is a retryable rate limit error (429)
23
+ */
24
+ function isRateLimitError(error) {
25
+ if (!error || typeof error !== 'object')
26
+ return false;
27
+ const err = error;
28
+ // Check for Cosmos DB 429 error code
29
+ if (err.code === 429)
30
+ return true;
31
+ // Check message for rate limiting indicators
32
+ if (err.message?.includes('429') || err.message?.toLowerCase().includes('too many requests')) {
33
+ return true;
34
+ }
35
+ // Check for TooManyRequests in error name or message
36
+ if (err.name === 'TooManyRequests' || err.message?.includes('TooManyRequests')) {
37
+ return true;
38
+ }
39
+ return false;
40
+ }
41
+ exports.isRateLimitError = isRateLimitError;
42
+ /**
43
+ * Check if an error is a retryable transient error (e.g., network issues, service unavailable)
44
+ */
45
+ function isTransientError(error) {
46
+ if (!error || typeof error !== 'object')
47
+ return false;
48
+ const err = error;
49
+ const { code } = err;
50
+ // Service unavailable (503), Gateway timeout (504), Request timeout (408)
51
+ if (code === 503 || code === 504 || code === 408)
52
+ return true;
53
+ // Network-related errors
54
+ if (err.message?.includes('ECONNRESET') ||
55
+ err.message?.includes('ETIMEDOUT') ||
56
+ err.message?.includes('ENOTFOUND') ||
57
+ err.message?.includes('socket hang up')) {
58
+ return true;
59
+ }
60
+ return false;
61
+ }
62
+ exports.isTransientError = isTransientError;
63
+ /**
64
+ * Extract retry-after delay from Cosmos DB error response
65
+ */
66
+ function getRetryAfterMs(error) {
67
+ // Check for x-ms-retry-after-ms header (Cosmos DB specific)
68
+ const retryAfterMs = error.headers?.['x-ms-retry-after-ms'];
69
+ if (retryAfterMs) {
70
+ const parsed = parseInt(retryAfterMs, 10);
71
+ if (!Number.isNaN(parsed) && parsed > 0) {
72
+ return parsed;
73
+ }
74
+ }
75
+ // Check for standard Retry-After header (in seconds)
76
+ const retryAfter = error.headers?.['retry-after'];
77
+ if (retryAfter) {
78
+ const parsed = parseInt(retryAfter, 10);
79
+ if (!Number.isNaN(parsed) && parsed > 0) {
80
+ return parsed * 1000; // Convert to milliseconds
81
+ }
82
+ }
83
+ return null;
84
+ }
85
+ exports.getRetryAfterMs = getRetryAfterMs;
86
+ /**
87
+ * Calculate delay for the next retry attempt using exponential backoff
88
+ */
89
+ function calculateBackoffDelay(attempt, options, retryAfterMs) {
90
+ // If Cosmos DB specified a retry-after delay, use it as the base
91
+ if (retryAfterMs && retryAfterMs > 0) {
92
+ // Add a small buffer to the Cosmos DB suggested delay
93
+ const bufferedDelay = Math.min(retryAfterMs * 1.1, options.maxDelayMs);
94
+ if (options.useJitter) {
95
+ // Add up to 20% jitter
96
+ const jitter = Math.random() * 0.2 * bufferedDelay;
97
+ return Math.min(bufferedDelay + jitter, options.maxDelayMs);
98
+ }
99
+ return bufferedDelay;
100
+ }
101
+ // Calculate exponential backoff: initialDelay * (multiplier ^ attempt)
102
+ const exponentialDelay = options.initialDelayMs * options.backoffMultiplier ** attempt;
103
+ const cappedDelay = Math.min(exponentialDelay, options.maxDelayMs);
104
+ if (options.useJitter) {
105
+ // Add jitter: randomize between 50% and 100% of the delay
106
+ const jitterMin = cappedDelay * 0.5;
107
+ const jitterMax = cappedDelay;
108
+ return jitterMin + Math.random() * (jitterMax - jitterMin);
109
+ }
110
+ return cappedDelay;
111
+ }
112
+ exports.calculateBackoffDelay = calculateBackoffDelay;
113
+ /**
114
+ * Sleep for the specified duration
115
+ */
116
+ function sleep(ms) {
117
+ return new Promise(resolve => {
118
+ setTimeout(resolve, ms);
119
+ });
120
+ }
121
+ /**
122
+ * Execute an async operation with retry logic for rate limiting
123
+ *
124
+ * @param operation The async operation to execute
125
+ * @param options Retry configuration options
126
+ * @returns The result of the operation
127
+ * @throws The last error if all retries are exhausted
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * const result = await withRetry(
132
+ * () => container.items.create(item),
133
+ * { maxRetries: 5, onRetry: (attempt, delay) => console.log(`Retry ${attempt}`) }
134
+ * );
135
+ * ```
136
+ */
137
+ async function withRetry(operation, options) {
138
+ const config = { ...DEFAULT_OPTIONS, ...options };
139
+ let lastError = null;
140
+ for (let attempt = 0; attempt <= config.maxRetries; attempt += 1) {
141
+ try {
142
+ // eslint-disable-next-line no-await-in-loop -- Sequential retry logic
143
+ return await operation();
144
+ }
145
+ catch (error) {
146
+ lastError = error;
147
+ // Check if error is retryable
148
+ const isRateLimit = isRateLimitError(error);
149
+ const isTransient = isTransientError(error);
150
+ if (!isRateLimit && !isTransient) {
151
+ // Non-retryable error, throw immediately
152
+ throw error;
153
+ }
154
+ // Check if we've exhausted retries
155
+ if (attempt >= config.maxRetries) {
156
+ throw new Error(`Operation failed after ${config.maxRetries} retries. Last error: ${lastError.message}`);
157
+ }
158
+ // Calculate delay for next retry
159
+ const retryAfterMs = isRateLimit ? getRetryAfterMs(error) : null;
160
+ const delayMs = calculateBackoffDelay(attempt, config, retryAfterMs);
161
+ // Call onRetry callback if provided
162
+ if (options?.onRetry) {
163
+ options.onRetry(attempt + 1, delayMs, lastError);
164
+ }
165
+ // Wait before retrying
166
+ // eslint-disable-next-line no-await-in-loop -- Required for retry delay
167
+ await sleep(delayMs);
168
+ }
169
+ }
170
+ // This should never be reached, but TypeScript needs it
171
+ throw lastError || new Error('Retry failed unexpectedly');
172
+ }
173
+ exports.withRetry = withRetry;
174
+ /**
175
+ * Create a retry wrapper with pre-configured options
176
+ *
177
+ * @param defaultOptions Default retry options to use
178
+ * @returns A withRetry function with the default options applied
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * const retryWithDefaults = createRetryWrapper({ maxRetries: 5 });
183
+ * const result = await retryWithDefaults(() => container.items.create(item));
184
+ * ```
185
+ */
186
+ function createRetryWrapper(defaultOptions) {
187
+ return (operation, overrideOptions) => withRetry(operation, { ...defaultOptions, ...overrideOptions });
188
+ }
189
+ exports.createRetryWrapper = createRetryWrapper;
190
+ /**
191
+ * Shared retry options instance for all models
192
+ * This allows centralized configuration of retry behavior
193
+ */
194
+ let sharedRetryOptions = {};
195
+ /**
196
+ * Configure the shared retry options for all Cosmos DB operations
197
+ * @param options Retry configuration
198
+ */
199
+ function configureRetryOptions(options) {
200
+ sharedRetryOptions = { ...options };
201
+ }
202
+ exports.configureRetryOptions = configureRetryOptions;
203
+ /**
204
+ * Get the current shared retry options
205
+ */
206
+ function getSharedRetryOptions() {
207
+ return { ...sharedRetryOptions };
208
+ }
209
+ exports.getSharedRetryOptions = getSharedRetryOptions;
210
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmV0cnktaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9yZXRyeS1oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7O0dBTUc7OztBQStDSDs7R0FFRztBQUNILE1BQU0sZUFBZSxHQUE0QztJQUMvRCxVQUFVLEVBQUUsQ0FBQztJQUNiLGNBQWMsRUFBRSxJQUFJO0lBQ3BCLFVBQVUsRUFBRSxLQUFLO0lBQ2pCLGlCQUFpQixFQUFFLENBQUM7SUFDcEIsU0FBUyxFQUFFLElBQUk7Q0FDaEIsQ0FBQztBQUVGOztHQUVHO0FBQ0gsU0FBZ0IsZ0JBQWdCLENBQUMsS0FBYztJQUM3QyxJQUFJLENBQUMsS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVE7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUV0RCxNQUFNLEdBQUcsR0FBRyxLQUF1QixDQUFDO0lBRXBDLHFDQUFxQztJQUNyQyxJQUFJLEdBQUcsQ0FBQyxJQUFJLEtBQUssR0FBRztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBRWxDLDZDQUE2QztJQUM3QyxJQUFJLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLEdBQUcsQ0FBQyxPQUFPLEVBQUUsV0FBVyxFQUFFLENBQUMsUUFBUSxDQUFDLG1CQUFtQixDQUFDLEVBQUUsQ0FBQztRQUM3RixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxxREFBcUQ7SUFDckQsSUFBSSxHQUFHLENBQUMsSUFBSSxLQUFLLGlCQUFpQixJQUFJLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLGlCQUFpQixDQUFDLEVBQUUsQ0FBQztRQUMvRSxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFuQkQsNENBbUJDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixnQkFBZ0IsQ0FBQyxLQUFjO0lBQzdDLElBQUksQ0FB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forestadmin-experimental/datasource-cosmos",
3
- "version": "1.6.2",
3
+ "version": "1.6.4",
4
4
  "main": "dist/index.js",
5
5
  "license": "GPL-3.0",
6
6
  "publishConfig": {