🚀 DAY 5 OF LAUNCH WEEK: Introducing Socket Firewall Enterprise.Learn more →
Socket
Book a DemoInstallSign in
Socket

@cyca/utils

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cyca/utils

Personal JS utils I use in the daily

latest
Source
npmnpm
Version
0.1.1
Version published
Maintainers
1
Created
Source

@cyca/utils

A collection of utility functions and hooks for my TypeScript/JavaScript projects.

Installation

npm install @cyca/utils
# or
pnpm add @cyca/utils
# or
bun add @cyca/utils

Table of Contents

  • Core Utilities
  • Deep Omit
  • Jotai Utilities
  • Event Emitter (Mitt)
  • React Hooks

Core Utilities

invariant(condition, message)

Throws an error if the condition is falsey. Inspired by tiny-invariant.

import { invariant } from '@cyca/utils'

invariant(typeof value === 'string', 'value must be a string')

Parameters:

  • condition: any - The condition to check
  • message: string | (() => string) - The message to throw (or a callback to generate the message)

Throws: InvariantError if condition is falsey

invariantResponse(condition, message, responseInit?)

Throws a 400 Response if the condition is falsey. Useful for server-side validation.

import { invariantResponse } from '@cyca/utils'

invariantResponse(typeof value === 'string', 'value must be a string')

Parameters:

  • condition: any - The condition to check
  • message: string | (() => string) - The message to throw
  • responseInit?: ResponseInit - Additional response init options

Throws: Response if condition is falsey

isValidHttpUrl(string)

Checks if a string is a valid HTTP URL.

import { isValidHttpUrl } from '@cyca/utils'

if (isValidHttpUrl('https://example.com')) {
  // valid URL
}

delay(ms, value?)

Promise wrapper around setTimeout.

import { delay } from '@cyca/utils'

await delay(1000) // wait 1 second
const result = await delay(500, 'value') // wait 500ms and return 'value'

Parameters:

  • ms: number - Milliseconds to wait
  • value?: T - Optional value to resolve with

Returns: Promise<unknown>

prependHttp(url, options?)

Prepends http:// or https:// to a URL if it doesn't already have a protocol.

import { prependHttp } from '@cyca/utils'

prependHttp('example.com') // 'http://example.com'
prependHttp('example.com', { https: true }) // 'https://example.com'

Parameters:

  • url: string - The URL to prepend
  • options?: { https?: boolean } - Options object

Returns: string

getUrlImageSize(url)

Gets the width and height of an image from a URL.

import { getUrlImageSize } from '@cyca/utils'

const { width, height } = await getUrlImageSize('https://example.com/image.jpg')

Returns: Promise<{ width: number; height: number }>

toBase64(str)

Converts a string to base64.

import { toBase64 } from '@cyca/utils'

const encoded = toBase64('hello world')

escapeRegExp(string)

Escapes special characters in a string for use in a regular expression.

import { escapeRegExp } from '@cyca/utils'

const escaped = escapeRegExp('hello.world')

higlightWords(textToHighlight, searchTerm, options?)

Highlights words in text that match a search term.

import { higlightWords } from '@cyca/utils'

const result = higlightWords('Hello world', 'world', {
  caseSensitive: false,
  mark: (part, matched) => matched ? `<mark>${part}</mark>` : part
})

Parameters:

  • textToHighlight: string - The text to search in
  • searchTerm: string - The term to search for
  • options? - Configuration object
    • caseSensitive?: boolean - Whether to match case
    • mark?: (part: string, matched: boolean) => T - Function to transform matched/unmatched parts
    • append?: (accum: T, part: P) => T | null - Function to accumulate results

debounce(func, timeout)

Creates a debounced function that delays invoking func until after timeout milliseconds.

import { debounce } from '@cyca/utils'

const debouncedFn = debounce(() => console.log('called'), 300)

debounceAnimationFrame(func)

Creates a debounced function that uses requestAnimationFrame.

import { debounceAnimationFrame } from '@cyca/utils'

const debouncedFn = debounceAnimationFrame(() => console.log('called'))

noop()

A no-op function that returns null.

import { noop } from '@cyca/utils'

const callback = noop()

Deep Omit

deepOmit(object, path)

Deeply omits a property from an object using a path array.

import { deepOmit } from '@cyca/utils/deep-omit'

const obj = { a: { b: { c: 1, d: 2 } } }
const result = deepOmit(obj, ['a', 'b', 'c'])
// result: { a: { b: { d: 2 } } }

Can also be used in curried form:

const omitPath = deepOmit(['a', 'b', 'c'])
const result = omitPath(obj)

Type-safe: The path is type-checked against the object structure.

Jotai Utilities

useAtomCallback(callback, options?)

A custom version of Jotai's useAtomCallback that keeps the latest callback identity.

import { useAtomCallback } from '@cyca/utils/jotai'

const handleClick = useAtomCallback((get, set) => {
  const value = get(someAtom)
  set(anotherAtom, value + 1)
})

Parameters:

  • callback: (get: Getter, set: Setter, ...args: Args) => Result - The callback function
  • options?: Options - Jotai store options

Returns: A memoized callback function

useSelectAtom(atom, selector)

Selects a derived value from an atom using a selector function.

import { useSelectAtom } from '@cyca/utils/jotai'

const userName = useSelectAtom(userAtom, (user) => user.name)

Parameters:

  • atom: Atom<V> - The atom to read from
  • selector: (v: V) => S - Function to derive value

Returns: The selected value

withSnapshotHistory(targetAtom, limit?)

Wraps an atom with undo/redo history functionality.

import { withSnapshotHistory, COMMIT, UNDO, REDO, RESET } from '@cyca/utils/jotai'

const countAtom = atom(0)
const historyAtom = withSnapshotHistory(countAtom, 10)

// In a component:
const [{ value, previous, canUndo, canRedo }, dispatch] = useAtom(historyAtom)

// Update the value (doesn't create history entry)
dispatch(5)

// Commit to history
dispatch(COMMIT)

// Undo/redo
dispatch(UNDO)
dispatch(REDO)

// Reset history
dispatch(RESET)

Parameters:

  • targetAtom: AnyWritableAtom<T> - The atom to track
  • limit?: number - Maximum history entries (default: unlimited)

Actions:

  • COMMIT - Record current value to history
  • UNDO - Move back one step
  • REDO - Move forward one step
  • RESET - Clear all history
  • SetStateAction<T> - Update value without creating history

init(callback, store?)

Initializes state or side effects when the store is created.

import { init } from '@cyca/utils/jotai'

const cleanup = init((get, set, store) => {
  // Initialize something
  set(someAtom, initialValue)
  
  // Return cleanup function
  return () => {
    // Cleanup
  }
})

Parameters:

  • callback: (get: Getter, set: Setter, store: Store) => void | (() => void) - Initialization function
  • store?: Store - Jotai store (uses default if not provided)

Returns: Cleanup function if provided by callback

Event Emitter (Mitt)

mitt(all?)

Creates a tiny event emitter.

import { mitt } from '@cyca/utils/mitt'

type Events = {
  'user:login': { id: string }
  'user:logout': void
}

const emitter = mitt<Events>()

emitter.on('user:login', (data) => {
  console.log('User logged in:', data.id)
})

emitter.emit('user:login', { id: '123' })

Parameters:

  • all?: EventHandlerMap<Events> - Optional initial handlers

Returns: Emitter<Events> with methods:

  • on(type, handler) - Subscribe to event
  • off(type, handler) - Unsubscribe from event
  • emit(type, event) - Emit event
  • all - Map of all handlers

bind(emitter, event, listener)

Binds a listener to an event and returns an unbind function.

import { mitt, bind } from '@cyca/utils/mitt'

const emitter = mitt()
const unbind = bind(emitter, 'event', (data) => {
  console.log(data)
})

// Later...
unbind()

Returns: () => void - Unbind function

bindAll(emitter, listeners)

Binds multiple listeners at once and returns an unbind function.

import { mitt, bindAll } from '@cyca/utils/mitt'

type Events = {
  'login': { id: string }
  'logout': void
}

const emitter = mitt<Events>()
const unbind = bindAll(emitter, {
  login: (data) => console.log('Login:', data.id),
  logout: () => console.log('Logout')
})

// Later...
unbind()

Returns: () => void - Unbind function that removes all listeners

React Hooks

useMediaQuery(query)

Hook to match media queries.

import { useMediaQuery } from '@cyca/utils/react'

const isMobile = useMediaQuery('(max-width: 768px)')

Returns: boolean | undefined - undefined during SSR

useClientLayoutEffect

Use useEffect during SSR and useLayoutEffect in the browser to avoid warnings.

import { useClientLayoutEffect } from '@cyca/utils/react'

useClientLayoutEffect(() => {
  // Safe to use in SSR
}, [])

useConstant(input)

Creates a value exactly once. Unlike useMemo, this is guaranteed.

import { useConstant } from '@cyca/utils/react'

const expensiveObject = useConstant(() => createExpensiveObject())

usePreviousEffect(effect, inputs)

Runs an effect with access to previous dependency values.

import { usePreviousEffect } from '@cyca/utils/react'

usePreviousEffect(([prevCount]) => {
  console.log(`Count changed from ${prevCount} to ${count}`)
}, [count])

useHasChangedEffect(effect, deps, equal?)

Runs an effect only when a dependency has changed.

import { useHasChangedEffect } from '@cyca/utils/react'

useHasChangedEffect(() => {
  console.log('User changed')
}, [user], (a, b) => a.id === b.id)

usePreviousValue(value)

Returns the previous value from the last render.

import { usePreviousValue } from '@cyca/utils/react'

const previousCount = usePreviousValue(count)

useHasChanged(value)

Returns true if the value has changed since the last render.

import { useHasChanged } from '@cyca/utils/react'

const hasChanged = useHasChanged(count)

useEvent(callback)

Creates an always-stable function identity. Easier to use than useCallback.

import { useEvent } from '@cyca/utils/react'

const handleClick = useEvent(() => {
  console.log(count) // Always has latest value
})

useLatest(value)

A React helper hook for storing latest value in ref object (updated in useLayoutEffect's callback). Similar to useEvent()

import { useLatest } from '@cyca/utils/react'

const valRef = useLatest(value)

// latest val
valRef.current

useAsyncCallback()

Returns a handler with pending states for async operations.

import { useAsyncCallback } from '@cyca/utils/react'

const [{ pending, success, error }, wrapAsync] = useAsyncCallback()

const handleSubmit = wrapAsync(async () => {
  await api.submit()
})

if (pending) return <Spinner />
if (error) return <Error error={error} />

Returns: [{ pending: boolean, success: boolean, error: Error | null }, wrap]

useEffectOnce(effectCb)

Runs an effect only once, even in strict mode.

import { useEffectOnce } from '@cyca/utils/react'

useEffectOnce(() => {
  console.log('Runs only once')
})

useDeepMemo(memoFn, key)

Memoizes a value using deep equality comparison.

import { useDeepMemo } from '@cyca/utils/react'

const memoizedValue = useDeepMemo(() => {
  return computeExpensiveValue(obj)
}, [obj])

useDeepMemoEffect(callback, deps)

Like useEffect but with deep equality comparison for dependencies.

import { useDeepMemoEffect } from '@cyca/utils/react'

useDeepMemoEffect(() => {
  console.log('Object deeply changed')
}, [complexObject])

useForceUpdate()

Returns a function to force a re-render.

import { useForceUpdate } from '@cyca/utils/react'

const [key, forceUpdate] = useForceUpdate()

// Later...
forceUpdate() // Forces re-render

useIntersectionCallback(callback, options?)

Detects element visibility using Intersection Observer.

import { useIntersectionCallback } from '@cyca/utils/react'

const ref = useIntersectionCallback((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('Element is visible')
    }
  })
}, { threshold: 0.5 })

return <div ref={ref}>Content</div>

useIsIntersecting(options?)

Returns a boolean indicating if element is intersecting and a ref callback.

import { useIsIntersecting } from '@cyca/utils/react'

const [isVisible, ref] = useIsIntersecting({ threshold: 0.5 })

return <div ref={ref}>{isVisible ? 'Visible' : 'Hidden'}</div>

useIsVisible, useInView

Aliases for useIsIntersecting.

useFocusElementOnVisible()

Automatically focuses an element when it becomes visible.

import { useFocusElementOnVisible } from '@cyca/utils/react'

const ref = useFocusElementOnVisible()

return <input ref={ref} />

useCounter(initialValue?)

A simple counter abstraction.

import { useCounter } from '@cyca/utils/react'

const { count, increment, decrement, reset, setCount } = useCounter(0)

useSuspendAfterMount(callback)

Defers a suspense-triggering function until after mount.

import { useSuspendAfterMount } from '@cyca/utils/react'

const data = useSuspendAfterMount(() => fetchData())

useLazyRef(fn)

A wrapper for useRef with lazy initialization.

import { useLazyRef } from '@cyca/utils/react'

const ref = useLazyRef(() => new ExpensiveClass())

useInterval(callback, delay)

Runs a callback at a regular interval.

import { useInterval } from '@cyca/utils/react'

useInterval(() => {
  console.log('Tick')
}, 1000)

useAnimationFrame(cb, deps)

Runs a callback on every animation frame.

import { useAnimationFrame } from '@cyca/utils/react'

useAnimationFrame(({ time, delta }) => {
  // Animation logic
}, [])

useStyleMeasure(prefix?)

Dynamically measures element size and updates CSS custom properties.

import { useStyleMeasure } from '@cyca/utils/react'

const ref = useStyleMeasure('box')

// Sets --box-width and --box-height CSS variables
return <div ref={ref}>Content</div>

withHook(useHook)

Converts a React hook into a render prop component.

import { withHook } from '@cyca/utils/react'

const WithCounter = withHook(useCounter)

<WithCounter args={[0]}>
  {({ count, increment }) => (
    <button onClick={increment}>{count}</button>
  )}
</WithCounter>

withSuspense(Component, Fallback?)

Wraps a component with Suspense boundary.

import { withSuspense } from '@cyca/utils/react'

const UserProfile = withSuspense(
  UserProfileComponent,
  () => <Spinner />
)

License

MIT

Keywords

react

FAQs

Package last updated on 12 Oct 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts