@happyvertical/utils 0.89.9 → 0.89.11

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.
@@ -1,1457 +0,0 @@
1
- import { createId, isCuid } from "@paralleldrive/cuid2";
2
- import { add, format, isValid, parse, parseISO } from "date-fns";
3
- import pluralize from "pluralize";
4
- //#region src/config/env-config.ts
5
- /**
6
- * Convert snake_case to camelCase
7
- * @param str - Snake case string
8
- * @returns Camel case string
9
- * @example
10
- * toCamelCase('max_retries') → 'maxRetries'
11
- * toCamelCase('api_key') → 'apiKey'
12
- */
13
- function toCamelCase(str) {
14
- return str.toLowerCase().replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
15
- }
16
- /**
17
- * Convert camelCase to SCREAMING_SNAKE_CASE
18
- * @param str - Camel case string
19
- * @returns Screaming snake case string
20
- * @example
21
- * toScreamingSnakeCase('maxRetries') → 'MAX_RETRIES'
22
- * toScreamingSnakeCase('apiKey') → 'API_KEY'
23
- */
24
- function toScreamingSnakeCase(str) {
25
- return str.replace(/([A-Z])/g, "_$1").toUpperCase().replace(/^_/, "");
26
- }
27
- /**
28
- * Convert string value to specified type
29
- * @param value - String value from environment variable
30
- * @param type - Target type for conversion
31
- * @returns Converted value
32
- * @throws Error if JSON parsing fails
33
- */
34
- function convertType(value, type) {
35
- switch (type) {
36
- case "number": {
37
- const num = Number(value);
38
- if (Number.isNaN(num)) throw new Error(`Cannot convert "${value}" to number: result is NaN`);
39
- return num;
40
- }
41
- case "boolean": return value.toLowerCase() === "true" || value === "1" || value.toLowerCase() === "yes";
42
- case "json": try {
43
- return JSON.parse(value);
44
- } catch (error) {
45
- throw new Error(`Cannot parse "${value}" as JSON: ${error instanceof Error ? error.message : "Unknown error"}`);
46
- }
47
- default: return value;
48
- }
49
- }
50
- /**
51
- * Load configuration from environment variables
52
- *
53
- * Scans environment variables matching the specified pattern and merges them
54
- * with user-provided options. User options always take precedence over env vars.
55
- *
56
- * @template T - Type of configuration object
57
- * @param userOptions - User-provided configuration (takes precedence)
58
- * @param options - Configuration options for env loading
59
- * @returns Merged configuration with env vars and user options
60
- *
61
- * @example
62
- * ```typescript
63
- * // Load HAVE_AI_* variables
64
- * const config = loadEnvConfig({ provider: 'openai' }, {
65
- * packageName: 'ai',
66
- * schema: {
67
- * provider: 'string',
68
- * model: 'string',
69
- * timeout: 'number',
70
- * maxRetries: 'number'
71
- * }
72
- * });
73
- * // Checks: HAVE_AI_PROVIDER, HAVE_AI_MODEL, HAVE_AI_TIMEOUT, HAVE_AI_MAX_RETRIES
74
- *
75
- * // Load SQLOO_* variables (backward compatibility)
76
- * const sqlConfig = loadEnvConfig({}, {
77
- * prefix: 'SQLOO',
78
- * schema: {
79
- * database: 'string',
80
- * host: 'string',
81
- * port: 'number'
82
- * }
83
- * });
84
- * // Checks: SQLOO_DATABASE, SQLOO_HOST, SQLOO_PORT
85
- *
86
- * // Load without prefix
87
- * const customConfig = loadEnvConfig({}, {
88
- * prefix: '',
89
- * schema: {
90
- * OPENAI_API_KEY: 'string'
91
- * }
92
- * });
93
- * // Checks: OPENAI_API_KEY
94
- * ```
95
- */
96
- function loadEnvConfig(userOptions = {}, options = {}) {
97
- const { prefix = "HAVE", packageName, schema = {}, transform = {}, allowUnknown = true } = options;
98
- const envPrefix = packageName && prefix ? `${prefix}_${packageName.toUpperCase()}_` : prefix ? `${prefix}_` : "";
99
- const config = { ...userOptions };
100
- const environment = typeof process !== "undefined" && process.env ? process.env : {};
101
- const fieldsToScan = allowUnknown ? /* @__PURE__ */ new Set([...Object.keys(schema), ...Object.keys(environment).filter((key) => envPrefix && key.startsWith(envPrefix)).map((key) => {
102
- return toCamelCase(key.slice(envPrefix.length));
103
- })]) : new Set(Object.keys(schema));
104
- for (const fieldName of fieldsToScan) {
105
- if (fieldName in userOptions) continue;
106
- const envVarName = envPrefix ? envPrefix + toScreamingSnakeCase(fieldName) : fieldName;
107
- const envValue = environment[envVarName];
108
- if (envValue === void 0) continue;
109
- const transformFn = transform[fieldName];
110
- if (transformFn) {
111
- try {
112
- config[fieldName] = transformFn(envValue);
113
- } catch (error) {
114
- console.warn(`Failed to transform ${envVarName}="${envValue}":`, error instanceof Error ? error.message : error);
115
- }
116
- continue;
117
- }
118
- const fieldType = schema[fieldName];
119
- if (fieldType) {
120
- try {
121
- config[fieldName] = convertType(envValue, fieldType);
122
- } catch (error) {
123
- console.warn(`Failed to convert ${envVarName}="${envValue}" to ${fieldType}:`, error instanceof Error ? error.message : error);
124
- }
125
- continue;
126
- }
127
- config[fieldName] = envValue;
128
- }
129
- return config;
130
- }
131
- //#endregion
132
- //#region src/shared/code/extraction.ts
133
- /**
134
- * Code extraction utilities for parsing code from text (e.g., AI responses)
135
- *
136
- * Provides functions to extract code blocks, JSON data, and function definitions
137
- * from markdown-formatted text or AI-generated responses.
138
- */
139
- /**
140
- * Extracts a code block from markdown-formatted text
141
- *
142
- * @param text - The text containing markdown code blocks
143
- * @param language - Optional language specifier to match (e.g., 'javascript', 'typescript', 'json')
144
- * @returns The extracted code without markdown delimiters, or empty string if not found
145
- *
146
- * @example
147
- * ```typescript
148
- * const code = extractCodeBlock(`
149
- * Here's the function:
150
- * \`\`\`javascript
151
- * function hello() {
152
- * return 'world';
153
- * }
154
- * \`\`\`
155
- * `, 'javascript');
156
- * // Returns: "function hello() {\n return 'world';\n}"
157
- * ```
158
- */
159
- function extractCodeBlock(text, language) {
160
- if (!text) return "";
161
- const langPattern = language ? `${language}\\s*` : "(?:\\w+\\s*)?";
162
- const codeBlockRegex = new RegExp(`\`\`\`${langPattern}\\r?\\n([\\s\\S]*?)\\r?\\n\`\`\``, "i");
163
- const match = text.match(codeBlockRegex);
164
- if (match?.[1]) return match[1].trim();
165
- const inlineMatch = text.match(/`([^`]+)`/);
166
- if (inlineMatch?.[1]) return inlineMatch[1].trim();
167
- return "";
168
- }
169
- /**
170
- * Extracts and parses JSON from text, handling markdown code blocks
171
- *
172
- * @param text - The text containing JSON data
173
- * @returns The parsed JSON object
174
- * @throws {SyntaxError} If the JSON is invalid
175
- *
176
- * @example
177
- * ```typescript
178
- * const data = extractJSON<{ name: string }>(`
179
- * The result is:
180
- * \`\`\`json
181
- * {
182
- * "name": "example"
183
- * }
184
- * \`\`\`
185
- * `);
186
- * // Returns: { name: "example" }
187
- * ```
188
- */
189
- function extractJSON(text) {
190
- if (!text) throw new SyntaxError("Cannot extract JSON from empty text");
191
- let jsonText = extractCodeBlock(text, "json");
192
- if (!jsonText) jsonText = extractCodeBlock(text);
193
- if (!jsonText) {
194
- const jsonObjectMatch = text.match(/\{[\s\S]*\}/);
195
- const jsonArrayMatch = text.match(/\[[\s\S]*\]/);
196
- if (jsonObjectMatch) jsonText = jsonObjectMatch[0];
197
- else if (jsonArrayMatch) jsonText = jsonArrayMatch[0];
198
- else jsonText = text.trim();
199
- }
200
- try {
201
- return JSON.parse(jsonText);
202
- } catch (error) {
203
- throw new SyntaxError(`Failed to parse JSON: ${error instanceof Error ? error.message : "Unknown error"}`);
204
- }
205
- }
206
- /**
207
- * Extracts all code blocks from markdown-formatted text
208
- *
209
- * @param text - The text containing markdown code blocks
210
- * @param language - Optional language specifier to filter by
211
- * @returns Array of extracted code blocks
212
- *
213
- * @example
214
- * ```typescript
215
- * const blocks = extractAllCodeBlocks(`
216
- * \`\`\`javascript
217
- * const a = 1;
218
- * \`\`\`
219
- *
220
- * \`\`\`typescript
221
- * const b: number = 2;
222
- * \`\`\`
223
- * `);
224
- * // Returns: ["const a = 1;", "const b: number = 2;"]
225
- * ```
226
- */
227
- function extractAllCodeBlocks(text, language) {
228
- if (!text) return [];
229
- const langPattern = language ? `${language}\\s*` : "(?:\\w+\\s*)?";
230
- const codeBlockRegex = new RegExp(`\`\`\`${langPattern}\\r?\\n([\\s\\S]*?)\\r?\\n\`\`\``, "gi");
231
- const blocks = [];
232
- const matches = text.matchAll(codeBlockRegex);
233
- for (const match of matches) if (match[1]) blocks.push(match[1].trim());
234
- return blocks;
235
- }
236
- /**
237
- * Extracts a specific function definition from code
238
- *
239
- * @param code - The code containing function definitions
240
- * @param functionName - The name of the function to extract
241
- * @returns The function definition, or empty string if not found
242
- *
243
- * @example
244
- * ```typescript
245
- * const code = `
246
- * function foo() { return 1; }
247
- * function bar() { return 2; }
248
- * `;
249
- *
250
- * const fooFunc = extractFunctionDefinition(code, 'foo');
251
- * // Returns: "function foo() { return 1; }"
252
- * ```
253
- */
254
- function extractFunctionDefinition(code, functionName) {
255
- if (!code || !functionName) return "";
256
- const patterns = [
257
- {
258
- regex: new RegExp(`function\\s+${functionName}\\s*\\([^)]*\\)\\s*\\{`, "i"),
259
- hasBraces: true
260
- },
261
- {
262
- regex: new RegExp(`(?:const|let|var)\\s+${functionName}\\s*=\\s*function\\s*\\([^)]*\\)\\s*\\{`, "i"),
263
- hasBraces: true
264
- },
265
- {
266
- regex: new RegExp(`(?:const|let|var)\\s+${functionName}\\s*=\\s*\\([^)]*\\)\\s*=>\\s*\\{`, "i"),
267
- hasBraces: true
268
- },
269
- {
270
- regex: new RegExp(`(?:const|let|var)\\s+${functionName}\\s*=\\s*\\([^)]*\\)\\s*=>\\s*[^;]+;?`, "i"),
271
- hasBraces: false
272
- }
273
- ];
274
- for (const { regex, hasBraces } of patterns) {
275
- const match = code.match(regex);
276
- if (match && match.index !== void 0) {
277
- const startIdx = match.index;
278
- if (!hasBraces) return match[0].trim();
279
- const braceIdx = code.indexOf("{", startIdx);
280
- if (braceIdx === -1) continue;
281
- let idx = braceIdx;
282
- let depth = 0;
283
- let endIdx = -1;
284
- while (idx < code.length) {
285
- const char = code[idx];
286
- if (char === "{") depth++;
287
- else if (char === "}") {
288
- depth--;
289
- if (depth === 0) {
290
- endIdx = idx;
291
- break;
292
- }
293
- }
294
- idx++;
295
- }
296
- if (endIdx !== -1) return code.slice(startIdx, endIdx + 1).trim();
297
- }
298
- }
299
- return "";
300
- }
301
- //#endregion
302
- //#region src/shared/code/validation.ts
303
- /**
304
- * Default dangerous patterns that should be disallowed
305
- */
306
- var DANGEROUS_PATTERNS = [
307
- /require\s*\(/i,
308
- /import\s+/i,
309
- /eval\s*\(/i,
310
- /Function\s*\(/i,
311
- /process\./i,
312
- /fs\./i,
313
- /child_process/i,
314
- /__dirname/i,
315
- /__filename/i,
316
- /global\./i
317
- ];
318
- /**
319
- * Validates code before execution in a sandbox
320
- *
321
- * @param code - The code to validate
322
- * @param options - Validation options
323
- * @returns Validation result with errors and warnings
324
- *
325
- * @example
326
- * ```typescript
327
- * const result = validateCode(`
328
- * function parse(data) {
329
- * return JSON.parse(data);
330
- * }
331
- * `, {
332
- * allowedGlobals: ['JSON'],
333
- * maxLength: 10000
334
- * });
335
- *
336
- * if (!result.valid) {
337
- * console.error('Code validation failed:', result.errors);
338
- * }
339
- * ```
340
- */
341
- function validateCode(code, options = {}) {
342
- const { allowedGlobals, disallowedPatterns = DANGEROUS_PATTERNS, maxLength = 5e4, allowRequire = false, allowImport = false, allowEval = false, checkSyntax = true } = options;
343
- const errors = [];
344
- const warnings = [];
345
- if (!code || code.trim().length === 0) {
346
- errors.push("Code is empty");
347
- return {
348
- valid: false,
349
- errors,
350
- warnings
351
- };
352
- }
353
- if (code.length > maxLength) errors.push(`Code exceeds maximum length (${code.length} > ${maxLength} characters)`);
354
- const patternFlags = /* @__PURE__ */ new Map([
355
- [DANGEROUS_PATTERNS[0], "require"],
356
- [DANGEROUS_PATTERNS[1], "import"],
357
- [DANGEROUS_PATTERNS[2], "eval"],
358
- [DANGEROUS_PATTERNS[3], "eval"]
359
- ]);
360
- const effectivePatterns = disallowedPatterns.filter((_pattern, index) => {
361
- const patternType = patternFlags.get(DANGEROUS_PATTERNS[index]);
362
- if (patternType === "require" && allowRequire) return false;
363
- if (patternType === "import" && allowImport) return false;
364
- if (patternType === "eval" && allowEval) return false;
365
- return true;
366
- });
367
- for (const pattern of effectivePatterns) if (pattern.test(code)) errors.push(`Code contains disallowed pattern: ${pattern.source.replace(/\\/g, "")}`);
368
- if (allowedGlobals) {
369
- const undeclaredVars = findUndeclaredVariables(code, allowedGlobals);
370
- if (undeclaredVars.length > 0) warnings.push(`Potentially undeclared variables: ${undeclaredVars.join(", ")}`);
371
- }
372
- if (checkSyntax) {
373
- const syntaxErrors = checkCodeSyntax(code);
374
- errors.push(...syntaxErrors);
375
- }
376
- const stats = {
377
- length: code.length,
378
- lines: code.split("\n").length,
379
- hasAsync: /\basync\b\s*(function|\([\w\s,={}[\]]*\)\s*=>|\w+\s*\()/m.test(code),
380
- hasArrowFunctions: /=>/.test(code),
381
- hasClasses: /\bclass\s+\w+/.test(code)
382
- };
383
- if (stats.lines > 100) warnings.push(`Code is long (${stats.lines} lines) - consider breaking into smaller functions`);
384
- return {
385
- valid: errors.length === 0,
386
- errors,
387
- warnings,
388
- stats
389
- };
390
- }
391
- /**
392
- * Checks code syntax without executing it
393
- *
394
- * @param code - The code to check
395
- * @returns Array of syntax error messages (empty if valid)
396
- */
397
- function checkCodeSyntax(code) {
398
- const errors = [];
399
- try {
400
- new Function(code);
401
- } catch (error) {
402
- if (error instanceof SyntaxError) {
403
- const message = error.message;
404
- if (message.includes("await is only valid") && /\bawait\b/.test(code)) try {
405
- new Function(`(async function() { ${code} })()`);
406
- return errors;
407
- } catch (asyncError) {
408
- if (asyncError instanceof SyntaxError) errors.push(`Syntax error: ${asyncError.message}`);
409
- }
410
- else errors.push(`Syntax error: ${message}`);
411
- }
412
- }
413
- return errors;
414
- }
415
- /**
416
- * Finds potentially undeclared variables in code
417
- *
418
- * **Important Limitations:**
419
- * This is a basic regex-based static analysis with known limitations:
420
- * - Cannot detect variables in destructuring assignments
421
- * - May miss variables declared in nested scopes
422
- * - Cannot handle dynamic variable access (e.g., obj[varName])
423
- * - Will have false positives for method calls and object properties
424
- * - Does not understand scope chains or closures
425
- *
426
- * For production use cases requiring accurate variable analysis, consider using
427
- * a proper AST parser like @babel/parser or acorn.
428
- *
429
- * @param code - The code to analyze
430
- * @param allowedGlobals - List of allowed global variables
431
- * @returns Array of potentially undeclared variable names (may include false positives)
432
- */
433
- function findUndeclaredVariables(code, allowedGlobals) {
434
- const undeclaredVars = /* @__PURE__ */ new Set();
435
- const matches = code.matchAll(/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\b/g);
436
- const declaredVars = /* @__PURE__ */ new Set();
437
- const declarations = code.matchAll(/\b(?:var|let|const|function)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g);
438
- for (const match of declarations) if (match[1]) declaredVars.add(match[1]);
439
- for (const match of matches) {
440
- const identifier = match[1];
441
- if (isJavaScriptKeyword(identifier)) continue;
442
- if (declaredVars.has(identifier)) continue;
443
- if (allowedGlobals.includes(identifier)) continue;
444
- if (isCommonBuiltin(identifier)) continue;
445
- undeclaredVars.add(identifier);
446
- }
447
- return Array.from(undeclaredVars);
448
- }
449
- /**
450
- * Checks if a word is a JavaScript keyword
451
- */
452
- function isJavaScriptKeyword(word) {
453
- return [
454
- "break",
455
- "case",
456
- "catch",
457
- "class",
458
- "const",
459
- "continue",
460
- "debugger",
461
- "default",
462
- "delete",
463
- "do",
464
- "else",
465
- "export",
466
- "extends",
467
- "finally",
468
- "for",
469
- "function",
470
- "if",
471
- "import",
472
- "in",
473
- "instanceof",
474
- "let",
475
- "new",
476
- "return",
477
- "super",
478
- "switch",
479
- "this",
480
- "throw",
481
- "try",
482
- "typeof",
483
- "var",
484
- "void",
485
- "while",
486
- "with",
487
- "yield",
488
- "async",
489
- "await"
490
- ].includes(word);
491
- }
492
- /**
493
- * Checks if a word is a common JavaScript built-in
494
- */
495
- function isCommonBuiltin(word) {
496
- return [
497
- "Array",
498
- "Object",
499
- "String",
500
- "Number",
501
- "Boolean",
502
- "Date",
503
- "Math",
504
- "JSON",
505
- "RegExp",
506
- "Error",
507
- "Map",
508
- "Set",
509
- "Promise",
510
- "Symbol",
511
- "undefined",
512
- "null",
513
- "true",
514
- "false",
515
- "console",
516
- "parseInt",
517
- "parseFloat",
518
- "isNaN",
519
- "isFinite",
520
- "decodeURI",
521
- "decodeURIComponent",
522
- "encodeURI",
523
- "encodeURIComponent"
524
- ].includes(word);
525
- }
526
- /**
527
- * Quick validation to check if code is safe for execution
528
- * Returns true if code passes basic safety checks
529
- *
530
- * @param code - The code to check
531
- * @returns true if code is safe, false otherwise
532
- *
533
- * @example
534
- * ```typescript
535
- * if (isSafeCode('return x + y')) {
536
- * // Safe to execute
537
- * }
538
- * ```
539
- */
540
- function isSafeCode(code) {
541
- return validateCode(code, {
542
- maxLength: 5e4,
543
- checkSyntax: true
544
- }).valid;
545
- }
546
- //#endregion
547
- //#region src/shared/logger.ts
548
- /**
549
- * Console-based logger implementation
550
- *
551
- * Routes all log messages to the appropriate console methods with optional context.
552
- */
553
- var ConsoleLogger = class {
554
- debug(message, context) {
555
- if (context) console.debug(message, context);
556
- else console.debug(message);
557
- }
558
- info(message, context) {
559
- if (context) console.info(message, context);
560
- else console.info(message);
561
- }
562
- warn(message, context) {
563
- if (context) console.warn(message, context);
564
- else console.warn(message);
565
- }
566
- error(message, context) {
567
- if (context) console.error(message, context);
568
- else console.error(message);
569
- }
570
- };
571
- /**
572
- * No-operation logger that discards all log messages
573
- *
574
- * Useful for disabling logging in production or testing environments.
575
- */
576
- var NoOpLogger = class {
577
- debug() {}
578
- info() {}
579
- warn() {}
580
- error() {}
581
- };
582
- /** Global logger instance used throughout the SDK */
583
- var globalLogger = new ConsoleLogger();
584
- /**
585
- * Replace the global logger with a custom implementation
586
- *
587
- * @param logger - Custom logger implementation
588
- * @example
589
- * ```typescript
590
- * setLogger(new CustomLogger());
591
- * ```
592
- */
593
- var setLogger = (logger) => {
594
- globalLogger = logger;
595
- };
596
- /**
597
- * Get the current global logger instance
598
- *
599
- * @returns Current logger implementation
600
- * @example
601
- * ```typescript
602
- * const logger = getLogger();
603
- * logger.info('Application started');
604
- * ```
605
- */
606
- var getLogger = () => {
607
- return globalLogger;
608
- };
609
- /**
610
- * Disable all logging by switching to no-op logger
611
- *
612
- * @example
613
- * ```typescript
614
- * if (process.env.NODE_ENV === 'production') {
615
- * disableLogging();
616
- * }
617
- * ```
618
- */
619
- var disableLogging = () => {
620
- globalLogger = new NoOpLogger();
621
- };
622
- /**
623
- * Enable console logging by switching to console logger
624
- *
625
- * @example
626
- * ```typescript
627
- * enableLogging(); // Re-enable after disabling
628
- * ```
629
- */
630
- var enableLogging = () => {
631
- globalLogger = new ConsoleLogger();
632
- };
633
- //#endregion
634
- //#region src/shared/types.ts
635
- /**
636
- * Shared type definitions and interfaces for universal use
637
- *
638
- * This module provides standardized error classes and logging interfaces
639
- * used throughout the HAVE SDK. All error classes extend BaseError to
640
- * provide consistent error handling with context and timestamps.
641
- */
642
- /**
643
- * Standardized error codes used across the HAVE SDK
644
- *
645
- * These codes provide consistent error categorization for better error handling
646
- * and monitoring across all packages in the SDK.
647
- */
648
- var ErrorCode = /* @__PURE__ */ function(ErrorCode) {
649
- /** Input validation failed */
650
- ErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR";
651
- /** API request/response error */
652
- ErrorCode["API_ERROR"] = "API_ERROR";
653
- /** File system operation error */
654
- ErrorCode["FILE_ERROR"] = "FILE_ERROR";
655
- /** Network connectivity or HTTP error */
656
- ErrorCode["NETWORK_ERROR"] = "NETWORK_ERROR";
657
- /** Database operation error */
658
- ErrorCode["DATABASE_ERROR"] = "DATABASE_ERROR";
659
- /** Data parsing or format error */
660
- ErrorCode["PARSING_ERROR"] = "PARSING_ERROR";
661
- /** Operation timeout error */
662
- ErrorCode["TIMEOUT_ERROR"] = "TIMEOUT_ERROR";
663
- /** Unspecified or unexpected error */
664
- ErrorCode["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
665
- return ErrorCode;
666
- }({});
667
- /**
668
- * Base error class providing standardized error handling across the HAVE SDK
669
- *
670
- * All custom errors extend this class to ensure consistent error structure,
671
- * context preservation, and debugging capabilities.
672
- *
673
- * @example
674
- * ```typescript
675
- * throw new BaseError('Something went wrong', ErrorCode.UNKNOWN_ERROR, {
676
- * userId: 123,
677
- * operation: 'processData'
678
- * });
679
- * ```
680
- */
681
- var BaseError = class extends Error {
682
- /** Error classification code */
683
- code;
684
- /** Additional context data for debugging */
685
- context;
686
- /** When the error occurred */
687
- timestamp;
688
- constructor(message, code = "UNKNOWN_ERROR", context, options) {
689
- super(message, options);
690
- this.name = this.constructor.name;
691
- this.code = code;
692
- this.context = context;
693
- this.timestamp = /* @__PURE__ */ new Date();
694
- Error.captureStackTrace?.(this, this.constructor);
695
- }
696
- /**
697
- * Serializes the error to a JSON-compatible object
698
- * @returns Object containing all error properties
699
- */
700
- toJSON() {
701
- return {
702
- name: this.name,
703
- message: this.message,
704
- code: this.code,
705
- context: this.context,
706
- timestamp: this.timestamp.toISOString(),
707
- stack: this.stack
708
- };
709
- }
710
- };
711
- /**
712
- * Produces a shallow JSON representation of a native error cause.
713
- *
714
- * Error properties are non-enumerable, so serializing a cause directly loses
715
- * the message and driver diagnostics. Keep the projection intentionally
716
- * shallow to avoid cycles while retaining the fields database drivers use for
717
- * actionable failures.
718
- */
719
- function serializeErrorCause(cause) {
720
- if (!(cause instanceof Error)) return cause;
721
- const driverFields = [
722
- "code",
723
- "detail",
724
- "hint",
725
- "severity",
726
- "errno"
727
- ];
728
- const serialized = {
729
- name: cause.name,
730
- message: cause.message
731
- };
732
- for (const field of driverFields) {
733
- const value = cause[field];
734
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") serialized[field] = value;
735
- }
736
- return serialized;
737
- }
738
- /**
739
- * Error thrown when input validation fails
740
- *
741
- * @example
742
- * ```typescript
743
- * throw new ValidationError('Email format invalid', {
744
- * email: 'invalid-email',
745
- * field: 'userEmail'
746
- * });
747
- * ```
748
- */
749
- var ValidationError = class extends BaseError {
750
- constructor(message, context) {
751
- super(message, "VALIDATION_ERROR", context);
752
- }
753
- };
754
- /**
755
- * Error thrown for API-related failures
756
- *
757
- * @example
758
- * ```typescript
759
- * throw new ApiError('HTTP 404 Not Found', {
760
- * url: 'https://api.example.com/users/123',
761
- * status: 404
762
- * });
763
- * ```
764
- */
765
- var ApiError = class extends BaseError {
766
- constructor(message, context) {
767
- super(message, "API_ERROR", context);
768
- }
769
- };
770
- /**
771
- * Error thrown for file system operation failures
772
- *
773
- * @example
774
- * ```typescript
775
- * throw new FileError('File not found', {
776
- * path: '/path/to/missing/file.txt',
777
- * operation: 'read'
778
- * });
779
- * ```
780
- */
781
- var FileError = class extends BaseError {
782
- constructor(message, context) {
783
- super(message, "FILE_ERROR", context);
784
- }
785
- };
786
- /**
787
- * Error thrown for network connectivity or HTTP failures
788
- *
789
- * @example
790
- * ```typescript
791
- * throw new NetworkError('Connection timeout', {
792
- * host: 'example.com',
793
- * timeout: 5000,
794
- * attempt: 3
795
- * });
796
- * ```
797
- */
798
- var NetworkError = class extends BaseError {
799
- constructor(message, context) {
800
- super(message, "NETWORK_ERROR", context);
801
- }
802
- };
803
- /**
804
- * Error thrown for database operation failures
805
- *
806
- * @example
807
- * ```typescript
808
- * const cause = Object.assign(new Error('relation does not exist'), {
809
- * code: '42P01'
810
- * });
811
- * throw new DatabaseError(
812
- * 'Query failed: relation does not exist',
813
- * { operation: 'query' },
814
- * cause
815
- * );
816
- * ```
817
- *
818
- * SQL adapters supply a sanitized error snapshot as `cause`. It remains a
819
- * standard, non-enumerable native Error cause, while `toJSON()` exposes a
820
- * shallow projection of common driver diagnostics for structured logging.
821
- */
822
- var DatabaseError = class extends BaseError {
823
- constructor(message, context, cause) {
824
- super(message, "DATABASE_ERROR", context, cause === void 0 ? void 0 : { cause });
825
- }
826
- toJSON() {
827
- return {
828
- ...super.toJSON(),
829
- ...this.cause === void 0 ? {} : { cause: serializeErrorCause(this.cause) }
830
- };
831
- }
832
- };
833
- /**
834
- * Error thrown for data parsing or format failures
835
- *
836
- * @example
837
- * ```typescript
838
- * throw new ParsingError('Invalid JSON format', {
839
- * input: '{invalid json}',
840
- * parser: 'JSON.parse',
841
- * position: 1
842
- * });
843
- * ```
844
- */
845
- var ParsingError = class extends BaseError {
846
- constructor(message, context) {
847
- super(message, "PARSING_ERROR", context);
848
- }
849
- };
850
- /**
851
- * Error thrown when operations exceed their timeout duration
852
- *
853
- * @example
854
- * ```typescript
855
- * throw new TimeoutError('Operation timed out', {
856
- * timeout: 5000,
857
- * operation: 'fetchData',
858
- * elapsedTime: 5234
859
- * });
860
- * ```
861
- */
862
- var TimeoutError = class extends BaseError {
863
- constructor(message, context) {
864
- super(message, "TIMEOUT_ERROR", context);
865
- }
866
- };
867
- //#endregion
868
- //#region src/shared/universal.ts
869
- /**
870
- * Universal utilities that work in both browser and Node.js environments
871
- */
872
- /**
873
- * Generates a unique identifier using CUID2 (preferred) or UUID fallback
874
- *
875
- * CUID2 is more secure and collision-resistant than UUIDs, but UUID is provided
876
- * as a fallback for RFC4122 compliance requirements.
877
- *
878
- * @param type - ID type: 'cuid2' (default) or 'uuid'
879
- * @returns A unique identifier string
880
- * @example
881
- * ```typescript
882
- * const id = makeId(); // CUID2: "ckx5f8h3z0000qzrmn831i7rn"
883
- * const uuid = makeId('uuid'); // UUID: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
884
- * ```
885
- */
886
- var makeId = (type = "cuid2") => {
887
- if (type === "cuid2") return createId();
888
- if (crypto?.randomUUID) return crypto.randomUUID();
889
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
890
- const r = Math.random() * 16 | 0;
891
- return (c === "x" ? r : r & 3 | 8).toString(16);
892
- });
893
- };
894
- /**
895
- * Generates a CUID2 identifier (collision-resistant, more secure than UUID)
896
- *
897
- * CUID2 provides better entropy and security compared to UUID v4, making it
898
- * ideal for distributed systems and user-facing identifiers.
899
- *
900
- * @returns A CUID2 identifier string
901
- * @example
902
- * ```typescript
903
- * const id = createId(); // "ckx5f8h3z0000qzrmn831i7rn"
904
- * ```
905
- */
906
- var createId$1 = createId;
907
- /**
908
- * Converts a string to a URL-friendly slug
909
- *
910
- * Handles international characters, removes special characters, and replaces
911
- * spaces with hyphens. Ampersands are converted to "-38-" for uniqueness.
912
- *
913
- * @param str - The string to convert to a slug
914
- * @returns A URL-friendly slug string
915
- * @example
916
- * ```typescript
917
- * makeSlug("My Example Title & Co."); // "my-example-title-38-co"
918
- * makeSlug("Café España"); // "cafe-espana"
919
- * ```
920
- */
921
- var makeSlug = (str) => {
922
- const from = "àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìıİłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż+·/_,:;";
923
- const to = "aaaaaaaaaacccddeeeeeeeegghiiiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz--------------";
924
- const textToCompare = new RegExp(from.split("").join("|").replace(/\+/g, "\\+"), "g");
925
- return str.toString().toLowerCase().replace("&", "-38-").replace(/\s+/g, "-").replace(textToCompare, (c) => to.charAt(from.indexOf(c))).replace(/[&.]/g, "-").replace(/[^\w-º+]+/g, "").replace(/--+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
926
- };
927
- /**
928
- * Extracts the filename from a URL's pathname
929
- *
930
- * Returns the last segment of the URL path. If no filename is found,
931
- * defaults to 'index.html'.
932
- *
933
- * @param url - The URL to extract filename from
934
- * @returns The filename from the URL
935
- * @throws {TypeError} When URL is invalid
936
- * @example
937
- * ```typescript
938
- * urlFilename("https://example.com/path/file.pdf"); // "file.pdf"
939
- * urlFilename("https://example.com/path/"); // "index.html"
940
- * ```
941
- */
942
- var urlFilename = (url) => {
943
- const pathSegments = new URL(url).pathname.split("/");
944
- return pathSegments[pathSegments.length - 1] || "index.html";
945
- };
946
- /**
947
- * Converts a URL to a file path by joining hostname and pathname
948
- *
949
- * Creates a file system compatible path from a URL by combining the hostname
950
- * with the pathname segments, useful for creating local file structures.
951
- *
952
- * @param url - The URL to convert to a path
953
- * @returns A file path string with hostname and path segments
954
- * @throws {TypeError} When URL is invalid
955
- * @example
956
- * ```typescript
957
- * urlPath("https://example.com/path/to/resource"); // "example.com/path/to/resource"
958
- * ```
959
- */
960
- var urlPath = (url) => {
961
- const parsedUrl = new URL(url);
962
- return [parsedUrl.hostname, ...parsedUrl.pathname.split("/").filter(Boolean)].join("/");
963
- };
964
- /**
965
- * Creates a Promise that resolves after a specified duration
966
- *
967
- * Useful for adding delays in async functions or rate limiting operations.
968
- *
969
- * @param duration - Time to wait in milliseconds
970
- * @returns Promise that resolves after the specified duration
971
- * @example
972
- * ```typescript
973
- * await sleep(1000); // Wait 1 second
974
- * console.log('1 second has passed');
975
- * ```
976
- */
977
- var sleep = (duration) => {
978
- return new Promise((resolve) => {
979
- setTimeout(resolve, duration);
980
- });
981
- };
982
- /**
983
- * Repeatedly calls a function until it returns a defined value or times out
984
- *
985
- * Polls an async function at regular intervals until it returns a defined value
986
- * or the timeout is reached. Useful for waiting for conditions to be met.
987
- *
988
- * @param it - Async function to poll
989
- * @param options - Configuration options
990
- * @param options.timeout - Maximum time to wait in milliseconds (0 = no timeout)
991
- * @param options.delay - Time between polling attempts in milliseconds
992
- * @returns Promise that resolves with the function result or rejects on timeout
993
- * @throws {TimeoutError} When timeout is reached before function returns defined value
994
- * @example
995
- * ```typescript
996
- * // Wait for a file to exist
997
- * const fileExists = await waitFor(
998
- * async () => {
999
- * try {
1000
- * await fs.access('/path/to/file');
1001
- * return true;
1002
- * } catch {
1003
- * return undefined; // Keep polling
1004
- * }
1005
- * },
1006
- * { timeout: 10000, delay: 500 }
1007
- * );
1008
- * ```
1009
- */
1010
- function waitFor(it, { timeout = 0, delay = 1e3 } = {}) {
1011
- return new Promise((resolve, reject) => {
1012
- const beginTime = Date.now();
1013
- (async function waitATick() {
1014
- try {
1015
- const result = await it();
1016
- if (typeof result !== "undefined") return resolve(result);
1017
- if (timeout > 0) {
1018
- if (Date.now() > beginTime + timeout) return reject(new TimeoutError("Function call timed out", {
1019
- timeout,
1020
- delay,
1021
- elapsedTime: Date.now() - beginTime
1022
- }));
1023
- }
1024
- setTimeout(waitATick, delay);
1025
- } catch (error) {
1026
- reject(error);
1027
- }
1028
- })();
1029
- });
1030
- }
1031
- /**
1032
- * Type guard to check if a value is an array
1033
- *
1034
- * @param obj - Value to check
1035
- * @returns True if value is an array, with TypeScript type narrowing
1036
- * @example
1037
- * ```typescript
1038
- * if (isArray(data)) {
1039
- * // TypeScript knows data is unknown[]
1040
- * data.forEach(item => console.log(item));
1041
- * }
1042
- * ```
1043
- */
1044
- var isArray = (obj) => {
1045
- return Array.isArray(obj);
1046
- };
1047
- /**
1048
- * Type guard to check if a value is a plain object
1049
- *
1050
- * Checks for objects that are not null, arrays, or other non-plain object types.
1051
- *
1052
- * @param obj - Value to check
1053
- * @returns True if value is a plain object, with TypeScript type narrowing
1054
- * @example
1055
- * ```typescript
1056
- * if (isPlainObject(data)) {
1057
- * // TypeScript knows data is Record<string, unknown>
1058
- * Object.keys(data).forEach(key => console.log(key, data[key]));
1059
- * }
1060
- * ```
1061
- */
1062
- var isPlainObject = (obj) => {
1063
- return typeof obj === "object" && obj !== null && !Array.isArray(obj);
1064
- };
1065
- /**
1066
- * Checks if a string is a valid URL
1067
- *
1068
- * Uses the URL constructor to validate the string format. Returns false
1069
- * for any string that cannot be parsed as a valid URL.
1070
- *
1071
- * @param url - String to validate as URL
1072
- * @returns True if string is a valid URL
1073
- * @example
1074
- * ```typescript
1075
- * isUrl("https://example.com"); // true
1076
- * isUrl("not-a-url"); // false
1077
- * ```
1078
- */
1079
- var isUrl = (url) => {
1080
- try {
1081
- new URL(url);
1082
- return true;
1083
- } catch {
1084
- return false;
1085
- }
1086
- };
1087
- /**
1088
- * Converts a string to camelCase
1089
- *
1090
- * Handles kebab-case, snake_case, and space-separated strings.
1091
- * Removes special characters and ensures proper camelCase formatting.
1092
- *
1093
- * @param str - String to convert
1094
- * @returns camelCase formatted string
1095
- * @example
1096
- * ```typescript
1097
- * camelCase("hello-world"); // "helloWorld"
1098
- * camelCase("snake_case_string"); // "snakeCaseString"
1099
- * camelCase("Some Title"); // "someTitle"
1100
- * ```
1101
- */
1102
- var camelCase = (str) => {
1103
- return str.toLowerCase().replace(/[-_]+/g, " ").replace(/[^\w\s]/g, "").replace(/\s(.)/g, (_, char) => char.toUpperCase()).replace(/\s/g, "").replace(/^(.)/, (_, char) => char.toLowerCase());
1104
- };
1105
- /**
1106
- * Converts a string to snake_case
1107
- *
1108
- * Handles camelCase, kebab-case, and space-separated strings.
1109
- * Converts to lowercase with underscore separators.
1110
- *
1111
- * @param str - String to convert
1112
- * @returns snake_case formatted string
1113
- * @example
1114
- * ```typescript
1115
- * snakeCase("helloWorld"); // "hello_world"
1116
- * snakeCase("kebab-case-string"); // "kebab_case_string"
1117
- * snakeCase("Some Title"); // "some_title"
1118
- * ```
1119
- */
1120
- var snakeCase = (str) => {
1121
- return str.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "").replace(/[-\s]+/g, "_");
1122
- };
1123
- /**
1124
- * Recursively converts all object keys to camelCase
1125
- *
1126
- * Deeply traverses an object or array and converts all keys to camelCase.
1127
- * Preserves the structure and values, only transforming key names.
1128
- *
1129
- * @param obj - Object or array to transform
1130
- * @returns New object/array with camelCase keys
1131
- * @example
1132
- * ```typescript
1133
- * keysToCamel({
1134
- * user_name: "john",
1135
- * user_details: { first_name: "John" }
1136
- * }); // { userName: "john", userDetails: { firstName: "John" } }
1137
- * ```
1138
- */
1139
- var keysToCamel = (obj) => {
1140
- if (isPlainObject(obj)) {
1141
- const n = {};
1142
- Object.keys(obj).forEach((k) => {
1143
- n[camelCase(k)] = keysToCamel(obj[k]);
1144
- });
1145
- return n;
1146
- }
1147
- if (isArray(obj)) return obj.map((i) => keysToCamel(i));
1148
- return obj;
1149
- };
1150
- /**
1151
- * Recursively converts all object keys to snake_case
1152
- *
1153
- * Deeply traverses an object or array and converts all keys to snake_case.
1154
- * Preserves the structure and values, only transforming key names.
1155
- *
1156
- * @param obj - Object or array to transform
1157
- * @returns New object/array with snake_case keys
1158
- * @example
1159
- * ```typescript
1160
- * keysToSnake({
1161
- * userName: "john",
1162
- * userDetails: { firstName: "John" }
1163
- * }); // { user_name: "john", user_details: { first_name: "John" } }
1164
- * ```
1165
- */
1166
- var keysToSnake = (obj) => {
1167
- if (isPlainObject(obj)) {
1168
- const n = {};
1169
- Object.keys(obj).forEach((k) => {
1170
- n[snakeCase(k)] = keysToSnake(obj[k]);
1171
- });
1172
- return n;
1173
- }
1174
- if (isArray(obj)) return obj.map((i) => keysToSnake(i));
1175
- return obj;
1176
- };
1177
- /**
1178
- * Converts a domain string to camelCase
1179
- *
1180
- * Convenience function that applies camelCase conversion to domain strings.
1181
- * Useful for converting API service names or domain identifiers.
1182
- *
1183
- * @param domain - Domain string to convert
1184
- * @returns camelCase formatted domain string
1185
- * @example
1186
- * ```typescript
1187
- * domainToCamel("api-service"); // "apiService"
1188
- * domainToCamel("user_management"); // "userManagement"
1189
- * ```
1190
- */
1191
- var domainToCamel = (domain) => camelCase(domain);
1192
- /**
1193
- * Creates a visual progress indicator by cycling through a sequence of characters
1194
- *
1195
- * Useful for creating animated progress indicators in CLI applications.
1196
- * Cycles through provided characters or defaults to dot sequences.
1197
- *
1198
- * @param tick - Current tick state (null to start)
1199
- * @param options - Configuration options
1200
- * @param options.chars - Array of characters to cycle through
1201
- * @returns Next character in the sequence
1202
- * @example
1203
- * ```typescript
1204
- * let tick = null;
1205
- * setInterval(() => {
1206
- * tick = logTicker(tick);
1207
- * process.stdout.write(`\rProcessing ${tick}`);
1208
- * }, 500);
1209
- * // Outputs: "Processing ." → "Processing .." → "Processing ..."
1210
- * ```
1211
- */
1212
- var logTicker = (tick, options = {}) => {
1213
- const { chars = [
1214
- ".",
1215
- "..",
1216
- "..."
1217
- ] } = options;
1218
- if (tick) {
1219
- const index = chars.indexOf(tick);
1220
- return index + 1 >= chars.length ? chars[0] : chars[index + 1];
1221
- }
1222
- return chars[0];
1223
- };
1224
- /**
1225
- * Parses an Amazon date string format (YYYYMMDDTHHMMSSZ) to a Date object
1226
- *
1227
- * Specifically handles the compact date format used by Amazon AWS services.
1228
- * Validates the format and throws detailed errors for invalid inputs.
1229
- *
1230
- * @param dateStr - Amazon date string in format YYYYMMDDTHHMMSSZ
1231
- * @returns Parsed Date object
1232
- * @throws {ParsingError} When date string format is invalid
1233
- * @example
1234
- * ```typescript
1235
- * parseAmazonDateString('20220223T215409Z');
1236
- * // Returns: Date object for February 23, 2022, 21:54:09 UTC
1237
- * ```
1238
- */
1239
- var parseAmazonDateString = (dateStr) => {
1240
- const match = dateStr.match(/^([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2})([A-Z0-9]+)/);
1241
- if (!match) throw new ParsingError("Could not parse Amazon date string", {
1242
- dateString: dateStr,
1243
- expectedFormat: "YYYYMMDDTHHMMSSZ"
1244
- });
1245
- const [matched, year, month, day, hour, minutes, seconds, timezone] = match;
1246
- if (matched !== dateStr) throw new ParsingError("Invalid Amazon date string format", {
1247
- dateString: dateStr,
1248
- matched,
1249
- expectedFormat: "YYYYMMDDTHHMMSSZ"
1250
- });
1251
- return /* @__PURE__ */ new Date(`${year}-${month}-${day}T${hour}:${minutes}:${seconds}${timezone}`);
1252
- };
1253
- /**
1254
- * Extracts and parses a date from a string
1255
- *
1256
- * Intelligently extracts dates from filenames or text strings by looking for
1257
- * common date patterns. Supports multiple formats including:
1258
- * - ISO dates (2023-01-15, 2023/01/15)
1259
- * - US dates (01/15/2023, 01-15-2023)
1260
- * - Natural language (January 15, 2023, Oct 14 2025)
1261
- * - Filenames with dates (Report_January_15_2023.pdf)
1262
- *
1263
- * @param str - String containing date information (filename, title, or text)
1264
- * @returns Parsed Date object or null if no valid date found
1265
- * @example
1266
- * ```typescript
1267
- * dateInString("Report_January_15_2023.pdf"); // Date(2023, 0, 15)
1268
- * dateInString("Regular Council Meeting October 14, 2025"); // Date(2025, 9, 14)
1269
- * dateInString("financial-report-dec-2023.pdf"); // Date(2023, 11, 1)
1270
- * dateInString("2023-01-15"); // Date(2023, 0, 15)
1271
- * dateInString("no-date-here.pdf"); // null
1272
- * ```
1273
- */
1274
- var dateInString = (str) => {
1275
- const cleanStr = str.toLowerCase();
1276
- const underscoreMatch = str.match(/(\d{4})_(\d{1,2})_(\d{1,2})/);
1277
- if (underscoreMatch) {
1278
- const [, year, month, day] = underscoreMatch;
1279
- const date = new Date(Number.parseInt(year, 10), Number.parseInt(month, 10) - 1, Number.parseInt(day, 10));
1280
- if (!Number.isNaN(date.getTime())) return date;
1281
- }
1282
- const dotMatch = str.match(/(\d{1,2})\.(\d{1,2})\.(\d{4})/);
1283
- if (dotMatch) {
1284
- const [, month, day, year] = dotMatch;
1285
- const date = new Date(Number.parseInt(year, 10), Number.parseInt(month, 10) - 1, Number.parseInt(day, 10));
1286
- if (!Number.isNaN(date.getTime())) return date;
1287
- }
1288
- const isoMatch = cleanStr.match(/(\d{4})[-/](\d{1,2})[-/](\d{1,2})/);
1289
- if (isoMatch) {
1290
- const [, year, month, day] = isoMatch;
1291
- const date = new Date(Number.parseInt(year, 10), Number.parseInt(month, 10) - 1, Number.parseInt(day, 10));
1292
- if (!Number.isNaN(date.getTime())) return date;
1293
- }
1294
- const usMatch = cleanStr.match(/(\d{1,2})[-/](\d{1,2})[-/](\d{4})/);
1295
- if (usMatch) {
1296
- const [, month, day, year] = usMatch;
1297
- const date = new Date(Number.parseInt(year, 10), Number.parseInt(month, 10) - 1, Number.parseInt(day, 10));
1298
- if (!Number.isNaN(date.getTime())) return date;
1299
- }
1300
- const yearMatch = cleanStr.match(/20\d{2}/);
1301
- if (!yearMatch) return null;
1302
- const year = Number.parseInt(yearMatch[0], 10);
1303
- const monthPatterns = {
1304
- january: 1,
1305
- jan: 1,
1306
- february: 2,
1307
- feb: 2,
1308
- march: 3,
1309
- mar: 3,
1310
- april: 4,
1311
- apr: 4,
1312
- may: 5,
1313
- june: 6,
1314
- jun: 6,
1315
- july: 7,
1316
- jul: 7,
1317
- august: 8,
1318
- aug: 8,
1319
- september: 9,
1320
- sep: 9,
1321
- sept: 9,
1322
- october: 10,
1323
- oct: 10,
1324
- november: 11,
1325
- nov: 11,
1326
- december: 12,
1327
- dec: 12
1328
- };
1329
- let foundMonth = null;
1330
- let monthStart = -1;
1331
- let monthName = "";
1332
- for (const [name, monthNum] of Object.entries(monthPatterns)) {
1333
- const monthIndex = cleanStr.indexOf(name);
1334
- if (monthIndex !== -1) {
1335
- foundMonth = monthNum;
1336
- monthStart = monthIndex;
1337
- monthName = name;
1338
- break;
1339
- }
1340
- }
1341
- if (!foundMonth) return null;
1342
- const yearIndex = cleanStr.indexOf(yearMatch[0]);
1343
- const beforeMonth = cleanStr.substring(Math.max(0, monthStart - 15), monthStart);
1344
- const afterMonth = cleanStr.substring(monthStart + monthName.length, Math.min(cleanStr.length, monthStart + monthName.length + 15));
1345
- const beforeYear = cleanStr.substring(Math.max(0, yearIndex - 15), yearIndex);
1346
- const afterYear = cleanStr.substring(yearIndex + 4, Math.min(cleanStr.length, yearIndex + 19));
1347
- const dayMatch = beforeMonth.match(/(?<!\d)(\d{1,2})\s*$/) || afterMonth.match(/^\s*(\d{1,2})(?!\d)/) || beforeYear.match(/(?<!\d)(\d{1,2})\s*$/) || afterYear.match(/^\s*(\d{1,2})(?!\d)/) || afterMonth.match(/[^\d](\d{1,2})(?!\d)/);
1348
- const day = dayMatch ? Number.parseInt(dayMatch[1], 10) : 1;
1349
- if (day < 1 || day > 31) return null;
1350
- const date = new Date(year, foundMonth - 1, day);
1351
- return !Number.isNaN(date.getTime()) ? date : null;
1352
- };
1353
- /**
1354
- * Formats a date string into a human-readable format using the system locale
1355
- *
1356
- * Uses the Intl.DateTimeFormat API to create localized, human-readable date strings.
1357
- * Automatically adapts to the user's system locale settings.
1358
- *
1359
- * @param dateString - ISO date string or any valid date string
1360
- * @returns Human-readable date string in system locale
1361
- * @example
1362
- * ```typescript
1363
- * prettyDate("2023-01-15T12:00:00Z"); // "January 15, 2023" (in English locale)
1364
- * ```
1365
- */
1366
- var prettyDate = (dateString) => {
1367
- const date = new Date(dateString);
1368
- return new Intl.DateTimeFormat(void 0, {
1369
- year: "numeric",
1370
- month: "long",
1371
- day: "numeric"
1372
- }).format(date);
1373
- };
1374
- /**
1375
- * String pluralization utilities using the pluralize library
1376
- *
1377
- * Re-exports the pluralize library function for word pluralization.
1378
- * Handles English pluralization rules including irregular forms.
1379
- *
1380
- * @example
1381
- * ```typescript
1382
- * pluralizeWord("cat"); // "cats"
1383
- * pluralizeWord("mouse"); // "mice"
1384
- * singularize("cats"); // "cat"
1385
- * isPlural("cats"); // true
1386
- * isSingular("cat"); // true
1387
- * ```
1388
- */
1389
- var pluralizeWord = pluralize;
1390
- var singularize = pluralize.singular;
1391
- var isPlural = pluralize.isPlural;
1392
- var isSingular = pluralize.isSingular;
1393
- /**
1394
- * Enhanced date utilities using date-fns library
1395
- *
1396
- * Re-exports commonly used date-fns functions for date manipulation and formatting.
1397
- * Provides more reliable date handling than native Date methods.
1398
- *
1399
- * @param date - Date object or ISO string to format
1400
- * @param formatStr - Format string (defaults to 'yyyy-MM-dd')
1401
- * @returns Formatted date string
1402
- * @example
1403
- * ```typescript
1404
- * formatDate(new Date(), 'yyyy-MM-dd'); // "2023-01-15"
1405
- * formatDate(new Date(), 'MM/dd/yyyy'); // "01/15/2023"
1406
- * parseDate('2023-01-15'); // Date object
1407
- * isValidDate(new Date()); // true
1408
- * addInterval(new Date(), { days: 7 }); // Date 7 days from now
1409
- * ```
1410
- */
1411
- var formatDate = (date, formatStr = "yyyy-MM-dd") => {
1412
- return format(typeof date === "string" ? new Date(date) : date, formatStr);
1413
- };
1414
- /**
1415
- * Parses a date string into a Date object
1416
- *
1417
- * When a format string is provided, uses date-fns `parse` with that format.
1418
- * Otherwise falls back to `parseISO` for ISO 8601 strings.
1419
- *
1420
- * @param dateStr - The date string to parse
1421
- * @param formatStr - Optional format pattern (e.g., 'MM/dd/yyyy', 'dd-MMM-yyyy')
1422
- * @returns Parsed Date object
1423
- * @example
1424
- * ```typescript
1425
- * parseDate('2023-01-15'); // ISO parse
1426
- * parseDate('01/15/2023', 'MM/dd/yyyy'); // Custom format parse
1427
- * ```
1428
- */
1429
- var parseDate = (dateStr, formatStr) => {
1430
- if (formatStr) return parse(dateStr, formatStr, /* @__PURE__ */ new Date());
1431
- return parseISO(dateStr);
1432
- };
1433
- var isValidDate = isValid;
1434
- var addInterval = add;
1435
- /**
1436
- * Gets a temporary directory path (cross-platform)
1437
- *
1438
- * Creates a platform-appropriate temporary directory path under the .have-sdk namespace.
1439
- * Uses environment variables in Node.js or falls back to /tmp.
1440
- *
1441
- * @param subfolder - Optional subfolder name within the temp directory
1442
- * @returns Cross-platform temporary directory path
1443
- * @example
1444
- * ```typescript
1445
- * getTempDirectory(); // "/tmp/.have-sdk" (Unix) or equivalent
1446
- * getTempDirectory("cache"); // "/tmp/.have-sdk/cache"
1447
- * ```
1448
- */
1449
- var getTempDirectory = (subfolder) => {
1450
- const environment = typeof process !== "undefined" ? process.env : void 0;
1451
- const basePath = `${environment?.TMPDIR || environment?.TMP || environment?.TEMP || "/tmp"}/.have-sdk`;
1452
- return subfolder ? `${basePath}/${subfolder}` : basePath;
1453
- };
1454
- //#endregion
1455
- export { ApiError as A, enableLogging as B, prettyDate as C, urlFilename as D, snakeCase as E, NetworkError as F, extractAllCodeBlocks as G, setLogger as H, ParsingError as I, extractJSON as J, extractCodeBlock as K, TimeoutError as L, DatabaseError as M, ErrorCode as N, urlPath as O, FileError as P, toScreamingSnakeCase as Q, ValidationError as R, pluralizeWord as S, sleep as T, isSafeCode as U, getLogger as V, validateCode as W, loadEnvConfig as X, convertType as Y, toCamelCase as Z, logTicker as _, domainToCamel as a, parseAmazonDateString as b, isArray as c, isPlural as d, isSingular as f, keysToSnake as g, keysToCamel as h, dateInString as i, BaseError as j, waitFor as k, isCuid as l, isValidDate as m, camelCase as n, formatDate as o, isUrl as p, extractFunctionDefinition as q, createId$1 as r, getTempDirectory as s, addInterval as t, isPlainObject as u, makeId as v, singularize as w, parseDate as x, makeSlug as y, disableLogging as z };
1456
-
1457
- //# sourceMappingURL=universal-CDrOobmp.js.map