@od-oneapp/utils 2026.2.2001-canary.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # @od-oneapp/utils
2
+
3
+ Collection of framework-agnostic utilities (class name helpers, formatting, validation, rate limiting) shared across
4
+ OneApp workspaces. Functions ship as TypeScript source and include rich JSDoc examples to improve AI tooling
5
+ performance.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pnpm --filter= @od-oneapp/utils < workspace > add
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```ts
16
+ import { cn, debounce, formatDate, truncate } from "@od-oneapp/utils";
17
+
18
+ const className = cn("base", isActive && "active");
19
+ const save = debounce((payload: unknown) => console.log(payload), 300);
20
+ const label = truncate(formatDate(new Date()), 12);
21
+ ```
22
+
23
+ ## Development
24
+
25
+ - `pnpm --filter=@od-oneapp/utils lint`
26
+ - `pnpm --filter=@od-oneapp/utils typecheck`
27
+
28
+ Because utilities are exported as ESM TypeScript, ensure your runtime transpiles them (e.g., via Next.js
29
+ `transpilePackages`).
package/cn.d.mts ADDED
@@ -0,0 +1,7 @@
1
+ import { ClassValue } from "clsx";
2
+
3
+ //#region src/cn.d.ts
4
+ declare function cn(...inputs: ClassValue[]): string;
5
+ //#endregion
6
+ export { cn };
7
+ //# sourceMappingURL=cn.d.mts.map
package/cn.d.mts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.d.mts","names":[],"sources":["../src/cn.ts"],"mappings":";;;iBAmCgB,EAAA,CAAA,GAAM,MAAA,EAAQ,UAAA"}
package/cn.mjs ADDED
@@ -0,0 +1,42 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ //#region src/cn.ts
5
+ /**
6
+ * @fileoverview Utility for merging class names with Tailwind CSS conflict resolution.
7
+ *
8
+ * Uses clsx for conditional class handling and tailwind-merge for resolving
9
+ * Tailwind CSS class conflicts (e.g., 'px-2 px-4' becomes 'px-4').
10
+ *
11
+ * @module @od-oneapp/utils/cn
12
+ */
13
+ /**
14
+ * Merges class names with Tailwind CSS conflict resolution.
15
+ *
16
+ * @param inputs - Variable number of class name arguments (strings, arrays, objects, or conditionals)
17
+ * @returns Merged class names string with Tailwind conflicts resolved
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * // Basic usage: merge class strings with conflict resolution
22
+ * cn('px-2 py-1', 'px-4') // Output: 'py-1 px-4' (px-4 wins)
23
+ *
24
+ * // Conditional classes: falsy values are filtered out
25
+ * cn('base', isActive && 'active') // Output: 'base active' or 'base'
26
+ *
27
+ * // Object syntax: keys with truthy values are included
28
+ * cn('base', { active: isActive }) // Output: 'base active' or 'base'
29
+ *
30
+ * // Mixed usage: all patterns can be combined
31
+ * cn('btn', 'btn-primary', isDisabled && 'opacity-50', { 'cursor-not-allowed': isDisabled })
32
+ * // Output: 'btn btn-primary opacity-50 cursor-not-allowed' (if disabled)
33
+ * // Output: 'btn btn-primary' (if enabled)
34
+ * ```
35
+ */
36
+ function cn(...inputs) {
37
+ return twMerge(clsx(inputs));
38
+ }
39
+
40
+ //#endregion
41
+ export { cn };
42
+ //# sourceMappingURL=cn.mjs.map
package/cn.mjs.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.mjs","names":[],"sources":["../src/cn.ts"],"sourcesContent":["/**\n * @fileoverview Utility for merging class names with Tailwind CSS conflict resolution.\n *\n * Uses clsx for conditional class handling and tailwind-merge for resolving\n * Tailwind CSS class conflicts (e.g., 'px-2 px-4' becomes 'px-4').\n *\n * @module @od-oneapp/utils/cn\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merges class names with Tailwind CSS conflict resolution.\n *\n * @param inputs - Variable number of class name arguments (strings, arrays, objects, or conditionals)\n * @returns Merged class names string with Tailwind conflicts resolved\n *\n * @example\n * ```ts\n * // Basic usage: merge class strings with conflict resolution\n * cn('px-2 py-1', 'px-4') // Output: 'py-1 px-4' (px-4 wins)\n *\n * // Conditional classes: falsy values are filtered out\n * cn('base', isActive && 'active') // Output: 'base active' or 'base'\n *\n * // Object syntax: keys with truthy values are included\n * cn('base', { active: isActive }) // Output: 'base active' or 'base'\n *\n * // Mixed usage: all patterns can be combined\n * cn('btn', 'btn-primary', isDisabled && 'opacity-50', { 'cursor-not-allowed': isDisabled })\n * // Output: 'btn btn-primary opacity-50 cursor-not-allowed' (if disabled)\n * // Output: 'btn btn-primary' (if enabled)\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,GAAG,GAAG,QAA8B;AAClD,QAAO,QAAQ,KAAK,OAAO,CAAC"}
package/date.d.mts ADDED
@@ -0,0 +1,5 @@
1
+ //#region src/date.d.ts
2
+ declare function formatRelativeDate(date: Date | string | number, baseDate?: Date): string;
3
+ //#endregion
4
+ export { formatRelativeDate };
5
+ //# sourceMappingURL=date.d.mts.map
package/date.d.mts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.d.mts","names":[],"sources":["../src/date.ts"],"mappings":";iBAqBgB,kBAAA,CACd,IAAA,EAAM,IAAA,oBACN,QAAA,GAAU,IAAA"}
package/date.mjs ADDED
@@ -0,0 +1,48 @@
1
+ //#region src/date.ts
2
+ /**
3
+ * @fileoverview Date formatting utilities
4
+ *
5
+ * Provides date formatting functions for consistent date display across the codebase.
6
+ *
7
+ * @module @od-oneapp/utils/date
8
+ */
9
+ /**
10
+ * Format a date as a relative time string (e.g., "2 hours ago", "yesterday")
11
+ *
12
+ * @param date - The date to format
13
+ * @param baseDate - The base date to compare against (defaults to now)
14
+ * @returns A human-readable relative time string
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * formatRelativeDate(new Date(Date.now() - 3600000)); // "1 hour ago"
19
+ * formatRelativeDate(new Date(Date.now() - 86400000)); // "yesterday"
20
+ * ```
21
+ */
22
+ function formatRelativeDate(date, baseDate = /* @__PURE__ */ new Date()) {
23
+ const d = date instanceof Date ? date : new Date(date);
24
+ const diffMs = baseDate.getTime() - d.getTime();
25
+ const diffSeconds = Math.floor(diffMs / 1e3);
26
+ const diffMinutes = Math.floor(diffSeconds / 60);
27
+ const diffHours = Math.floor(diffMinutes / 60);
28
+ const diffDays = Math.floor(diffHours / 24);
29
+ if (diffSeconds < 60) return "just now";
30
+ if (diffMinutes < 60) return diffMinutes === 1 ? "1 minute ago" : `${diffMinutes} minutes ago`;
31
+ if (diffHours < 24) return diffHours === 1 ? "1 hour ago" : `${diffHours} hours ago`;
32
+ if (diffDays === 1) return "yesterday";
33
+ if (diffDays < 7) return `${diffDays} days ago`;
34
+ if (diffDays < 30) {
35
+ const weeks = Math.floor(diffDays / 7);
36
+ return weeks === 1 ? "1 week ago" : `${weeks} weeks ago`;
37
+ }
38
+ if (diffDays < 365) {
39
+ const months = Math.floor(diffDays / 30);
40
+ return months === 1 ? "1 month ago" : `${months} months ago`;
41
+ }
42
+ const years = Math.floor(diffDays / 365);
43
+ return years === 1 ? "1 year ago" : `${years} years ago`;
44
+ }
45
+
46
+ //#endregion
47
+ export { formatRelativeDate };
48
+ //# sourceMappingURL=date.mjs.map
package/date.mjs.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.mjs","names":[],"sources":["../src/date.ts"],"sourcesContent":["/**\n * @fileoverview Date formatting utilities\n *\n * Provides date formatting functions for consistent date display across the codebase.\n *\n * @module @od-oneapp/utils/date\n */\n\n/**\n * Format a date as a relative time string (e.g., \"2 hours ago\", \"yesterday\")\n *\n * @param date - The date to format\n * @param baseDate - The base date to compare against (defaults to now)\n * @returns A human-readable relative time string\n *\n * @example\n * ```ts\n * formatRelativeDate(new Date(Date.now() - 3600000)); // \"1 hour ago\"\n * formatRelativeDate(new Date(Date.now() - 86400000)); // \"yesterday\"\n * ```\n */\nexport function formatRelativeDate(\n date: Date | string | number,\n baseDate: Date = new Date(),\n): string {\n const d = date instanceof Date ? date : new Date(date);\n const now = baseDate;\n const diffMs = now.getTime() - d.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const diffDays = Math.floor(diffHours / 24);\n\n if (diffSeconds < 60) {\n return 'just now';\n }\n\n if (diffMinutes < 60) {\n return diffMinutes === 1 ? '1 minute ago' : `${diffMinutes} minutes ago`;\n }\n\n if (diffHours < 24) {\n return diffHours === 1 ? '1 hour ago' : `${diffHours} hours ago`;\n }\n\n if (diffDays === 1) {\n return 'yesterday';\n }\n\n if (diffDays < 7) {\n return `${diffDays} days ago`;\n }\n\n if (diffDays < 30) {\n const weeks = Math.floor(diffDays / 7);\n return weeks === 1 ? '1 week ago' : `${weeks} weeks ago`;\n }\n\n if (diffDays < 365) {\n const months = Math.floor(diffDays / 30);\n return months === 1 ? '1 month ago' : `${months} months ago`;\n }\n\n const years = Math.floor(diffDays / 365);\n return years === 1 ? '1 year ago' : `${years} years ago`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,mBACd,MACA,2BAAiB,IAAI,MAAM,EACnB;CACR,MAAM,IAAI,gBAAgB,OAAO,OAAO,IAAI,KAAK,KAAK;CAEtD,MAAM,SADM,SACO,SAAS,GAAG,EAAE,SAAS;CAC1C,MAAM,cAAc,KAAK,MAAM,SAAS,IAAK;CAC7C,MAAM,cAAc,KAAK,MAAM,cAAc,GAAG;CAChD,MAAM,YAAY,KAAK,MAAM,cAAc,GAAG;CAC9C,MAAM,WAAW,KAAK,MAAM,YAAY,GAAG;AAE3C,KAAI,cAAc,GAChB,QAAO;AAGT,KAAI,cAAc,GAChB,QAAO,gBAAgB,IAAI,iBAAiB,GAAG,YAAY;AAG7D,KAAI,YAAY,GACd,QAAO,cAAc,IAAI,eAAe,GAAG,UAAU;AAGvD,KAAI,aAAa,EACf,QAAO;AAGT,KAAI,WAAW,EACb,QAAO,GAAG,SAAS;AAGrB,KAAI,WAAW,IAAI;EACjB,MAAM,QAAQ,KAAK,MAAM,WAAW,EAAE;AACtC,SAAO,UAAU,IAAI,eAAe,GAAG,MAAM;;AAG/C,KAAI,WAAW,KAAK;EAClB,MAAM,SAAS,KAAK,MAAM,WAAW,GAAG;AACxC,SAAO,WAAW,IAAI,gBAAgB,GAAG,OAAO;;CAGlD,MAAM,QAAQ,KAAK,MAAM,WAAW,IAAI;AACxC,QAAO,UAAU,IAAI,eAAe,GAAG,MAAM"}
package/debounce.d.mts ADDED
@@ -0,0 +1,6 @@
1
+ //#region src/debounce.d.ts
2
+ declare function debounce<T extends (...args: unknown[]) => unknown>(fn: T, delay: number): (...args: Parameters<T>) => void;
3
+ declare function throttle<T extends (...args: unknown[]) => unknown>(fn: T, limit: number): (...args: Parameters<T>) => void;
4
+ //#endregion
5
+ export { debounce, throttle };
6
+ //# sourceMappingURL=debounce.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debounce.d.mts","names":[],"sources":["../src/debounce.ts"],"mappings":";iBA8CgB,QAAA,eAAuB,IAAA,wBAAA,CACrC,EAAA,EAAI,CAAA,EACJ,KAAA,eACK,IAAA,EAAM,UAAA,CAAW,CAAA;AAAA,iBA2DR,QAAA,eAAuB,IAAA,wBAAA,CACrC,EAAA,EAAI,CAAA,EACJ,KAAA,eACK,IAAA,EAAM,UAAA,CAAW,CAAA"}
package/debounce.mjs ADDED
@@ -0,0 +1,110 @@
1
+ //#region src/debounce.ts
2
+ /**
3
+ * @fileoverview Debounce and throttle utilities for function execution control.
4
+ *
5
+ * Provides debounce and throttle functions to limit how often functions can fire.
6
+ * Useful for optimizing performance and improving user experience.
7
+ *
8
+ * @module @od-oneapp/utils/debounce
9
+ */
10
+ /**
11
+ * Debounce function to limit how often a function can fire.
12
+ *
13
+ * Why debounce:
14
+ * - Reduces API calls for search inputs (wait for user to stop typing)
15
+ * - Prevents excessive re-renders during rapid state updates
16
+ * - Improves performance for expensive operations (e.g., filtering large datasets)
17
+ * - Better UX: only process final value, not intermediate states
18
+ *
19
+ * Use debounce when: You want the final value after user stops an action
20
+ * Use throttle when: You want periodic values during continuous action
21
+ *
22
+ * @param fn - Function to debounce
23
+ * @param delay - Delay in milliseconds (typical: 150-500ms for UX)
24
+ * @returns Debounced function
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * // Search input: only search after user stops typing
29
+ * const debouncedSearch = debounce((query: string) => {
30
+ * fetchResults(query);
31
+ * }, 300);
32
+ *
33
+ * // Call sequence over 400ms:
34
+ * debouncedSearch('a'); // 0ms: Timer starts
35
+ * debouncedSearch('ab'); // 100ms: Timer resets
36
+ * debouncedSearch('abc'); // 200ms: Timer resets
37
+ * // At 500ms: fetchResults('abc') executes
38
+ * // Result: Only 1 API call with final query
39
+ *
40
+ * // Window resize: recalculate layout after resize stops
41
+ * const debouncedResize = debounce(() => {
42
+ * recalculateLayout();
43
+ * }, 250);
44
+ * window.addEventListener('resize', debouncedResize);
45
+ * ```
46
+ */
47
+ function debounce(fn, delay) {
48
+ let timeoutId = null;
49
+ return function debounced(...args) {
50
+ if (timeoutId !== null) clearTimeout(timeoutId);
51
+ timeoutId = setTimeout(() => {
52
+ fn(...args);
53
+ timeoutId = null;
54
+ }, delay);
55
+ };
56
+ }
57
+ /**
58
+ * Throttle function to ensure a function is called at most once per time period.
59
+ *
60
+ * Why throttle:
61
+ * - Limits execution frequency for continuous events (scroll, mousemove)
62
+ * - Guarantees function fires at regular intervals during activity
63
+ * - Better than debounce for real-time feedback (e.g., scroll position)
64
+ * - Prevents performance degradation from high-frequency events
65
+ *
66
+ * Use throttle when: You want periodic updates during continuous action
67
+ * Use debounce when: You only care about the final state after action stops
68
+ *
69
+ * @param fn - Function to throttle
70
+ * @param limit - Minimum time in milliseconds between calls (typical: 100-250ms)
71
+ * @returns Throttled function
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * // Scroll position tracking: update every 100ms while scrolling
76
+ * const throttledScroll = throttle(() => {
77
+ * const position = window.scrollY;
78
+ * updateScrollIndicator(position);
79
+ * }, 100);
80
+ * window.addEventListener('scroll', throttledScroll);
81
+ * // Result: Updates 10x per second during scroll, not 100x
82
+ *
83
+ * // Mouse move tracking for drag operations
84
+ * const throttledMouseMove = throttle((e: MouseEvent) => {
85
+ * updateDragPosition(e.clientX, e.clientY);
86
+ * }, 16); // ~60fps
87
+ * element.addEventListener('mousemove', throttledMouseMove);
88
+ *
89
+ * // API polling: check status every 5 seconds max
90
+ * const throttledPoll = throttle(() => {
91
+ * checkStatus();
92
+ * }, 5000);
93
+ * ```
94
+ */
95
+ function throttle(fn, limit) {
96
+ let inThrottle = false;
97
+ return function throttled(...args) {
98
+ if (!inThrottle) {
99
+ fn(...args);
100
+ inThrottle = true;
101
+ setTimeout(() => {
102
+ inThrottle = false;
103
+ }, limit);
104
+ }
105
+ };
106
+ }
107
+
108
+ //#endregion
109
+ export { debounce, throttle };
110
+ //# sourceMappingURL=debounce.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debounce.mjs","names":[],"sources":["../src/debounce.ts"],"sourcesContent":["/**\n * @fileoverview Debounce and throttle utilities for function execution control.\n *\n * Provides debounce and throttle functions to limit how often functions can fire.\n * Useful for optimizing performance and improving user experience.\n *\n * @module @od-oneapp/utils/debounce\n */\n\n/**\n * Debounce function to limit how often a function can fire.\n *\n * Why debounce:\n * - Reduces API calls for search inputs (wait for user to stop typing)\n * - Prevents excessive re-renders during rapid state updates\n * - Improves performance for expensive operations (e.g., filtering large datasets)\n * - Better UX: only process final value, not intermediate states\n *\n * Use debounce when: You want the final value after user stops an action\n * Use throttle when: You want periodic values during continuous action\n *\n * @param fn - Function to debounce\n * @param delay - Delay in milliseconds (typical: 150-500ms for UX)\n * @returns Debounced function\n *\n * @example\n * ```ts\n * // Search input: only search after user stops typing\n * const debouncedSearch = debounce((query: string) => {\n * fetchResults(query);\n * }, 300);\n *\n * // Call sequence over 400ms:\n * debouncedSearch('a'); // 0ms: Timer starts\n * debouncedSearch('ab'); // 100ms: Timer resets\n * debouncedSearch('abc'); // 200ms: Timer resets\n * // At 500ms: fetchResults('abc') executes\n * // Result: Only 1 API call with final query\n *\n * // Window resize: recalculate layout after resize stops\n * const debouncedResize = debounce(() => {\n * recalculateLayout();\n * }, 250);\n * window.addEventListener('resize', debouncedResize);\n * ```\n */\nexport function debounce<T extends (...args: unknown[]) => unknown>(\n fn: T,\n delay: number,\n): (...args: Parameters<T>) => void {\n // Store timeout ID to cancel pending executions\n // Using ReturnType<typeof setTimeout> for cross-platform compatibility (Node.js vs Browser)\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n return function debounced(...args: Parameters<T>) {\n // Cancel previous timeout if exists\n // This is the key behavior: each call resets the timer\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n\n // Schedule new execution after delay\n // Only executes if no new calls come in during delay period\n timeoutId = setTimeout(() => {\n fn(...args);\n timeoutId = null; // Clear reference for memory efficiency\n }, delay);\n };\n}\n\n/**\n * Throttle function to ensure a function is called at most once per time period.\n *\n * Why throttle:\n * - Limits execution frequency for continuous events (scroll, mousemove)\n * - Guarantees function fires at regular intervals during activity\n * - Better than debounce for real-time feedback (e.g., scroll position)\n * - Prevents performance degradation from high-frequency events\n *\n * Use throttle when: You want periodic updates during continuous action\n * Use debounce when: You only care about the final state after action stops\n *\n * @param fn - Function to throttle\n * @param limit - Minimum time in milliseconds between calls (typical: 100-250ms)\n * @returns Throttled function\n *\n * @example\n * ```ts\n * // Scroll position tracking: update every 100ms while scrolling\n * const throttledScroll = throttle(() => {\n * const position = window.scrollY;\n * updateScrollIndicator(position);\n * }, 100);\n * window.addEventListener('scroll', throttledScroll);\n * // Result: Updates 10x per second during scroll, not 100x\n *\n * // Mouse move tracking for drag operations\n * const throttledMouseMove = throttle((e: MouseEvent) => {\n * updateDragPosition(e.clientX, e.clientY);\n * }, 16); // ~60fps\n * element.addEventListener('mousemove', throttledMouseMove);\n *\n * // API polling: check status every 5 seconds max\n * const throttledPoll = throttle(() => {\n * checkStatus();\n * }, 5000);\n * ```\n */\nexport function throttle<T extends (...args: unknown[]) => unknown>(\n fn: T,\n limit: number,\n): (...args: Parameters<T>) => void {\n // Flag to track if we're in throttle period\n // When true, calls are ignored until period ends\n let inThrottle = false;\n\n return function throttled(...args: Parameters<T>) {\n // Only execute if not currently in throttle period\n if (!inThrottle) {\n fn(...args); // Execute immediately on first call\n inThrottle = true; // Enter throttle period\n\n // Exit throttle period after limit milliseconds\n // This ensures minimum time between executions\n setTimeout(() => {\n inThrottle = false;\n }, limit);\n }\n // If inThrottle is true, this call is silently ignored\n // This is the key difference from debounce\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,SAAgB,SACd,IACA,OACkC;CAGlC,IAAI,YAAkD;AAEtD,QAAO,SAAS,UAAU,GAAG,MAAqB;AAGhD,MAAI,cAAc,KAChB,cAAa,UAAU;AAKzB,cAAY,iBAAiB;AAC3B,MAAG,GAAG,KAAK;AACX,eAAY;KACX,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0Cb,SAAgB,SACd,IACA,OACkC;CAGlC,IAAI,aAAa;AAEjB,QAAO,SAAS,UAAU,GAAG,MAAqB;AAEhD,MAAI,CAAC,YAAY;AACf,MAAG,GAAG,KAAK;AACX,gBAAa;AAIb,oBAAiB;AACf,iBAAa;MACZ,MAAM"}
package/index.d.mts ADDED
@@ -0,0 +1,4 @@
1
+ import { cn } from "./cn.mjs";
2
+ import { formatRelativeDate } from "./date.mjs";
3
+ import { debounce, throttle } from "./debounce.mjs";
4
+ export { cn, debounce, formatRelativeDate, throttle };
package/index.mjs ADDED
@@ -0,0 +1,5 @@
1
+ import { cn } from "./cn.mjs";
2
+ import { formatRelativeDate } from "./date.mjs";
3
+ import { debounce, throttle } from "./debounce.mjs";
4
+
5
+ export { cn, debounce, formatRelativeDate, throttle };
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@od-oneapp/utils",
3
+ "version": "2026.2.2001-canary.1",
4
+ "description": "Shared utility functions",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "import": "./index.mjs",
10
+ "types": "./index.d.mts"
11
+ }
12
+ },
13
+ "peerDependenciesMeta": {},
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/OneDigital-Product/monorepo.git",
17
+ "directory": "platform/packages/utils"
18
+ },
19
+ "license": "UNLICENSED",
20
+ "publishConfig": {
21
+ "access": "restricted",
22
+ "registry": "https://registry.npmjs.org/"
23
+ }
24
+ }