npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kontsedal/olas-vue

v1.0.1

Published

Olas Vue adapter — olasPlugin, useRoot, useValue, useQuery, useInfiniteQuery, useField, useMutation.

Readme

@kontsedal/olas-vue

The Vue 3 adapter for Olas. It turns Olas signals into Vue refs. The root is built outside Vue, once, and app.use(olasPlugin(root)) hands it to every component. Vue does not own a controller's lifetime, so a component that unmounts drops its subscriptions and nothing else.

Install

pnpm add @kontsedal/olas-vue @kontsedal/olas-core @preact/signals-core vue

vue >= 3.4 is a peer dependency.

Example

// counter.ts: the controller knows nothing about Vue
import { defineController, signal } from '@kontsedal/olas-core'

export const counter = defineController(() => {
  const count = signal(0)
  return { count, inc: () => count.set(count.peek() + 1) }
})
// main.ts: build the root once, then install it
import { createRoot } from '@kontsedal/olas-core'
import { olasPlugin } from '@kontsedal/olas-vue'
import { createApp } from 'vue'
import App from './App.vue'
import { counter } from './counter'

export const root = createRoot(counter, { deps: {} })
createApp(App).use(olasPlugin(root)).mount('#app')

// Register the root's type once, so `useRoot()` needs no type argument.
declare module '@kontsedal/olas-vue' {
  interface Register {
    root: typeof root
  }
}
<!-- App.vue: components read signals as refs -->
<script setup lang="ts">
import { useRoot, useValue } from '@kontsedal/olas-vue'

const api = useRoot()
const count = useValue(api.count)
</script>

<template>
  <button @click="api.inc">{{ count }}</button>
</template>

API

| Export | Purpose | |---|---| | olasPlugin(root) | The Vue plugin for app.use. It provides the root to the whole app. | | useRoot<Api>() | The root's api. Register types it; a type argument is an unchecked cast. Throws when no plugin provided a root, and when called outside a component's setup(). | | useValue(signal, { isEqual? }) | A read-only ref over any ReadSignal: a signal, a computed, a Field, a Form or a FieldArray. While isEqual calls a new value equal to the one the ref last returned, the ref keeps returning that one, as React's useValue does. | | useQuery(subscription) | One ref per AsyncState signal (data, status, isLoading, isFetching and the rest), plus refetch, reset and cancel. | | useInfiniteQuery(subscription) | useQuery's refs, plus pages, flat, the paging flags, fetchNextPage and fetchPreviousPage. | | useField(field) | A writable value ref for v-model, refs for the validation state, and the field's actions. | | useMutation(mutation) | Refs for data, error, status, isPending and lastVariables, plus mutate, run and reset. |

Register and RegisteredApi type useRoot(). Each hook's return type is exported as Use…Return, and Refs<T> is the shape they return their state in.

How it behaves

  • A read does not lag a write. A ref's getter reads the signal's current value, so code that writes a signal and then reads the ref sees the new value. That holds inside a batch too, and useField's value reads the same way.
  • Vue tracks each ref on its own. A template that reads data does not re-render when isFetching flips, because each field is a separate ref.
  • Subscriptions end with the component. The adapter ties each one to the current effect scope with onScopeDispose. Called outside any scope, a hook still returns a working ref, but nothing ends its subscription. A development build warns about it once per hook, naming the hook. To use a hook outside a component, call it inside effectScope().run() and call stop() on the scope when you are done.
  • A server render does not subscribe. Vue never stops a component's effect scope on the server, so a subscription made there would outlive the request. During renderToString, a hook's refs read each signal's current value and subscribe to nothing.
  • mutate is fire-and-forget. It returns nothing, and a failure lands on error and status. The adapter catches the rejection, so it does not become an unhandled one. run returns the promise, and the caller owns its rejection.
  • The refs are read-only. useValue ignores an assignment. Write through the signal, or through useField's value, which calls field.set.
  • v-model binds a field's whole value. v-model="value" assigns the ref, which calls field.set. On an object-valued field, v-model="value.name" assigns name on the field's own value object instead: nothing calls field.set and no validator runs. The field keeps its baseline as a copy of its own, so reset() still restores. Bind a writable computed that sets a new object, computed({ get: () => value.value.name, set: (name) => set({ ...value.value, name }) }), or bind a Form's leaf field.

Testing

A controller tests without Vue, through createTestController from @kontsedal/olas-core/testing. examples/vue-tasks shows both halves: controller tests in plain Node, and one mounted run of the real app. packages/integration/tests/adapter-parity/ runs the same scenarios through this adapter, React, preact/compat and Svelte, and asserts the same DOM.