@geenius/tools 0.1.0 → 0.3.0
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.
- package/package.json +62 -3
- package/packages/convex/shared/README.md +1 -1
- package/packages/devtools/dist/index.d.ts +204 -0
- package/packages/devtools/dist/index.js +186 -0
- package/packages/devtools/dist/index.js.map +1 -0
- package/packages/devtools/react/README.md +1 -1
- package/packages/devtools/solidjs/README.md +1 -1
- package/packages/devtools/solidjs/dist/index.js +1830 -0
- package/packages/devtools/solidjs/dist/index.js.map +1 -0
- package/packages/env/dist/index.d.ts +151 -0
- package/packages/env/dist/index.js +93 -0
- package/packages/env/dist/index.js.map +1 -0
- package/packages/errors/dist/index.d.ts +177 -0
- package/packages/errors/dist/index.js +187 -0
- package/packages/errors/dist/index.js.map +1 -0
- package/packages/errors/react/README.md +1 -1
- package/packages/errors/solidjs/README.md +1 -1
- package/packages/logger/dist/index.d.ts +171 -0
- package/packages/logger/dist/index.js +216 -0
- package/packages/logger/dist/index.js.map +1 -0
- package/packages/logger/react/README.md +1 -1
- package/packages/logger/solidjs/README.md +1 -1
- package/packages/perf/dist/index.d.ts +168 -0
- package/packages/perf/dist/index.js +265 -0
- package/packages/perf/dist/index.js.map +1 -0
- package/packages/perf/react/README.md +1 -1
- package/packages/perf/solidjs/README.md +1 -1
- package/packages/shared/dist/index.d.ts +253 -0
- package/packages/shared/dist/index.js +278 -0
- package/packages/shared/dist/index.js.map +1 -0
- package/.changeset/config.json +0 -11
- package/.env.example +0 -2
- package/.github/CODEOWNERS +0 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -16
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -11
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -10
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/ci.yml +0 -23
- package/.github/workflows/release.yml +0 -29
- package/.node-version +0 -1
- package/.nvmrc +0 -1
- package/.prettierrc +0 -7
- package/.project/ACCOUNT.yaml +0 -4
- package/.project/IDEAS.yaml +0 -7
- package/.project/PROJECT.yaml +0 -11
- package/.project/ROADMAP.yaml +0 -15
- package/CODE_OF_CONDUCT.md +0 -26
- package/CONTRIBUTING.md +0 -69
- package/SECURITY.md +0 -18
- package/SUPPORT.md +0 -14
- package/packages/convex/shared/package.json +0 -42
- package/packages/convex/shared/src/audit/index.ts +0 -5
- package/packages/convex/shared/src/audit/presets.ts +0 -165
- package/packages/convex/shared/src/audit/schema.ts +0 -85
- package/packages/convex/shared/src/audit/write.ts +0 -102
- package/packages/convex/shared/src/extract.ts +0 -75
- package/packages/convex/shared/src/index.ts +0 -41
- package/packages/convex/shared/src/messages.ts +0 -45
- package/packages/convex/shared/src/security.ts +0 -112
- package/packages/convex/shared/src/throw.ts +0 -184
- package/packages/convex/shared/src/types.ts +0 -57
- package/packages/convex/shared/src/utils.ts +0 -58
- package/packages/convex/shared/tsconfig.json +0 -28
- package/packages/convex/shared/tsup.config.ts +0 -12
- package/packages/devtools/package.json +0 -27
- package/packages/devtools/react/package.json +0 -53
- package/packages/devtools/react/src/components/DesignPreview.tsx +0 -59
- package/packages/devtools/react/src/components/DesignSwitcherDropdown.tsx +0 -99
- package/packages/devtools/react/src/components/DevSidebar.tsx +0 -247
- package/packages/devtools/react/src/components/DevToolbar.tsx +0 -242
- package/packages/devtools/react/src/components/GitHubIssueDialog.tsx +0 -402
- package/packages/devtools/react/src/components/InspectorOverlay.tsx +0 -312
- package/packages/devtools/react/src/components/PageLoadWaterfall.tsx +0 -144
- package/packages/devtools/react/src/components/PerformancePanel.tsx +0 -330
- package/packages/devtools/react/src/context/DevModeContext.tsx +0 -226
- package/packages/devtools/react/src/context/PerformanceContext.tsx +0 -143
- package/packages/devtools/react/src/data/designs.ts +0 -13
- package/packages/devtools/react/src/hooks/useGitHubLabels.ts +0 -47
- package/packages/devtools/react/src/hooks/useVirtualList.ts +0 -124
- package/packages/devtools/react/src/index.ts +0 -77
- package/packages/devtools/react/src/panels/ConvexSpy.tsx +0 -130
- package/packages/devtools/react/src/panels/DatabaseSeeder.tsx +0 -116
- package/packages/devtools/react/src/panels/DevModePhase2.tsx +0 -191
- package/packages/devtools/react/src/panels/DevModePhase3.tsx +0 -234
- package/packages/devtools/react/src/panels/FeatureFlagsToggle.tsx +0 -104
- package/packages/devtools/react/src/panels/QuickRouteJump.tsx +0 -152
- package/packages/devtools/react/src/services/github-service.ts +0 -247
- package/packages/devtools/react/tsconfig.json +0 -31
- package/packages/devtools/react/tsup.config.ts +0 -18
- package/packages/devtools/solidjs/package.json +0 -49
- package/packages/devtools/solidjs/src/components/DesignPreview.tsx +0 -51
- package/packages/devtools/solidjs/src/components/DesignSwitcherDropdown.tsx +0 -95
- package/packages/devtools/solidjs/src/components/DevSidebar.tsx +0 -247
- package/packages/devtools/solidjs/src/components/DevToolbar.tsx +0 -242
- package/packages/devtools/solidjs/src/components/GitHubIssueDialog.tsx +0 -400
- package/packages/devtools/solidjs/src/components/InspectorOverlay.tsx +0 -311
- package/packages/devtools/solidjs/src/components/PageLoadWaterfall.tsx +0 -144
- package/packages/devtools/solidjs/src/components/PerformancePanel.tsx +0 -330
- package/packages/devtools/solidjs/src/context/DevModeContext.tsx +0 -216
- package/packages/devtools/solidjs/src/context/PerformanceContext.tsx +0 -135
- package/packages/devtools/solidjs/src/data/designs.ts +0 -13
- package/packages/devtools/solidjs/src/hooks/createGitHubLabels.ts +0 -47
- package/packages/devtools/solidjs/src/index.ts +0 -64
- package/packages/devtools/solidjs/src/services/github-service.ts +0 -247
- package/packages/devtools/solidjs/tsconfig.json +0 -21
- package/packages/devtools/src/index.ts +0 -377
- package/packages/devtools/tsup.config.ts +0 -12
- package/packages/env/package.json +0 -30
- package/packages/env/src/index.ts +0 -264
- package/packages/env/tsup.config.ts +0 -12
- package/packages/errors/package.json +0 -27
- package/packages/errors/react/package.json +0 -72
- package/packages/errors/react/src/analytics.ts +0 -16
- package/packages/errors/react/src/components/ErrorBoundary.tsx +0 -248
- package/packages/errors/react/src/components/ErrorDisplay.tsx +0 -328
- package/packages/errors/react/src/components/ValidationErrors.tsx +0 -102
- package/packages/errors/react/src/config.ts +0 -199
- package/packages/errors/react/src/constants.ts +0 -74
- package/packages/errors/react/src/hooks/useErrorBoundary.ts +0 -92
- package/packages/errors/react/src/hooks/useErrorHandler.ts +0 -87
- package/packages/errors/react/src/index.ts +0 -96
- package/packages/errors/react/src/types.ts +0 -102
- package/packages/errors/react/src/utils/errorMessages.ts +0 -35
- package/packages/errors/react/src/utils/errorPolicy.ts +0 -139
- package/packages/errors/react/src/utils/extractAppError.ts +0 -174
- package/packages/errors/react/src/utils/formatError.ts +0 -112
- package/packages/errors/react/tsconfig.json +0 -25
- package/packages/errors/react/tsup.config.ts +0 -24
- package/packages/errors/solidjs/package.json +0 -46
- package/packages/errors/solidjs/src/components/ErrorDisplay.tsx +0 -179
- package/packages/errors/solidjs/src/config.ts +0 -98
- package/packages/errors/solidjs/src/hooks/createErrorHandler.ts +0 -107
- package/packages/errors/solidjs/src/index.ts +0 -61
- package/packages/errors/solidjs/src/types.ts +0 -34
- package/packages/errors/solidjs/src/utils/errorPolicy.ts +0 -56
- package/packages/errors/solidjs/src/utils/extractAppError.ts +0 -94
- package/packages/errors/solidjs/src/utils/formatError.ts +0 -33
- package/packages/errors/solidjs/tsconfig.json +0 -26
- package/packages/errors/solidjs/tsup.config.ts +0 -21
- package/packages/errors/src/index.ts +0 -320
- package/packages/errors/tsup.config.ts +0 -12
- package/packages/logger/package.json +0 -27
- package/packages/logger/react/package.json +0 -46
- package/packages/logger/react/src/index.ts +0 -4
- package/packages/logger/react/src/useMetrics.ts +0 -42
- package/packages/logger/react/src/usePerformanceLog.ts +0 -61
- package/packages/logger/react/tsconfig.json +0 -31
- package/packages/logger/react/tsup.config.ts +0 -12
- package/packages/logger/solidjs/package.json +0 -45
- package/packages/logger/solidjs/src/createMetrics.ts +0 -37
- package/packages/logger/solidjs/src/createPerformanceLog.ts +0 -58
- package/packages/logger/solidjs/src/index.ts +0 -4
- package/packages/logger/solidjs/tsconfig.json +0 -32
- package/packages/logger/solidjs/tsup.config.ts +0 -12
- package/packages/logger/src/index.ts +0 -363
- package/packages/logger/tsup.config.ts +0 -12
- package/packages/perf/package.json +0 -27
- package/packages/perf/react/package.json +0 -59
- package/packages/perf/react/src/components/PerformanceDashboard.tsx +0 -257
- package/packages/perf/react/src/hooks/useMonitoredQuery.ts +0 -89
- package/packages/perf/react/src/hooks/usePerformanceMetrics.ts +0 -78
- package/packages/perf/react/src/index.ts +0 -33
- package/packages/perf/react/src/services/PerformanceMonitor.ts +0 -313
- package/packages/perf/react/src/types.ts +0 -77
- package/packages/perf/react/tsconfig.json +0 -25
- package/packages/perf/react/tsup.config.ts +0 -19
- package/packages/perf/solidjs/package.json +0 -41
- package/packages/perf/solidjs/src/components/PerformanceDashboard.tsx +0 -207
- package/packages/perf/solidjs/src/hooks/createPerformanceMetrics.ts +0 -73
- package/packages/perf/solidjs/src/index.ts +0 -31
- package/packages/perf/solidjs/src/services/PerformanceMonitor.ts +0 -134
- package/packages/perf/solidjs/src/types.ts +0 -78
- package/packages/perf/solidjs/tsconfig.json +0 -26
- package/packages/perf/solidjs/tsup.config.ts +0 -14
- package/packages/perf/src/index.ts +0 -410
- package/packages/perf/tsup.config.ts +0 -12
- package/pnpm-workspace.yaml +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @geenius/tools-perf — Performance monitoring\n *\n * Provides utilities for measuring and tracking performance metrics.\n * Supports timing, memory profiling, and metric collection.\n */\n\n/**\n * Performance metric entry\n */\nexport interface PerfMetric {\n /** Metric name */\n name: string\n /** Duration in milliseconds */\n duration: number\n /** When metric was recorded */\n timestamp: Date\n /** Metric tags */\n tags?: Record<string, string>\n /** Additional metadata */\n metadata?: Record<string, unknown>\n}\n\n/**\n * Performance monitor callback\n */\nexport type PerfCallback = (metric: PerfMetric) => void | Promise<void>\n\n/**\n * Simple timer for measuring duration\n *\n * @example\n * ```ts\n * const timer = new Timer()\n * // ... do work ...\n * console.log(timer.elapsed()) // duration in ms\n * ```\n */\nexport class Timer {\n private startTime: number\n\n constructor() {\n this.startTime = this.now()\n }\n\n /**\n * Gets elapsed time in milliseconds\n */\n elapsed(): number {\n return this.now() - this.startTime\n }\n\n /**\n * Resets timer\n */\n reset() {\n this.startTime = this.now()\n }\n\n /**\n * Gets current time in milliseconds\n */\n private now(): number {\n if (typeof performance !== 'undefined' && performance.now) {\n return performance.now()\n }\n return Date.now()\n }\n}\n\n/**\n * Performance tracker for named metrics\n *\n * @example\n * ```ts\n * const perf = new PerfTracker()\n * perf.mark('fetch-start')\n * // ... fetch data ...\n * perf.measure('api-call', 'fetch-start')\n * ```\n */\nexport class PerfTracker {\n private marks: Map<string, number> = new Map()\n private metrics: PerfMetric[] = []\n private callbacks: PerfCallback[] = []\n\n /**\n * Records a performance mark at current time\n */\n mark(name: string, tags?: Record<string, string>) {\n const now = typeof performance !== 'undefined' && performance.now\n ? performance.now()\n : Date.now()\n\n this.marks.set(name, now)\n }\n\n /**\n * Measures duration from mark to now\n */\n measure(\n name: string,\n startMark: string,\n endMark?: string,\n metadata?: Record<string, unknown>\n ): number {\n const startTime = this.marks.get(startMark)\n if (startTime === undefined) {\n console.warn(`Mark \"${startMark}\" not found`)\n return 0\n }\n\n let endTime: number\n if (endMark) {\n endTime = this.marks.get(endMark) ?? this.now()\n } else {\n endTime = this.now()\n }\n\n const duration = endTime - startTime\n\n const metric: PerfMetric = {\n name,\n duration,\n timestamp: new Date(),\n metadata,\n }\n\n this.metrics.push(metric)\n this.emit(metric)\n\n return duration\n }\n\n /**\n * Times a function execution\n *\n * @example\n * ```ts\n * const duration = await perf.time('fetch', async () => {\n * return fetch('/api/data')\n * })\n * ```\n */\n async time<T>(\n name: string,\n fn: () => T | Promise<T>,\n metadata?: Record<string, unknown>\n ): Promise<{ duration: number; result: T }> {\n const timer = new Timer()\n\n try {\n const result = await Promise.resolve(fn())\n const duration = timer.elapsed()\n\n const metric: PerfMetric = {\n name,\n duration,\n timestamp: new Date(),\n metadata,\n }\n\n this.metrics.push(metric)\n this.emit(metric)\n\n return { duration, result }\n } catch (error) {\n const duration = timer.elapsed()\n const metric: PerfMetric = {\n name,\n duration,\n timestamp: new Date(),\n metadata: {\n ...metadata,\n error: error instanceof Error ? error.message : String(error),\n },\n }\n\n this.metrics.push(metric)\n this.emit(metric)\n\n throw error\n }\n }\n\n /**\n * Times a sync function execution\n */\n timeSync<T>(\n name: string,\n fn: () => T,\n metadata?: Record<string, unknown>\n ): { duration: number; result: T } {\n const timer = new Timer()\n\n try {\n const result = fn()\n const duration = timer.elapsed()\n\n const metric: PerfMetric = {\n name,\n duration,\n timestamp: new Date(),\n metadata,\n }\n\n this.metrics.push(metric)\n this.emit(metric)\n\n return { duration, result }\n } catch (error) {\n const duration = timer.elapsed()\n const metric: PerfMetric = {\n name,\n duration,\n timestamp: new Date(),\n metadata: {\n ...metadata,\n error: error instanceof Error ? error.message : String(error),\n },\n }\n\n this.metrics.push(metric)\n this.emit(metric)\n\n throw error\n }\n }\n\n /**\n * Registers callback for metric events\n */\n on(callback: PerfCallback) {\n this.callbacks.push(callback)\n return () => {\n this.callbacks = this.callbacks.filter((cb) => cb !== callback)\n }\n }\n\n /**\n * Emits metric to registered callbacks\n */\n private emit(metric: PerfMetric) {\n for (const callback of this.callbacks) {\n try {\n void callback(metric)\n } catch {\n // Silently fail to prevent perf tracking from breaking app\n }\n }\n }\n\n /**\n * Gets all recorded metrics\n */\n getMetrics(): PerfMetric[] {\n return [...this.metrics]\n }\n\n /**\n * Gets metrics by name\n */\n getByName(name: string): PerfMetric[] {\n return this.metrics.filter((m) => m.name === name)\n }\n\n /**\n * Gets average duration for named metric\n */\n getAverage(name: string): number {\n const metrics = this.getByName(name)\n if (metrics.length === 0) return 0\n\n const total = metrics.reduce((sum, m) => sum + m.duration, 0)\n return total / metrics.length\n }\n\n /**\n * Clears all metrics\n */\n clear() {\n this.marks.clear()\n this.metrics = []\n }\n\n /**\n * Gets current time in ms\n */\n private now(): number {\n if (typeof performance !== 'undefined' && performance.now) {\n return performance.now()\n }\n return Date.now()\n }\n}\n\n/**\n * Creates a performance tracker instance\n *\n * @example\n * ```ts\n * const perf = createPerfTracker()\n * await perf.time('api-call', () => fetch('/api/data'))\n * ```\n */\nexport function createPerfTracker(): PerfTracker {\n return new PerfTracker()\n}\n\n/**\n * Measures memory usage (Node.js only)\n *\n * @returns Memory usage in bytes\n */\nexport function getMemoryUsage(): {\n heapUsed: number\n heapTotal: number\n external: number\n} {\n if (typeof process !== 'undefined' && process.memoryUsage) {\n const usage = process.memoryUsage()\n return {\n heapUsed: usage.heapUsed,\n heapTotal: usage.heapTotal,\n external: usage.external,\n }\n }\n\n return {\n heapUsed: 0,\n heapTotal: 0,\n external: 0,\n }\n}\n\n/**\n * Decorator for automatic function timing\n *\n * @example\n * ```ts\n * class DataService {\n * @Timed()\n * async fetchData() {\n * return fetch('/api/data')\n * }\n * }\n * ```\n */\nexport function Timed(name?: string): MethodDecorator {\n return function (target, prop, descriptor) {\n if (!descriptor || typeof descriptor.value !== 'function') {\n return descriptor\n }\n\n const originalFn = descriptor.value\n const metricName = name ?? String(prop)\n const tracker = createPerfTracker()\n\n ;(descriptor as any).value = async function (...args: any[]) {\n const { duration, result } = await tracker.time(metricName, () =>\n (originalFn as Function).apply(this, args)\n )\n return result\n }\n\n return descriptor\n }\n}\n\n/**\n * Debounce function with performance tracking\n */\nexport function debounce<T extends (...args: any[]) => any>(\n fn: T,\n wait: number,\n name?: string\n): T {\n let timeout: NodeJS.Timeout | null = null\n const tracker = createPerfTracker()\n\n return ((...args: any[]) => {\n if (timeout) {\n clearTimeout(timeout)\n }\n\n timeout = setTimeout(() => {\n void tracker.timeSync(name ?? fn.name, () => fn(...args))\n }, wait)\n }) as T\n}\n\n/**\n * Throttle function with performance tracking\n */\nexport function throttle<T extends (...args: any[]) => any>(\n fn: T,\n wait: number,\n name?: string\n): T {\n let last = 0\n const tracker = createPerfTracker()\n\n return ((...args: any[]) => {\n const now = Date.now()\n if (now - last >= wait) {\n last = now\n void tracker.timeSync(name ?? fn.name, () => fn(...args))\n }\n }) as T\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
# ✦ @geenius-
|
|
1
|
+
# ✦ @geenius/tools-perf-react\n\n> React performance monitoring — dashboard, metrics hooks, query tracking\n\n---\n\n## Overview\nBuilt with Steve Jobs-level minimalism and Jony Ive-level craftsmanship, this package is designed to deliver unparalleled developer experience (DX) and rock-solid performance.\n\n## Installation\n\n```bash\npnpm add @geenius/tools-perf-react\n```\n\n## Usage\n\n```typescript\nimport { init } from '@geenius/tools-perf-react';\n\n// Initialize the module with absolute precision\ninit({\n mode: 'premium',\n});\n```\n\n## Architecture\n- **Zero-config**: It just works.\n- **Strictly Typed**: Fully written in TypeScript for flawless IntelliSense.\n- **Framework Agnostic**: seamlessly integrates into the Geenius ecosystem.\n\n---\n\n*Designed by Antigravity HQ*\n
|
|
@@ -1 +1 @@
|
|
|
1
|
-
# ✦ @geenius-
|
|
1
|
+
# ✦ @geenius/tools-perf-solidjs\n\n> SolidJS performance monitoring — metrics signals & dashboard\n\n---\n\n## Overview\nBuilt with Steve Jobs-level minimalism and Jony Ive-level craftsmanship, this package is designed to deliver unparalleled developer experience (DX) and rock-solid performance.\n\n## Installation\n\n```bash\npnpm add @geenius/tools-perf-solidjs\n```\n\n## Usage\n\n```typescript\nimport { init } from '@geenius/tools-perf-solidjs';\n\n// Initialize the module with absolute precision\ninit({\n mode: 'premium',\n});\n```\n\n## Architecture\n- **Zero-config**: It just works.\n- **Strictly Typed**: Fully written in TypeScript for flawless IntelliSense.\n- **Framework Agnostic**: seamlessly integrates into the Geenius ecosystem.\n\n---\n\n*Designed by Antigravity HQ*\n
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { ClassValue } from 'clsx';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Merge CSS class names with Tailwind conflict resolution.
|
|
5
|
+
* Handles strings, objects, arrays, and falsy values.
|
|
6
|
+
* When Tailwind classes conflict (e.g. `p-2` + `p-4`), the last one wins.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* cn('px-4 py-2', { 'bg-blue-500': isActive, 'bg-gray-300': !isActive })
|
|
11
|
+
* cn('p-2', 'p-4') // → 'p-4'
|
|
12
|
+
* cn('text-sm', null, undefined, false, 'font-bold') // → 'text-sm font-bold'
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Wait for a specified number of milliseconds.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* await sleep(1000) // wait 1 second
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare function sleep(ms: number): Promise<void>;
|
|
26
|
+
interface RetryOptions {
|
|
27
|
+
/** Maximum number of attempts (default: 3) */
|
|
28
|
+
maxAttempts?: number;
|
|
29
|
+
/** Initial delay in ms between attempts (default: 100) */
|
|
30
|
+
delayMs?: number;
|
|
31
|
+
/** Multiplier applied to delay after each failure (default: 2) */
|
|
32
|
+
backoffMultiplier?: number;
|
|
33
|
+
/** Maximum delay in ms (default: 30000) */
|
|
34
|
+
maxDelayMs?: number;
|
|
35
|
+
/** Only retry if error message matches one of these strings */
|
|
36
|
+
retryableErrors?: string[];
|
|
37
|
+
/** Custom predicate to decide if error is retryable */
|
|
38
|
+
shouldRetry?: (error: unknown, attempt: number) => boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Retry an async function with exponential backoff.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const data = await retry(() => fetch('/api/data'), {
|
|
46
|
+
* maxAttempts: 3,
|
|
47
|
+
* delayMs: 100,
|
|
48
|
+
* backoffMultiplier: 2,
|
|
49
|
+
* })
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Race a promise against a timeout. Throws if not resolved in time.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const data = await timeout(fetch('/api/slow'), 5000)
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
declare function timeout<T>(promise: Promise<T>, ms: number): Promise<T>;
|
|
62
|
+
/**
|
|
63
|
+
* Execute a function after a delay.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const result = await delay(() => expensiveComputation(), 100)
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
declare function delay<T>(fn: () => T | Promise<T>, ms: number): Promise<T>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Return a debounced version of fn that delays invocation until after
|
|
74
|
+
* `ms` milliseconds have elapsed since the last call.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* const handleSearch = debounce((query: string) => {
|
|
79
|
+
* fetchResults(query)
|
|
80
|
+
* }, 300)
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function debounce<T extends (...args: Parameters<T>) => ReturnType<T>>(fn: T, ms: number): ((...args: Parameters<T>) => void) & {
|
|
84
|
+
cancel: () => void;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Return a throttled version of fn that fires at most once per `ms` window.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* const handleScroll = throttle(() => updateScrollPosition(), 100)
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
declare function throttle<T extends (...args: Parameters<T>) => ReturnType<T>>(fn: T, ms: number): (...args: Parameters<T>) => void;
|
|
95
|
+
/**
|
|
96
|
+
* Return a memoized version of fn. Results are cached by serialized arguments.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* const fib = memoize((n: number): number => n <= 1 ? n : fib(n - 1) + fib(n - 2))
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
declare function memoize<T extends (...args: Parameters<T>) => ReturnType<T>>(fn: T, keyFn?: (...args: Parameters<T>) => string): T;
|
|
104
|
+
/**
|
|
105
|
+
* Compose functions right-to-left. The rightmost function is applied first.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* const transform = compose(trim, toLowerCase, removeSpaces)
|
|
110
|
+
* transform(' Hello World ') // removeSpaces → toLowerCase → trim
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
declare function compose<T>(...fns: Array<(arg: T) => T>): (arg: T) => T;
|
|
114
|
+
/**
|
|
115
|
+
* Pipe functions left-to-right. The leftmost function is applied first.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* const transform = pipe(removeSpaces, toLowerCase, trim)
|
|
120
|
+
* transform(' Hello World ') // removeSpaces → toLowerCase → trim
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
declare function pipe<T>(...fns: Array<(arg: T) => T>): (arg: T) => T;
|
|
124
|
+
|
|
125
|
+
/** Add `days` to a date and return a new Date. */
|
|
126
|
+
declare function addDays(date: Date, days: number): Date;
|
|
127
|
+
/** Add `hours` to a date and return a new Date. */
|
|
128
|
+
declare function addHours(date: Date, hours: number): Date;
|
|
129
|
+
/** Add `minutes` to a date and return a new Date. */
|
|
130
|
+
declare function addMinutes(date: Date, minutes: number): Date;
|
|
131
|
+
/** Add `seconds` to a date and return a new Date. */
|
|
132
|
+
declare function addSeconds(date: Date, seconds: number): Date;
|
|
133
|
+
/**
|
|
134
|
+
* Format a date using a simple template string.
|
|
135
|
+
* Tokens: yyyy, MM, dd, HH, mm, ss
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* formatDate(new Date('2026-04-05T14:30:00'), 'yyyy-MM-dd HH:mm:ss')
|
|
140
|
+
* // → '2026-04-05 14:30:00'
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
declare function formatDate(date: Date, format: string): string;
|
|
144
|
+
/**
|
|
145
|
+
* Parse a date string using a format template.
|
|
146
|
+
* Tokens: yyyy, MM, dd, HH, mm, ss
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* parseDate('2026-04-05', 'yyyy-MM-dd') // → Date object
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
declare function parseDate(dateStr: string, format: string): Date;
|
|
154
|
+
/**
|
|
155
|
+
* Returns true if the date is in the past.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* isExpired(new Date('2020-01-01')) // → true
|
|
160
|
+
* isExpired(new Date('2099-01-01')) // → false
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
declare function isExpired(date: Date): boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Return a human-readable relative time string.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* getRelativeTime(new Date(Date.now() - 5000)) // → 'just now'
|
|
170
|
+
* getRelativeTime(new Date(Date.now() - 120000)) // → '2 minutes ago'
|
|
171
|
+
* getRelativeTime(new Date(Date.now() + 86400000)) // → 'in 1 day'
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
declare function getRelativeTime(date: Date): string;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Convert a string to a URL-safe slug.
|
|
178
|
+
* @example slugify('Hello World!') // → 'hello-world'
|
|
179
|
+
*/
|
|
180
|
+
declare function slugify(str: string): string;
|
|
181
|
+
/**
|
|
182
|
+
* Capitalize the first letter of a string.
|
|
183
|
+
* @example capitalize('hello') // → 'Hello'
|
|
184
|
+
*/
|
|
185
|
+
declare function capitalize(str: string): string;
|
|
186
|
+
/**
|
|
187
|
+
* Convert a string to camelCase.
|
|
188
|
+
* @example camelCase('hello-world') // → 'helloWorld'
|
|
189
|
+
*/
|
|
190
|
+
declare function camelCase(str: string): string;
|
|
191
|
+
/**
|
|
192
|
+
* Convert a string to snake_case.
|
|
193
|
+
* @example snakeCase('helloWorld') // → 'hello_world'
|
|
194
|
+
*/
|
|
195
|
+
declare function snakeCase(str: string): string;
|
|
196
|
+
/**
|
|
197
|
+
* Convert a string to PascalCase.
|
|
198
|
+
* @example pascalCase('hello-world') // → 'HelloWorld'
|
|
199
|
+
*/
|
|
200
|
+
declare function pascalCase(str: string): string;
|
|
201
|
+
/**
|
|
202
|
+
* Truncate a string to a maximum length, appending a suffix if truncated.
|
|
203
|
+
* @example truncate('This is a long string', 10) // → 'This is a...'
|
|
204
|
+
*/
|
|
205
|
+
declare function truncate(str: string, maxLength: number, suffix?: string): string;
|
|
206
|
+
/**
|
|
207
|
+
* Escape HTML special characters to prevent XSS.
|
|
208
|
+
* @example escapeHtml('<script>alert("xss")</script>') // → '<script>...'
|
|
209
|
+
*/
|
|
210
|
+
declare function escapeHtml(str: string): string;
|
|
211
|
+
/**
|
|
212
|
+
* Unescape HTML entities back to their characters.
|
|
213
|
+
* @example unescapeHtml('<b>') // → '<b>'
|
|
214
|
+
*/
|
|
215
|
+
declare function unescapeHtml(str: string): string;
|
|
216
|
+
/**
|
|
217
|
+
* Alias for pascalCase. Convert kebab/snake to PascalCase.
|
|
218
|
+
* @example toPascalCase('my-component') // → 'MyComponent'
|
|
219
|
+
*/
|
|
220
|
+
declare const toPascalCase: typeof pascalCase;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Returns true if the string is a valid email address.
|
|
224
|
+
*/
|
|
225
|
+
declare function isEmail(str: string): boolean;
|
|
226
|
+
/**
|
|
227
|
+
* Returns true if the string is a valid URL (http or https).
|
|
228
|
+
*/
|
|
229
|
+
declare function isUrl(str: string): boolean;
|
|
230
|
+
/**
|
|
231
|
+
* Returns true if the string looks like a phone number.
|
|
232
|
+
* Accepts E.164 format and common national formats.
|
|
233
|
+
*/
|
|
234
|
+
declare function isPhone(str: string): boolean;
|
|
235
|
+
/**
|
|
236
|
+
* Returns true if the string is a valid UUID v4.
|
|
237
|
+
*/
|
|
238
|
+
declare function isUUID(str: string): boolean;
|
|
239
|
+
/**
|
|
240
|
+
* Returns true if the string meets strong password requirements:
|
|
241
|
+
* - At least 8 characters
|
|
242
|
+
* - At least one uppercase letter
|
|
243
|
+
* - At least one lowercase letter
|
|
244
|
+
* - At least one digit
|
|
245
|
+
* - At least one special character
|
|
246
|
+
*/
|
|
247
|
+
declare function isStrongPassword(str: string): boolean;
|
|
248
|
+
/**
|
|
249
|
+
* Returns true if the string passes a basic Luhn algorithm check (credit card).
|
|
250
|
+
*/
|
|
251
|
+
declare function isCreditCard(str: string): boolean;
|
|
252
|
+
|
|
253
|
+
export { type RetryOptions, addDays, addHours, addMinutes, addSeconds, camelCase, capitalize, cn, compose, debounce, delay, escapeHtml, formatDate, getRelativeTime, isCreditCard, isEmail, isExpired, isPhone, isStrongPassword, isUUID, isUrl, memoize, parseDate, pascalCase, pipe, retry, sleep, slugify, snakeCase, throttle, timeout, toPascalCase, truncate, unescapeHtml };
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// src/cn.ts
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
function cn(...inputs) {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// src/async.ts
|
|
9
|
+
function sleep(ms) {
|
|
10
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11
|
+
}
|
|
12
|
+
async function retry(fn, options = {}) {
|
|
13
|
+
const {
|
|
14
|
+
maxAttempts = 3,
|
|
15
|
+
delayMs = 100,
|
|
16
|
+
backoffMultiplier = 2,
|
|
17
|
+
maxDelayMs = 3e4,
|
|
18
|
+
retryableErrors,
|
|
19
|
+
shouldRetry
|
|
20
|
+
} = options;
|
|
21
|
+
let lastError;
|
|
22
|
+
let currentDelay = delayMs;
|
|
23
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
24
|
+
try {
|
|
25
|
+
return await fn();
|
|
26
|
+
} catch (error) {
|
|
27
|
+
lastError = error;
|
|
28
|
+
const isLastAttempt = attempt === maxAttempts;
|
|
29
|
+
if (isLastAttempt) break;
|
|
30
|
+
if (shouldRetry && !shouldRetry(error, attempt)) break;
|
|
31
|
+
if (retryableErrors && retryableErrors.length > 0) {
|
|
32
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
33
|
+
const isRetryable = retryableErrors.some((re) => msg.includes(re));
|
|
34
|
+
if (!isRetryable) break;
|
|
35
|
+
}
|
|
36
|
+
await sleep(Math.min(currentDelay, maxDelayMs));
|
|
37
|
+
currentDelay *= backoffMultiplier;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
throw lastError;
|
|
41
|
+
}
|
|
42
|
+
async function timeout(promise, ms) {
|
|
43
|
+
let timer;
|
|
44
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
45
|
+
timer = setTimeout(() => reject(new Error(`Timed out after ${ms}ms`)), ms);
|
|
46
|
+
});
|
|
47
|
+
try {
|
|
48
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
49
|
+
} finally {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function delay(fn, ms) {
|
|
54
|
+
await sleep(ms);
|
|
55
|
+
return fn();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/function.ts
|
|
59
|
+
function debounce(fn, ms) {
|
|
60
|
+
let timer;
|
|
61
|
+
function debounced(...args) {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
timer = setTimeout(() => fn(...args), ms);
|
|
64
|
+
}
|
|
65
|
+
debounced.cancel = () => clearTimeout(timer);
|
|
66
|
+
return debounced;
|
|
67
|
+
}
|
|
68
|
+
function throttle(fn, ms) {
|
|
69
|
+
let lastCall = 0;
|
|
70
|
+
return function(...args) {
|
|
71
|
+
const now = Date.now();
|
|
72
|
+
if (now - lastCall >= ms) {
|
|
73
|
+
lastCall = now;
|
|
74
|
+
fn(...args);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function memoize(fn, keyFn) {
|
|
79
|
+
const cache = /* @__PURE__ */ new Map();
|
|
80
|
+
return function(...args) {
|
|
81
|
+
const key = keyFn ? keyFn(...args) : JSON.stringify(args);
|
|
82
|
+
if (cache.has(key)) return cache.get(key);
|
|
83
|
+
const result = fn(...args);
|
|
84
|
+
cache.set(key, result);
|
|
85
|
+
return result;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function compose(...fns) {
|
|
89
|
+
return (arg) => fns.reduceRight((acc, fn) => fn(acc), arg);
|
|
90
|
+
}
|
|
91
|
+
function pipe(...fns) {
|
|
92
|
+
return (arg) => fns.reduce((acc, fn) => fn(acc), arg);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/date.ts
|
|
96
|
+
function addDays(date, days) {
|
|
97
|
+
const result = new Date(date);
|
|
98
|
+
result.setDate(result.getDate() + days);
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
function addHours(date, hours) {
|
|
102
|
+
return new Date(date.getTime() + hours * 60 * 60 * 1e3);
|
|
103
|
+
}
|
|
104
|
+
function addMinutes(date, minutes) {
|
|
105
|
+
return new Date(date.getTime() + minutes * 60 * 1e3);
|
|
106
|
+
}
|
|
107
|
+
function addSeconds(date, seconds) {
|
|
108
|
+
return new Date(date.getTime() + seconds * 1e3);
|
|
109
|
+
}
|
|
110
|
+
function formatDate(date, format) {
|
|
111
|
+
const pad = (n, width = 2) => String(n).padStart(width, "0");
|
|
112
|
+
return format.replace("yyyy", String(date.getFullYear())).replace("MM", pad(date.getMonth() + 1)).replace("dd", pad(date.getDate())).replace("HH", pad(date.getHours())).replace("mm", pad(date.getMinutes())).replace("ss", pad(date.getSeconds()));
|
|
113
|
+
}
|
|
114
|
+
function parseDate(dateStr, format) {
|
|
115
|
+
const tokenMap = {};
|
|
116
|
+
const tokens = [
|
|
117
|
+
{ token: "yyyy", length: 4, key: "year" },
|
|
118
|
+
{ token: "MM", length: 2, key: "month" },
|
|
119
|
+
{ token: "dd", length: 2, key: "day" },
|
|
120
|
+
{ token: "HH", length: 2, key: "hour" },
|
|
121
|
+
{ token: "mm", length: 2, key: "minute" },
|
|
122
|
+
{ token: "ss", length: 2, key: "second" }
|
|
123
|
+
];
|
|
124
|
+
let remaining = format;
|
|
125
|
+
let idx = 0;
|
|
126
|
+
for (const { token, length, key } of tokens) {
|
|
127
|
+
const pos = remaining.indexOf(token);
|
|
128
|
+
if (pos !== -1) {
|
|
129
|
+
const strPos = format.indexOf(token);
|
|
130
|
+
tokenMap[key] = parseInt(dateStr.slice(strPos, strPos + length), 10);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return new Date(
|
|
134
|
+
tokenMap["year"] ?? 1970,
|
|
135
|
+
(tokenMap["month"] ?? 1) - 1,
|
|
136
|
+
tokenMap["day"] ?? 1,
|
|
137
|
+
tokenMap["hour"] ?? 0,
|
|
138
|
+
tokenMap["minute"] ?? 0,
|
|
139
|
+
tokenMap["second"] ?? 0
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
function isExpired(date) {
|
|
143
|
+
return date.getTime() < Date.now();
|
|
144
|
+
}
|
|
145
|
+
function getRelativeTime(date) {
|
|
146
|
+
const diffMs = date.getTime() - Date.now();
|
|
147
|
+
const diffSec = Math.round(diffMs / 1e3);
|
|
148
|
+
const absSec = Math.abs(diffSec);
|
|
149
|
+
if (absSec < 10) return "just now";
|
|
150
|
+
const units = [
|
|
151
|
+
[60, "second"],
|
|
152
|
+
[3600, "minute"],
|
|
153
|
+
[86400, "hour"],
|
|
154
|
+
[604800, "day"],
|
|
155
|
+
[2592e3, "week"],
|
|
156
|
+
[31536e3, "month"],
|
|
157
|
+
[Infinity, "year"]
|
|
158
|
+
];
|
|
159
|
+
let value = absSec;
|
|
160
|
+
let unit = "second";
|
|
161
|
+
for (let i = 0; i < units.length - 1; i++) {
|
|
162
|
+
if (absSec < units[i][0]) {
|
|
163
|
+
const divisor = i === 0 ? 1 : units[i - 1][0];
|
|
164
|
+
value = Math.round(absSec / divisor);
|
|
165
|
+
unit = units[i - 1]?.[1] ?? "second";
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
if (i === units.length - 2) {
|
|
169
|
+
value = Math.round(absSec / units[i][0]);
|
|
170
|
+
unit = units[i][1];
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const plural = value !== 1 ? "s" : "";
|
|
174
|
+
return diffSec < 0 ? `${value} ${unit}${plural} ago` : `in ${value} ${unit}${plural}`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/string.ts
|
|
178
|
+
function slugify(str) {
|
|
179
|
+
return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
180
|
+
}
|
|
181
|
+
function capitalize(str) {
|
|
182
|
+
if (!str) return str;
|
|
183
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
184
|
+
}
|
|
185
|
+
function camelCase(str) {
|
|
186
|
+
return str.replace(/[-_\s]+(.)/g, (_, c) => c.toUpperCase()).replace(/^(.)/, (c) => c.toLowerCase());
|
|
187
|
+
}
|
|
188
|
+
function snakeCase(str) {
|
|
189
|
+
return str.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[-\s]+/g, "_").toLowerCase();
|
|
190
|
+
}
|
|
191
|
+
function pascalCase(str) {
|
|
192
|
+
return str.replace(/[-_\s]+(.)/g, (_, c) => c.toUpperCase()).replace(/^(.)/, (c) => c.toUpperCase());
|
|
193
|
+
}
|
|
194
|
+
function truncate(str, maxLength, suffix = "...") {
|
|
195
|
+
if (str.length <= maxLength) return str;
|
|
196
|
+
return str.slice(0, maxLength - suffix.length) + suffix;
|
|
197
|
+
}
|
|
198
|
+
function escapeHtml(str) {
|
|
199
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
200
|
+
}
|
|
201
|
+
function unescapeHtml(str) {
|
|
202
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'");
|
|
203
|
+
}
|
|
204
|
+
var toPascalCase = pascalCase;
|
|
205
|
+
|
|
206
|
+
// src/validation.ts
|
|
207
|
+
function isEmail(str) {
|
|
208
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
|
|
209
|
+
}
|
|
210
|
+
function isUrl(str) {
|
|
211
|
+
try {
|
|
212
|
+
const url = new URL(str);
|
|
213
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
214
|
+
} catch {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function isPhone(str) {
|
|
219
|
+
return /^\+?[1-9]\d{6,14}$/.test(str.replace(/[\s\-().]/g, ""));
|
|
220
|
+
}
|
|
221
|
+
function isUUID(str) {
|
|
222
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str);
|
|
223
|
+
}
|
|
224
|
+
function isStrongPassword(str) {
|
|
225
|
+
return str.length >= 8 && /[A-Z]/.test(str) && /[a-z]/.test(str) && /[0-9]/.test(str) && /[^A-Za-z0-9]/.test(str);
|
|
226
|
+
}
|
|
227
|
+
function isCreditCard(str) {
|
|
228
|
+
const digits = str.replace(/\D/g, "");
|
|
229
|
+
if (digits.length < 13 || digits.length > 19) return false;
|
|
230
|
+
let sum = 0;
|
|
231
|
+
let alternate = false;
|
|
232
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
233
|
+
let n = parseInt(digits[i], 10);
|
|
234
|
+
if (alternate) {
|
|
235
|
+
n *= 2;
|
|
236
|
+
if (n > 9) n -= 9;
|
|
237
|
+
}
|
|
238
|
+
sum += n;
|
|
239
|
+
alternate = !alternate;
|
|
240
|
+
}
|
|
241
|
+
return sum % 10 === 0;
|
|
242
|
+
}
|
|
243
|
+
export {
|
|
244
|
+
addDays,
|
|
245
|
+
addHours,
|
|
246
|
+
addMinutes,
|
|
247
|
+
addSeconds,
|
|
248
|
+
camelCase,
|
|
249
|
+
capitalize,
|
|
250
|
+
cn,
|
|
251
|
+
compose,
|
|
252
|
+
debounce,
|
|
253
|
+
delay,
|
|
254
|
+
escapeHtml,
|
|
255
|
+
formatDate,
|
|
256
|
+
getRelativeTime,
|
|
257
|
+
isCreditCard,
|
|
258
|
+
isEmail,
|
|
259
|
+
isExpired,
|
|
260
|
+
isPhone,
|
|
261
|
+
isStrongPassword,
|
|
262
|
+
isUUID,
|
|
263
|
+
isUrl,
|
|
264
|
+
memoize,
|
|
265
|
+
parseDate,
|
|
266
|
+
pascalCase,
|
|
267
|
+
pipe,
|
|
268
|
+
retry,
|
|
269
|
+
sleep,
|
|
270
|
+
slugify,
|
|
271
|
+
snakeCase,
|
|
272
|
+
throttle,
|
|
273
|
+
timeout,
|
|
274
|
+
toPascalCase,
|
|
275
|
+
truncate,
|
|
276
|
+
unescapeHtml
|
|
277
|
+
};
|
|
278
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cn.ts","../src/async.ts","../src/function.ts","../src/date.ts","../src/string.ts","../src/validation.ts"],"sourcesContent":["// @geenius/tools-shared — src/cn.ts\n// Tailwind-aware class name utility.\n\nimport { clsx, type ClassValue } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\n/**\n * Merge CSS class names with Tailwind conflict resolution.\n * Handles strings, objects, arrays, and falsy values.\n * When Tailwind classes conflict (e.g. `p-2` + `p-4`), the last one wins.\n *\n * @example\n * ```ts\n * cn('px-4 py-2', { 'bg-blue-500': isActive, 'bg-gray-300': !isActive })\n * cn('p-2', 'p-4') // → 'p-4'\n * cn('text-sm', null, undefined, false, 'font-bold') // → 'text-sm font-bold'\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs))\n}\n","// @geenius/tools-shared — src/async.ts\n// Async utility functions.\n\n// ─── sleep ────────────────────────────────────────────────────\n\n/**\n * Wait for a specified number of milliseconds.\n *\n * @example\n * ```ts\n * await sleep(1000) // wait 1 second\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n// ─── retry ────────────────────────────────────────────────────\n\nexport interface RetryOptions {\n /** Maximum number of attempts (default: 3) */\n maxAttempts?: number\n /** Initial delay in ms between attempts (default: 100) */\n delayMs?: number\n /** Multiplier applied to delay after each failure (default: 2) */\n backoffMultiplier?: number\n /** Maximum delay in ms (default: 30000) */\n maxDelayMs?: number\n /** Only retry if error message matches one of these strings */\n retryableErrors?: string[]\n /** Custom predicate to decide if error is retryable */\n shouldRetry?: (error: unknown, attempt: number) => boolean\n}\n\n/**\n * Retry an async function with exponential backoff.\n *\n * @example\n * ```ts\n * const data = await retry(() => fetch('/api/data'), {\n * maxAttempts: 3,\n * delayMs: 100,\n * backoffMultiplier: 2,\n * })\n * ```\n */\nexport async function retry<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {},\n): Promise<T> {\n const {\n maxAttempts = 3,\n delayMs = 100,\n backoffMultiplier = 2,\n maxDelayMs = 30_000,\n retryableErrors,\n shouldRetry,\n } = options\n\n let lastError: unknown\n let currentDelay = delayMs\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn()\n } catch (error) {\n lastError = error\n\n const isLastAttempt = attempt === maxAttempts\n\n if (isLastAttempt) break\n\n // Check custom predicate first\n if (shouldRetry && !shouldRetry(error, attempt)) break\n\n // Check retryable error list\n if (retryableErrors && retryableErrors.length > 0) {\n const msg = error instanceof Error ? error.message : String(error)\n const isRetryable = retryableErrors.some((re) => msg.includes(re))\n if (!isRetryable) break\n }\n\n await sleep(Math.min(currentDelay, maxDelayMs))\n currentDelay *= backoffMultiplier\n }\n }\n\n throw lastError\n}\n\n// ─── timeout ──────────────────────────────────────────────────\n\n/**\n * Race a promise against a timeout. Throws if not resolved in time.\n *\n * @example\n * ```ts\n * const data = await timeout(fetch('/api/slow'), 5000)\n * ```\n */\nexport async function timeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n let timer: ReturnType<typeof setTimeout>\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(`Timed out after ${ms}ms`)), ms)\n })\n\n try {\n return await Promise.race([promise, timeoutPromise])\n } finally {\n clearTimeout(timer!)\n }\n}\n\n// ─── delay ───────────────────────────────────────────────────\n\n/**\n * Execute a function after a delay.\n *\n * @example\n * ```ts\n * const result = await delay(() => expensiveComputation(), 100)\n * ```\n */\nexport async function delay<T>(fn: () => T | Promise<T>, ms: number): Promise<T> {\n await sleep(ms)\n return fn()\n}\n","// @geenius/tools-shared — src/function.ts\n// Higher-order function utilities.\n\n// ─── debounce ─────────────────────────────────────────────────\n\n/**\n * Return a debounced version of fn that delays invocation until after\n * `ms` milliseconds have elapsed since the last call.\n *\n * @example\n * ```ts\n * const handleSearch = debounce((query: string) => {\n * fetchResults(query)\n * }, 300)\n * ```\n */\nexport function debounce<T extends (...args: Parameters<T>) => ReturnType<T>>(\n fn: T,\n ms: number,\n): ((...args: Parameters<T>) => void) & { cancel: () => void } {\n let timer: ReturnType<typeof setTimeout> | undefined\n\n function debounced(...args: Parameters<T>) {\n clearTimeout(timer)\n timer = setTimeout(() => fn(...args), ms)\n }\n\n debounced.cancel = () => clearTimeout(timer)\n\n return debounced\n}\n\n// ─── throttle ─────────────────────────────────────────────────\n\n/**\n * Return a throttled version of fn that fires at most once per `ms` window.\n *\n * @example\n * ```ts\n * const handleScroll = throttle(() => updateScrollPosition(), 100)\n * ```\n */\nexport function throttle<T extends (...args: Parameters<T>) => ReturnType<T>>(\n fn: T,\n ms: number,\n): (...args: Parameters<T>) => void {\n let lastCall = 0\n\n return function (...args: Parameters<T>) {\n const now = Date.now()\n if (now - lastCall >= ms) {\n lastCall = now\n fn(...args)\n }\n }\n}\n\n// ─── memoize ──────────────────────────────────────────────────\n\n/**\n * Return a memoized version of fn. Results are cached by serialized arguments.\n *\n * @example\n * ```ts\n * const fib = memoize((n: number): number => n <= 1 ? n : fib(n - 1) + fib(n - 2))\n * ```\n */\nexport function memoize<T extends (...args: Parameters<T>) => ReturnType<T>>(\n fn: T,\n keyFn?: (...args: Parameters<T>) => string,\n): T {\n const cache = new Map<string, ReturnType<T>>()\n\n return function (...args: Parameters<T>): ReturnType<T> {\n const key = keyFn ? keyFn(...args) : JSON.stringify(args)\n if (cache.has(key)) return cache.get(key) as ReturnType<T>\n const result = fn(...args)\n cache.set(key, result)\n return result\n } as T\n}\n\n// ─── compose ──────────────────────────────────────────────────\n\n/**\n * Compose functions right-to-left. The rightmost function is applied first.\n *\n * @example\n * ```ts\n * const transform = compose(trim, toLowerCase, removeSpaces)\n * transform(' Hello World ') // removeSpaces → toLowerCase → trim\n * ```\n */\nexport function compose<T>(...fns: Array<(arg: T) => T>): (arg: T) => T {\n return (arg: T) => fns.reduceRight((acc, fn) => fn(acc), arg)\n}\n\n// ─── pipe ─────────────────────────────────────────────────────\n\n/**\n * Pipe functions left-to-right. The leftmost function is applied first.\n *\n * @example\n * ```ts\n * const transform = pipe(removeSpaces, toLowerCase, trim)\n * transform(' Hello World ') // removeSpaces → toLowerCase → trim\n * ```\n */\nexport function pipe<T>(...fns: Array<(arg: T) => T>): (arg: T) => T {\n return (arg: T) => fns.reduce((acc, fn) => fn(acc), arg)\n}\n","// @geenius/tools-shared — src/date.ts\n// Date manipulation utilities. Zero external dependencies.\n\n// ─── Add helpers ──────────────────────────────────────────────\n\n/** Add `days` to a date and return a new Date. */\nexport function addDays(date: Date, days: number): Date {\n const result = new Date(date)\n result.setDate(result.getDate() + days)\n return result\n}\n\n/** Add `hours` to a date and return a new Date. */\nexport function addHours(date: Date, hours: number): Date {\n return new Date(date.getTime() + hours * 60 * 60 * 1000)\n}\n\n/** Add `minutes` to a date and return a new Date. */\nexport function addMinutes(date: Date, minutes: number): Date {\n return new Date(date.getTime() + minutes * 60 * 1000)\n}\n\n/** Add `seconds` to a date and return a new Date. */\nexport function addSeconds(date: Date, seconds: number): Date {\n return new Date(date.getTime() + seconds * 1000)\n}\n\n// ─── Format ───────────────────────────────────────────────────\n\n/**\n * Format a date using a simple template string.\n * Tokens: yyyy, MM, dd, HH, mm, ss\n *\n * @example\n * ```ts\n * formatDate(new Date('2026-04-05T14:30:00'), 'yyyy-MM-dd HH:mm:ss')\n * // → '2026-04-05 14:30:00'\n * ```\n */\nexport function formatDate(date: Date, format: string): string {\n const pad = (n: number, width = 2) => String(n).padStart(width, '0')\n\n return format\n .replace('yyyy', String(date.getFullYear()))\n .replace('MM', pad(date.getMonth() + 1))\n .replace('dd', pad(date.getDate()))\n .replace('HH', pad(date.getHours()))\n .replace('mm', pad(date.getMinutes()))\n .replace('ss', pad(date.getSeconds()))\n}\n\n// ─── Parse ────────────────────────────────────────────────────\n\n/**\n * Parse a date string using a format template.\n * Tokens: yyyy, MM, dd, HH, mm, ss\n *\n * @example\n * ```ts\n * parseDate('2026-04-05', 'yyyy-MM-dd') // → Date object\n * ```\n */\nexport function parseDate(dateStr: string, format: string): Date {\n const tokenMap: Record<string, number> = {}\n\n const tokens = [\n { token: 'yyyy', length: 4, key: 'year' },\n { token: 'MM', length: 2, key: 'month' },\n { token: 'dd', length: 2, key: 'day' },\n { token: 'HH', length: 2, key: 'hour' },\n { token: 'mm', length: 2, key: 'minute' },\n { token: 'ss', length: 2, key: 'second' },\n ]\n\n let remaining = format\n let idx = 0\n\n for (const { token, length, key } of tokens) {\n const pos = remaining.indexOf(token)\n if (pos !== -1) {\n const strPos = format.indexOf(token)\n tokenMap[key] = parseInt(dateStr.slice(strPos, strPos + length), 10)\n }\n }\n\n return new Date(\n tokenMap['year'] ?? 1970,\n (tokenMap['month'] ?? 1) - 1,\n tokenMap['day'] ?? 1,\n tokenMap['hour'] ?? 0,\n tokenMap['minute'] ?? 0,\n tokenMap['second'] ?? 0,\n )\n}\n\n// ─── isExpired ────────────────────────────────────────────────\n\n/**\n * Returns true if the date is in the past.\n *\n * @example\n * ```ts\n * isExpired(new Date('2020-01-01')) // → true\n * isExpired(new Date('2099-01-01')) // → false\n * ```\n */\nexport function isExpired(date: Date): boolean {\n return date.getTime() < Date.now()\n}\n\n// ─── getRelativeTime ──────────────────────────────────────────\n\n/**\n * Return a human-readable relative time string.\n *\n * @example\n * ```ts\n * getRelativeTime(new Date(Date.now() - 5000)) // → 'just now'\n * getRelativeTime(new Date(Date.now() - 120000)) // → '2 minutes ago'\n * getRelativeTime(new Date(Date.now() + 86400000)) // → 'in 1 day'\n * ```\n */\nexport function getRelativeTime(date: Date): string {\n const diffMs = date.getTime() - Date.now()\n const diffSec = Math.round(diffMs / 1000)\n const absSec = Math.abs(diffSec)\n\n if (absSec < 10) return 'just now'\n\n const units: [number, string][] = [\n [60, 'second'],\n [3600, 'minute'],\n [86400, 'hour'],\n [604800, 'day'],\n [2592000, 'week'],\n [31536000, 'month'],\n [Infinity, 'year'],\n ]\n\n let value = absSec\n let unit = 'second'\n\n for (let i = 0; i < units.length - 1; i++) {\n if (absSec < units[i][0]) {\n const divisor = i === 0 ? 1 : units[i - 1][0]\n value = Math.round(absSec / divisor)\n unit = units[i - 1]?.[1] ?? 'second'\n break\n }\n if (i === units.length - 2) {\n value = Math.round(absSec / units[i][0])\n unit = units[i][1]\n }\n }\n\n const plural = value !== 1 ? 's' : ''\n\n return diffSec < 0\n ? `${value} ${unit}${plural} ago`\n : `in ${value} ${unit}${plural}`\n}\n","// @geenius/tools-shared — src/string.ts\n// String manipulation utilities.\n\n/**\n * Convert a string to a URL-safe slug.\n * @example slugify('Hello World!') // → 'hello-world'\n */\nexport function slugify(str: string): string {\n return str\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9\\s-]/g, '')\n .replace(/[\\s_-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n}\n\n/**\n * Capitalize the first letter of a string.\n * @example capitalize('hello') // → 'Hello'\n */\nexport function capitalize(str: string): string {\n if (!str) return str\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\n/**\n * Convert a string to camelCase.\n * @example camelCase('hello-world') // → 'helloWorld'\n */\nexport function camelCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)/g, (_, c: string) => c.toUpperCase())\n .replace(/^(.)/, (c) => c.toLowerCase())\n}\n\n/**\n * Convert a string to snake_case.\n * @example snakeCase('helloWorld') // → 'hello_world'\n */\nexport function snakeCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[-\\s]+/g, '_')\n .toLowerCase()\n}\n\n/**\n * Convert a string to PascalCase.\n * @example pascalCase('hello-world') // → 'HelloWorld'\n */\nexport function pascalCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)/g, (_, c: string) => c.toUpperCase())\n .replace(/^(.)/, (c) => c.toUpperCase())\n}\n\n/**\n * Truncate a string to a maximum length, appending a suffix if truncated.\n * @example truncate('This is a long string', 10) // → 'This is a...'\n */\nexport function truncate(str: string, maxLength: number, suffix = '...'): string {\n if (str.length <= maxLength) return str\n return str.slice(0, maxLength - suffix.length) + suffix\n}\n\n/**\n * Escape HTML special characters to prevent XSS.\n * @example escapeHtml('<script>alert(\"xss\")</script>') // → '<script>...'\n */\nexport function escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n}\n\n/**\n * Unescape HTML entities back to their characters.\n * @example unescapeHtml('<b>') // → '<b>'\n */\nexport function unescapeHtml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n}\n\n/**\n * Alias for pascalCase. Convert kebab/snake to PascalCase.\n * @example toPascalCase('my-component') // → 'MyComponent'\n */\nexport const toPascalCase = pascalCase\n","// @geenius/tools-shared — src/validation.ts\n// Input validation predicates.\n\n/**\n * Returns true if the string is a valid email address.\n */\nexport function isEmail(str: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(str)\n}\n\n/**\n * Returns true if the string is a valid URL (http or https).\n */\nexport function isUrl(str: string): boolean {\n try {\n const url = new URL(str)\n return url.protocol === 'http:' || url.protocol === 'https:'\n } catch {\n return false\n }\n}\n\n/**\n * Returns true if the string looks like a phone number.\n * Accepts E.164 format and common national formats.\n */\nexport function isPhone(str: string): boolean {\n return /^\\+?[1-9]\\d{6,14}$/.test(str.replace(/[\\s\\-().]/g, ''))\n}\n\n/**\n * Returns true if the string is a valid UUID v4.\n */\nexport function isUUID(str: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str)\n}\n\n/**\n * Returns true if the string meets strong password requirements:\n * - At least 8 characters\n * - At least one uppercase letter\n * - At least one lowercase letter\n * - At least one digit\n * - At least one special character\n */\nexport function isStrongPassword(str: string): boolean {\n return (\n str.length >= 8 &&\n /[A-Z]/.test(str) &&\n /[a-z]/.test(str) &&\n /[0-9]/.test(str) &&\n /[^A-Za-z0-9]/.test(str)\n )\n}\n\n/**\n * Returns true if the string passes a basic Luhn algorithm check (credit card).\n */\nexport function isCreditCard(str: string): boolean {\n const digits = str.replace(/\\D/g, '')\n if (digits.length < 13 || digits.length > 19) return false\n\n let sum = 0\n let alternate = false\n\n for (let i = digits.length - 1; i >= 0; i--) {\n let n = parseInt(digits[i], 10)\n if (alternate) {\n n *= 2\n if (n > 9) n -= 9\n }\n sum += n\n alternate = !alternate\n }\n\n return sum % 10 === 0\n}\n"],"mappings":"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","names":[]}
|
package/.changeset/config.json
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
|
3
|
-
"changelog": "@changesets/cli/changelog",
|
|
4
|
-
"commit": false,
|
|
5
|
-
"fixed": [],
|
|
6
|
-
"linked": [],
|
|
7
|
-
"access": "public",
|
|
8
|
-
"baseBranch": "main",
|
|
9
|
-
"updateInternalDependencies": "patch",
|
|
10
|
-
"ignore": []
|
|
11
|
-
}
|
package/.env.example
DELETED
package/.github/CODEOWNERS
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
* @mxn2020
|