ts-time-utils 0.0.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 (80) hide show
  1. package/README.md +343 -0
  2. package/dist/age.d.ts +49 -0
  3. package/dist/age.d.ts.map +1 -0
  4. package/dist/age.js +106 -0
  5. package/dist/calculate.d.ts +49 -0
  6. package/dist/calculate.d.ts.map +1 -0
  7. package/dist/calculate.js +179 -0
  8. package/dist/calendar.d.ts +82 -0
  9. package/dist/calendar.d.ts.map +1 -0
  10. package/dist/calendar.js +154 -0
  11. package/dist/constants.d.ts +35 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/constants.js +17 -0
  14. package/dist/esm/age.d.ts +49 -0
  15. package/dist/esm/age.d.ts.map +1 -0
  16. package/dist/esm/age.js +106 -0
  17. package/dist/esm/calculate.d.ts +49 -0
  18. package/dist/esm/calculate.d.ts.map +1 -0
  19. package/dist/esm/calculate.js +179 -0
  20. package/dist/esm/calendar.d.ts +82 -0
  21. package/dist/esm/calendar.d.ts.map +1 -0
  22. package/dist/esm/calendar.js +154 -0
  23. package/dist/esm/constants.d.ts +35 -0
  24. package/dist/esm/constants.d.ts.map +1 -0
  25. package/dist/esm/constants.js +17 -0
  26. package/dist/esm/format.d.ts +25 -0
  27. package/dist/esm/format.d.ts.map +1 -0
  28. package/dist/esm/format.js +189 -0
  29. package/dist/esm/index.d.ts +17 -0
  30. package/dist/esm/index.d.ts.map +1 -0
  31. package/dist/esm/index.js +28 -0
  32. package/dist/esm/interval.d.ts +30 -0
  33. package/dist/esm/interval.d.ts.map +1 -0
  34. package/dist/esm/interval.js +86 -0
  35. package/dist/esm/parse.d.ts +31 -0
  36. package/dist/esm/parse.d.ts.map +1 -0
  37. package/dist/esm/parse.js +217 -0
  38. package/dist/esm/performance.d.ts +110 -0
  39. package/dist/esm/performance.d.ts.map +1 -0
  40. package/dist/esm/performance.js +222 -0
  41. package/dist/esm/rangePresets.d.ts +45 -0
  42. package/dist/esm/rangePresets.d.ts.map +1 -0
  43. package/dist/esm/rangePresets.js +124 -0
  44. package/dist/esm/timezone.d.ts +38 -0
  45. package/dist/esm/timezone.d.ts.map +1 -0
  46. package/dist/esm/timezone.js +99 -0
  47. package/dist/esm/validate.d.ts +62 -0
  48. package/dist/esm/validate.d.ts.map +1 -0
  49. package/dist/esm/validate.js +108 -0
  50. package/dist/esm/workingHours.d.ts +25 -0
  51. package/dist/esm/workingHours.d.ts.map +1 -0
  52. package/dist/esm/workingHours.js +107 -0
  53. package/dist/format.d.ts +25 -0
  54. package/dist/format.d.ts.map +1 -0
  55. package/dist/format.js +189 -0
  56. package/dist/index.d.ts +17 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +28 -0
  59. package/dist/interval.d.ts +30 -0
  60. package/dist/interval.d.ts.map +1 -0
  61. package/dist/interval.js +86 -0
  62. package/dist/parse.d.ts +31 -0
  63. package/dist/parse.d.ts.map +1 -0
  64. package/dist/parse.js +217 -0
  65. package/dist/performance.d.ts +110 -0
  66. package/dist/performance.d.ts.map +1 -0
  67. package/dist/performance.js +222 -0
  68. package/dist/rangePresets.d.ts +45 -0
  69. package/dist/rangePresets.d.ts.map +1 -0
  70. package/dist/rangePresets.js +124 -0
  71. package/dist/timezone.d.ts +38 -0
  72. package/dist/timezone.d.ts.map +1 -0
  73. package/dist/timezone.js +99 -0
  74. package/dist/validate.d.ts +62 -0
  75. package/dist/validate.d.ts.map +1 -0
  76. package/dist/validate.js +108 -0
  77. package/dist/workingHours.d.ts +25 -0
  78. package/dist/workingHours.d.ts.map +1 -0
  79. package/dist/workingHours.js +107 -0
  80. package/package.json +102 -0
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Interval utilities: operations on time intervals [start, end)
3
+ */
4
+ /** Create an interval ensuring start <= end */
5
+ export function createInterval(start, end) {
6
+ const s = new Date(start);
7
+ const e = new Date(end);
8
+ if (isNaN(s.getTime()) || isNaN(e.getTime()) || s > e)
9
+ return null;
10
+ return { start: s, end: e };
11
+ }
12
+ /** Validate an object is a proper interval */
13
+ export function isValidInterval(i) {
14
+ return !!i && i.start instanceof Date && i.end instanceof Date && !isNaN(i.start) && !isNaN(i.end) && i.start <= i.end;
15
+ }
16
+ /** Duration of interval in ms */
17
+ export function intervalDuration(i) {
18
+ return i.end.getTime() - i.start.getTime();
19
+ }
20
+ /** Whether interval contains date (inclusive start, exclusive end) */
21
+ export function intervalContains(i, date) {
22
+ const d = date instanceof Date ? date : new Date(date);
23
+ return d >= i.start && d < i.end;
24
+ }
25
+ /** Whether two intervals overlap */
26
+ export function intervalsOverlap(a, b) {
27
+ return a.start < b.end && b.start < a.end;
28
+ }
29
+ /** Intersection of two intervals, or null */
30
+ export function intervalIntersection(a, b) {
31
+ const start = a.start > b.start ? a.start : b.start;
32
+ const end = a.end < b.end ? a.end : b.end;
33
+ return start < end ? { start, end } : null;
34
+ }
35
+ /** Merge overlapping or touching intervals into a minimal set */
36
+ export function mergeIntervals(intervals) {
37
+ if (intervals.length === 0)
38
+ return [];
39
+ const sorted = [...intervals].sort((a, b) => a.start.getTime() - b.start.getTime());
40
+ const result = [];
41
+ let current = { ...sorted[0] };
42
+ for (let i = 1; i < sorted.length; i++) {
43
+ const next = sorted[i];
44
+ if (next.start <= current.end) { // overlap or touching
45
+ if (next.end > current.end)
46
+ current.end = next.end;
47
+ }
48
+ else {
49
+ result.push(current);
50
+ current = { ...next };
51
+ }
52
+ }
53
+ result.push(current);
54
+ return result;
55
+ }
56
+ /** Subtract interval b from a (can split into 0,1,2 intervals) */
57
+ export function subtractInterval(a, b) {
58
+ if (!intervalsOverlap(a, b))
59
+ return [a];
60
+ const parts = [];
61
+ if (b.start > a.start)
62
+ parts.push({ start: a.start, end: b.start });
63
+ if (b.end < a.end)
64
+ parts.push({ start: b.end, end: a.end });
65
+ return parts;
66
+ }
67
+ /** Split an interval into day-boundary intervals (UTC based) */
68
+ export function splitIntervalByDay(i) {
69
+ const res = [];
70
+ let cursor = new Date(i.start);
71
+ while (cursor < i.end) {
72
+ const dayEnd = new Date(Date.UTC(cursor.getUTCFullYear(), cursor.getUTCMonth(), cursor.getUTCDate() + 1));
73
+ const end = dayEnd < i.end ? dayEnd : i.end;
74
+ res.push({ start: new Date(cursor), end: new Date(end) });
75
+ cursor = end;
76
+ }
77
+ return res;
78
+ }
79
+ /** Total covered duration of possibly overlapping intervals */
80
+ export function totalIntervalCoverage(intervals) {
81
+ return mergeIntervals(intervals).reduce((sum, i) => sum + intervalDuration(i), 0);
82
+ }
83
+ /** Normalize array: filter invalid and merge */
84
+ export function normalizeIntervals(intervals) {
85
+ return mergeIntervals(intervals.filter(isValidInterval));
86
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Advanced date parsing utilities
3
+ */
4
+ /**
5
+ * Parse various date formats intelligently
6
+ * @param input - date string, number, or Date object
7
+ */
8
+ export declare function parseDate(input: string | number | Date): Date | null;
9
+ /**
10
+ * Parse relative date strings like "tomorrow", "next monday", "2 weeks ago"
11
+ * @param input - relative date string
12
+ */
13
+ export declare function parseRelativeDate(input: string): Date | null;
14
+ /**
15
+ * Parse "time ago" strings like "5 minutes ago", "2 hours ago"
16
+ * @param input - time ago string
17
+ */
18
+ export declare function parseTimeAgo(input: string): Date | null;
19
+ /**
20
+ * Parse custom date format
21
+ * @param dateString - date string to parse
22
+ * @param format - format pattern (e.g., "YYYY-MM-DD", "DD/MM/YYYY")
23
+ */
24
+ export declare function parseCustomFormat(dateString: string, format: string): Date | null;
25
+ /**
26
+ * Try parsing with multiple formats
27
+ * @param dateString - date string to parse
28
+ * @param formats - array of format patterns to try
29
+ */
30
+ export declare function parseManyFormats(dateString: string, formats: string[]): Date | null;
31
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAuDpE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CA6C5D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAiBvD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAmDjF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,CAMnF"}
package/dist/parse.js ADDED
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Advanced date parsing utilities
3
+ */
4
+ /**
5
+ * Parse various date formats intelligently
6
+ * @param input - date string, number, or Date object
7
+ */
8
+ export function parseDate(input) {
9
+ if (input instanceof Date) {
10
+ return isNaN(input.getTime()) ? null : input;
11
+ }
12
+ if (typeof input === 'number') {
13
+ const date = new Date(input);
14
+ return isNaN(date.getTime()) ? null : date;
15
+ }
16
+ if (typeof input !== 'string') {
17
+ return null;
18
+ }
19
+ // Try native Date parsing first, but validate the result
20
+ const nativeDate = new Date(input);
21
+ if (!isNaN(nativeDate.getTime())) {
22
+ // Additional validation for edge cases like "2025-02-30"
23
+ if (input.includes('-') && input.match(/^\d{4}-\d{2}-\d{2}/)) {
24
+ const [year, month, day] = input.split('-').map(Number);
25
+ const testDate = new Date(year, month - 1, day);
26
+ if (testDate.getFullYear() !== year || testDate.getMonth() !== month - 1 || testDate.getDate() !== day) {
27
+ return null;
28
+ }
29
+ }
30
+ return nativeDate;
31
+ }
32
+ // Try common patterns
33
+ const patterns = [
34
+ /^(\d{4})-(\d{2})-(\d{2})$/, // YYYY-MM-DD
35
+ /^(\d{2})\/(\d{2})\/(\d{4})$/, // MM/DD/YYYY
36
+ /^(\d{2})-(\d{2})-(\d{4})$/, // MM-DD-YYYY
37
+ /^(\d{4})(\d{2})(\d{2})$/, // YYYYMMDD
38
+ ];
39
+ for (const pattern of patterns) {
40
+ const match = input.match(pattern);
41
+ if (match) {
42
+ const [, first, second, third] = match;
43
+ // Try different interpretations based on pattern
44
+ if (pattern.source.includes('(\\d{4})')) {
45
+ // Year first format
46
+ const date = new Date(parseInt(first), parseInt(second) - 1, parseInt(third));
47
+ if (!isNaN(date.getTime()))
48
+ return date;
49
+ }
50
+ else {
51
+ // Month/day first format (assuming US format)
52
+ const date = new Date(parseInt(third), parseInt(first) - 1, parseInt(second));
53
+ if (!isNaN(date.getTime()))
54
+ return date;
55
+ }
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+ /**
61
+ * Parse relative date strings like "tomorrow", "next monday", "2 weeks ago"
62
+ * @param input - relative date string
63
+ */
64
+ export function parseRelativeDate(input) {
65
+ const now = new Date();
66
+ const lowercaseInput = input.toLowerCase().trim();
67
+ // Handle simple cases
68
+ switch (lowercaseInput) {
69
+ case 'now':
70
+ case 'today':
71
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate());
72
+ case 'yesterday':
73
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
74
+ case 'tomorrow':
75
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
76
+ }
77
+ // Handle "X time ago" or "in X time"
78
+ const agoMatch = lowercaseInput.match(/^(\d+)\s+(second|minute|hour|day|week|month|year)s?\s+ago$/);
79
+ if (agoMatch) {
80
+ const [, amount, unit] = agoMatch;
81
+ return subtractTimeUnits(now, parseInt(amount), unit);
82
+ }
83
+ const inMatch = lowercaseInput.match(/^in\s+(\d+)\s+(second|minute|hour|day|week|month|year)s?$/);
84
+ if (inMatch) {
85
+ const [, amount, unit] = inMatch;
86
+ return addTimeUnits(now, parseInt(amount), unit);
87
+ }
88
+ // Handle "next/last weekday"
89
+ const weekdays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
90
+ const nextWeekdayMatch = lowercaseInput.match(/^next\s+(sunday|monday|tuesday|wednesday|thursday|friday|saturday)$/);
91
+ if (nextWeekdayMatch) {
92
+ const targetDay = weekdays.indexOf(nextWeekdayMatch[1]);
93
+ const daysUntilTarget = (targetDay - now.getDay() + 7) % 7 || 7;
94
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate() + daysUntilTarget);
95
+ }
96
+ const lastWeekdayMatch = lowercaseInput.match(/^last\s+(sunday|monday|tuesday|wednesday|thursday|friday|saturday)$/);
97
+ if (lastWeekdayMatch) {
98
+ const targetDay = weekdays.indexOf(lastWeekdayMatch[1]);
99
+ const daysSinceTarget = (now.getDay() - targetDay + 7) % 7 || 7;
100
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate() - daysSinceTarget);
101
+ }
102
+ return null;
103
+ }
104
+ /**
105
+ * Parse "time ago" strings like "5 minutes ago", "2 hours ago"
106
+ * @param input - time ago string
107
+ */
108
+ export function parseTimeAgo(input) {
109
+ const now = new Date();
110
+ const lowercaseInput = input.toLowerCase().trim();
111
+ // Handle simple cases
112
+ if (lowercaseInput === 'just now' || lowercaseInput === 'now') {
113
+ return now;
114
+ }
115
+ // Handle "X time ago"
116
+ const match = lowercaseInput.match(/^(\d+)\s+(second|minute|hour|day|week|month|year)s?\s+ago$/);
117
+ if (match) {
118
+ const [, amount, unit] = match;
119
+ return subtractTimeUnits(now, parseInt(amount), unit);
120
+ }
121
+ return null;
122
+ }
123
+ /**
124
+ * Parse custom date format
125
+ * @param dateString - date string to parse
126
+ * @param format - format pattern (e.g., "YYYY-MM-DD", "DD/MM/YYYY")
127
+ */
128
+ export function parseCustomFormat(dateString, format) {
129
+ // Simple implementation for common patterns
130
+ const formatMap = {
131
+ 'YYYY-MM-DD': /^(\d{4})-(\d{2})-(\d{2})$/,
132
+ 'DD/MM/YYYY': /^(\d{2})\/(\d{2})\/(\d{4})$/,
133
+ 'MM/DD/YYYY': /^(\d{2})\/(\d{2})\/(\d{4})$/,
134
+ 'DD-MM-YYYY': /^(\d{2})-(\d{2})-(\d{4})$/,
135
+ 'MM-DD-YYYY': /^(\d{2})-(\d{2})-(\d{4})$/,
136
+ };
137
+ const regex = formatMap[format];
138
+ if (!regex)
139
+ return null;
140
+ const match = dateString.match(regex);
141
+ if (!match)
142
+ return null;
143
+ const [, first, second, third] = match;
144
+ let year, month, day;
145
+ switch (format) {
146
+ case 'YYYY-MM-DD':
147
+ year = parseInt(first);
148
+ month = parseInt(second) - 1;
149
+ day = parseInt(third);
150
+ break;
151
+ case 'DD/MM/YYYY':
152
+ case 'DD-MM-YYYY':
153
+ day = parseInt(first);
154
+ month = parseInt(second) - 1;
155
+ year = parseInt(third);
156
+ break;
157
+ case 'MM/DD/YYYY':
158
+ case 'MM-DD-YYYY':
159
+ month = parseInt(first) - 1;
160
+ day = parseInt(second);
161
+ year = parseInt(third);
162
+ break;
163
+ default:
164
+ return null;
165
+ }
166
+ const date = new Date(year, month, day);
167
+ // Validate that the date components match what was parsed
168
+ // This catches cases like February 30th which JS converts to March 2nd
169
+ if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) {
170
+ return null;
171
+ }
172
+ return isNaN(date.getTime()) ? null : date;
173
+ }
174
+ /**
175
+ * Try parsing with multiple formats
176
+ * @param dateString - date string to parse
177
+ * @param formats - array of format patterns to try
178
+ */
179
+ export function parseManyFormats(dateString, formats) {
180
+ for (const format of formats) {
181
+ const result = parseCustomFormat(dateString, format);
182
+ if (result)
183
+ return result;
184
+ }
185
+ return null;
186
+ }
187
+ // Helper functions
188
+ function addTimeUnits(date, amount, unit) {
189
+ const result = new Date(date);
190
+ switch (unit) {
191
+ case 'second':
192
+ result.setSeconds(result.getSeconds() + amount);
193
+ break;
194
+ case 'minute':
195
+ result.setMinutes(result.getMinutes() + amount);
196
+ break;
197
+ case 'hour':
198
+ result.setHours(result.getHours() + amount);
199
+ break;
200
+ case 'day':
201
+ result.setDate(result.getDate() + amount);
202
+ break;
203
+ case 'week':
204
+ result.setDate(result.getDate() + (amount * 7));
205
+ break;
206
+ case 'month':
207
+ result.setMonth(result.getMonth() + amount);
208
+ break;
209
+ case 'year':
210
+ result.setFullYear(result.getFullYear() + amount);
211
+ break;
212
+ }
213
+ return result;
214
+ }
215
+ function subtractTimeUnits(date, amount, unit) {
216
+ return addTimeUnits(date, -amount, unit);
217
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Async time utilities for delays, timeouts, and performance
3
+ */
4
+ /**
5
+ * Sleep for a specified number of milliseconds
6
+ * @param ms - milliseconds to sleep
7
+ */
8
+ export declare function sleep(ms: number): Promise<void>;
9
+ /**
10
+ * Add a timeout to any promise
11
+ * @param promise - promise to add timeout to
12
+ * @param ms - timeout in milliseconds
13
+ * @param timeoutMessage - optional timeout error message
14
+ */
15
+ export declare function timeout<T>(promise: Promise<T>, ms: number, timeoutMessage?: string): Promise<T>;
16
+ /**
17
+ * Debounce function - delays execution until after delay has passed since last call
18
+ * @param fn - function to debounce
19
+ * @param delay - delay in milliseconds
20
+ */
21
+ export declare function debounce<T extends (...args: any[]) => any>(fn: T, delay: number): (...args: Parameters<T>) => void;
22
+ /**
23
+ * Throttle function - limits execution to once per delay period
24
+ * @param fn - function to throttle
25
+ * @param delay - delay in milliseconds
26
+ */
27
+ export declare function throttle<T extends (...args: any[]) => any>(fn: T, delay: number): (...args: Parameters<T>) => void;
28
+ /**
29
+ * Retry a promise-returning function with exponential backoff
30
+ * @param fn - function that returns a promise
31
+ * @param maxAttempts - maximum number of attempts
32
+ * @param baseDelay - base delay in milliseconds
33
+ * @param maxDelay - maximum delay in milliseconds
34
+ */
35
+ export declare function retry<T>(fn: () => Promise<T>, maxAttempts?: number, baseDelay?: number, maxDelay?: number): Promise<T>;
36
+ /**
37
+ * Stopwatch for measuring elapsed time
38
+ */
39
+ export declare class Stopwatch {
40
+ private startTime;
41
+ private endTime;
42
+ private pausedTime;
43
+ private pauseStart;
44
+ /**
45
+ * Start the stopwatch
46
+ */
47
+ start(): void;
48
+ /**
49
+ * Stop the stopwatch
50
+ */
51
+ stop(): number;
52
+ /**
53
+ * Pause the stopwatch
54
+ */
55
+ pause(): void;
56
+ /**
57
+ * Resume the stopwatch
58
+ */
59
+ resume(): void;
60
+ /**
61
+ * Reset the stopwatch
62
+ */
63
+ reset(): void;
64
+ /**
65
+ * Get elapsed time without stopping
66
+ */
67
+ getElapsed(): number;
68
+ /**
69
+ * Check if stopwatch is running
70
+ */
71
+ isRunning(): boolean;
72
+ /**
73
+ * Check if stopwatch is paused
74
+ */
75
+ isPaused(): boolean;
76
+ }
77
+ /**
78
+ * Create a new stopwatch instance
79
+ */
80
+ export declare function createStopwatch(): Stopwatch;
81
+ /**
82
+ * Measure execution time of a synchronous function
83
+ * @param fn - function to measure
84
+ * @returns tuple of [result, elapsed time in ms]
85
+ */
86
+ export declare function measureTime<T>(fn: () => T): [T, number];
87
+ /**
88
+ * Measure execution time of an asynchronous function
89
+ * @param fn - async function to measure
90
+ * @returns promise that resolves to tuple of [result, elapsed time in ms]
91
+ */
92
+ export declare function measureAsync<T>(fn: () => Promise<T>): Promise<[T, number]>;
93
+ /**
94
+ * Benchmark result interface
95
+ */
96
+ export interface BenchmarkResult {
97
+ totalTime: number;
98
+ averageTime: number;
99
+ minTime: number;
100
+ maxTime: number;
101
+ iterations: number;
102
+ opsPerSecond: number;
103
+ }
104
+ /**
105
+ * Benchmark a function by running it multiple times
106
+ * @param fn - function to benchmark
107
+ * @param iterations - number of iterations to run
108
+ */
109
+ export declare function benchmark(fn: () => void, iterations?: number): BenchmarkResult;
110
+ //# sourceMappingURL=performance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance.d.ts","sourceRoot":"","sources":["../src/performance.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,EAAE,EAAE,MAAM,EACV,cAAc,SAAwB,GACrC,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACxD,EAAE,EAAE,CAAC,EACL,KAAK,EAAE,MAAM,GACZ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAOlC;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EACxD,EAAE,EAAE,CAAC,EACL,KAAK,EAAE,MAAM,GACZ,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAUlC;AAED;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,CAAC,EAC3B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,WAAW,GAAE,MAAU,EACvB,SAAS,GAAE,MAAa,EACxB,QAAQ,GAAE,MAAc,GACvB,OAAO,CAAC,CAAC,CAAC,CAwBZ;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAAuB;IAEzC;;OAEG;IACH,KAAK,IAAI,IAAI;IAUb;;OAEG;IACH,IAAI,IAAI,MAAM;IAed;;OAEG;IACH,KAAK,IAAI,IAAI;IAUb;;OAEG;IACH,MAAM,IAAI,IAAI;IAQd;;OAEG;IACH,KAAK,IAAI,IAAI;IAOb;;OAEG;IACH,UAAU,IAAI,MAAM;IAepB;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,QAAQ,IAAI,OAAO;CAGpB;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,SAAS,CAE3C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAKvD;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAKhF;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,UAAU,GAAE,MAAa,GAAG,eAAe,CAsBpF"}
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Async time utilities for delays, timeouts, and performance
3
+ */
4
+ /**
5
+ * Sleep for a specified number of milliseconds
6
+ * @param ms - milliseconds to sleep
7
+ */
8
+ export function sleep(ms) {
9
+ return new Promise(resolve => setTimeout(resolve, ms));
10
+ }
11
+ /**
12
+ * Add a timeout to any promise
13
+ * @param promise - promise to add timeout to
14
+ * @param ms - timeout in milliseconds
15
+ * @param timeoutMessage - optional timeout error message
16
+ */
17
+ export function timeout(promise, ms, timeoutMessage = 'Operation timed out') {
18
+ return Promise.race([
19
+ promise,
20
+ new Promise((_, reject) => setTimeout(() => reject(new Error(timeoutMessage)), ms))
21
+ ]);
22
+ }
23
+ /**
24
+ * Debounce function - delays execution until after delay has passed since last call
25
+ * @param fn - function to debounce
26
+ * @param delay - delay in milliseconds
27
+ */
28
+ export function debounce(fn, delay) {
29
+ let timeoutId;
30
+ return (...args) => {
31
+ clearTimeout(timeoutId);
32
+ timeoutId = setTimeout(() => fn(...args), delay);
33
+ };
34
+ }
35
+ /**
36
+ * Throttle function - limits execution to once per delay period
37
+ * @param fn - function to throttle
38
+ * @param delay - delay in milliseconds
39
+ */
40
+ export function throttle(fn, delay) {
41
+ let lastCall = 0;
42
+ return (...args) => {
43
+ const now = Date.now();
44
+ if (now - lastCall >= delay) {
45
+ lastCall = now;
46
+ fn(...args);
47
+ }
48
+ };
49
+ }
50
+ /**
51
+ * Retry a promise-returning function with exponential backoff
52
+ * @param fn - function that returns a promise
53
+ * @param maxAttempts - maximum number of attempts
54
+ * @param baseDelay - base delay in milliseconds
55
+ * @param maxDelay - maximum delay in milliseconds
56
+ */
57
+ export async function retry(fn, maxAttempts = 3, baseDelay = 1000, maxDelay = 10000) {
58
+ let lastError;
59
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
60
+ try {
61
+ return await fn();
62
+ }
63
+ catch (error) {
64
+ lastError = error;
65
+ if (attempt === maxAttempts) {
66
+ throw lastError;
67
+ }
68
+ // Exponential backoff with jitter
69
+ const delay = Math.min(baseDelay * Math.pow(2, attempt - 1) + Math.random() * 1000, maxDelay);
70
+ await sleep(delay);
71
+ }
72
+ }
73
+ throw lastError;
74
+ }
75
+ /**
76
+ * Stopwatch for measuring elapsed time
77
+ */
78
+ export class Stopwatch {
79
+ constructor() {
80
+ this.startTime = null;
81
+ this.endTime = null;
82
+ this.pausedTime = 0;
83
+ this.pauseStart = null;
84
+ }
85
+ /**
86
+ * Start the stopwatch
87
+ */
88
+ start() {
89
+ if (this.startTime !== null) {
90
+ throw new Error('Stopwatch is already running');
91
+ }
92
+ this.startTime = performance.now();
93
+ this.endTime = null;
94
+ this.pausedTime = 0;
95
+ this.pauseStart = null;
96
+ }
97
+ /**
98
+ * Stop the stopwatch
99
+ */
100
+ stop() {
101
+ if (this.startTime === null) {
102
+ throw new Error('Stopwatch is not running');
103
+ }
104
+ if (this.pauseStart !== null) {
105
+ this.pausedTime += performance.now() - this.pauseStart;
106
+ this.pauseStart = null;
107
+ }
108
+ this.endTime = performance.now();
109
+ const elapsed = this.endTime - this.startTime - this.pausedTime;
110
+ return elapsed;
111
+ }
112
+ /**
113
+ * Pause the stopwatch
114
+ */
115
+ pause() {
116
+ if (this.startTime === null) {
117
+ throw new Error('Stopwatch is not running');
118
+ }
119
+ if (this.pauseStart !== null) {
120
+ throw new Error('Stopwatch is already paused');
121
+ }
122
+ this.pauseStart = performance.now();
123
+ }
124
+ /**
125
+ * Resume the stopwatch
126
+ */
127
+ resume() {
128
+ if (this.pauseStart === null) {
129
+ throw new Error('Stopwatch is not paused');
130
+ }
131
+ this.pausedTime += performance.now() - this.pauseStart;
132
+ this.pauseStart = null;
133
+ }
134
+ /**
135
+ * Reset the stopwatch
136
+ */
137
+ reset() {
138
+ this.startTime = null;
139
+ this.endTime = null;
140
+ this.pausedTime = 0;
141
+ this.pauseStart = null;
142
+ }
143
+ /**
144
+ * Get elapsed time without stopping
145
+ */
146
+ getElapsed() {
147
+ if (this.startTime === null) {
148
+ return 0;
149
+ }
150
+ const now = performance.now();
151
+ let pausedTime = this.pausedTime;
152
+ if (this.pauseStart !== null) {
153
+ pausedTime += now - this.pauseStart;
154
+ }
155
+ return now - this.startTime - pausedTime;
156
+ }
157
+ /**
158
+ * Check if stopwatch is running
159
+ */
160
+ isRunning() {
161
+ return this.startTime !== null && this.endTime === null && this.pauseStart === null;
162
+ }
163
+ /**
164
+ * Check if stopwatch is paused
165
+ */
166
+ isPaused() {
167
+ return this.pauseStart !== null;
168
+ }
169
+ }
170
+ /**
171
+ * Create a new stopwatch instance
172
+ */
173
+ export function createStopwatch() {
174
+ return new Stopwatch();
175
+ }
176
+ /**
177
+ * Measure execution time of a synchronous function
178
+ * @param fn - function to measure
179
+ * @returns tuple of [result, elapsed time in ms]
180
+ */
181
+ export function measureTime(fn) {
182
+ const start = performance.now();
183
+ const result = fn();
184
+ const elapsed = performance.now() - start;
185
+ return [result, elapsed];
186
+ }
187
+ /**
188
+ * Measure execution time of an asynchronous function
189
+ * @param fn - async function to measure
190
+ * @returns promise that resolves to tuple of [result, elapsed time in ms]
191
+ */
192
+ export async function measureAsync(fn) {
193
+ const start = performance.now();
194
+ const result = await fn();
195
+ const elapsed = performance.now() - start;
196
+ return [result, elapsed];
197
+ }
198
+ /**
199
+ * Benchmark a function by running it multiple times
200
+ * @param fn - function to benchmark
201
+ * @param iterations - number of iterations to run
202
+ */
203
+ export function benchmark(fn, iterations = 1000) {
204
+ const times = [];
205
+ for (let i = 0; i < iterations; i++) {
206
+ const [, elapsed] = measureTime(fn);
207
+ times.push(elapsed);
208
+ }
209
+ const totalTime = times.reduce((sum, time) => sum + time, 0);
210
+ const averageTime = totalTime / iterations;
211
+ const minTime = Math.min(...times);
212
+ const maxTime = Math.max(...times);
213
+ const opsPerSecond = 1000 / averageTime;
214
+ return {
215
+ totalTime,
216
+ averageTime,
217
+ minTime,
218
+ maxTime,
219
+ iterations,
220
+ opsPerSecond
221
+ };
222
+ }