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

@avsbhq/vue

v1.0.0

Published

Vue 3 SDK for the [A vs B](https://app.avsb.cloud) platform.

Readme

@avsbhq/vue

Vue 3 SDK for the A vs B platform.

Drop an <AvsbProvider> at the top of your component tree (or call app.use(AvsbPlugin)) and read feature flags from anywhere using composables. Built on @avsbhq/browser; components re-render automatically when flag values change.


1. Install

npm install @avsbhq/vue

Vue 3.4 or later is required as a peer dependency. Pinia integration is optional — install pinia only if you use useAvsbStore.


2. Quickstart

<!-- App.vue -->
<script setup lang="ts">
import { AvsbProvider } from '@avsbhq/vue'
</script>

<template>
  <AvsbProvider :sdk-key="sdkKey" :context="{ kind: 'user', key: userId }">
    <RouterView />
  </AvsbProvider>
</template>
<!-- CheckoutButton.vue -->
<script setup lang="ts">
import { useFlag, useTrack } from '@avsbhq/vue'

const newCheckout = useFlag('new-checkout-flow', false)
const track = useTrack()
</script>

<template>
  <button @click="track('checkout_clicked')">
    {{ newCheckout.value ? 'Start checkout (new)' : 'Buy now' }}
  </button>
</template>

3. SDK keys

Get a client SDK key from your A vs B project's Environments page.

Client SDK keys are safe to embed in browser bundles — store them in your framework's public env variable:

VITE_AVSB_SDK_KEY=sdk-...
// main.ts
const key = import.meta.env.VITE_AVSB_SDK_KEY

Server SDK keys (used by @avsbhq/node) must never be exposed to the browser.


4. Identity — identify, updateAttributes, alias, reset

Provider-level context

Pass a context object to <AvsbProvider> at bootstrap. This is the evaluation context used for all flag reads until you call identify.

<AvsbProvider :sdk-key="key" :context="{ kind: 'user', key: userId, plan: 'pro' }">

useIdentify

Replace the current context at runtime (e.g. after sign-in):

import { useIdentify } from '@avsbhq/vue'

const identify = useIdentify()

function onSignIn(user: User) {
  identify({ kind: 'user', key: user.id, email: user.email, plan: user.plan })
}

The function is stable — it will not change reference between renders.

useAlias

Record that an anonymous visitor and an identified user are the same person. Call this once at sign-in:

import { useAlias } from '@avsbhq/vue'

const alias = useAlias()

async function onSignIn(anonKey: string, userId: string) {
  await alias(
    { kind: 'user', key: anonKey },
    { kind: 'user', key: userId }
  )
}

reset

Call client.reset() via useAvsbClient() to clear the current identity and return to the anonymous state.


5. Multi-context

A vs B supports multi-context evaluation — evaluating a flag for both a user and an organisation simultaneously:

identify({
  kind: 'multi',
  user: { kind: 'user', key: 'u_123', plan: 'pro' },
  organization: { kind: 'organization', key: 'org_456', tier: 'enterprise' },
})

6. Reading flags

useFlag — full Flag object

import { useFlag } from '@avsbhq/vue'

const checkoutFlag = useFlag('new-checkout-flow', false)
// checkoutFlag is ComputedRef<Flag<boolean>>

// In template:
// checkoutFlag.value.value        → the boolean value
// checkoutFlag.value.isEnabled()  → true if rule-served AND truthy
// checkoutFlag.value.variationKey → 'on' | 'off' | ...
// checkoutFlag.value.source       → 'rule' | 'override' | 'not_found' | ...

A default value is always required. It is returned until the SDK is ready and whenever the flag is not found.

useFlagValue — raw value shortcut

import { useFlagValue } from '@avsbhq/vue'

const showBanner = useFlagValue('promo-banner', false)
// showBanner is ComputedRef<boolean>

Typed variants

Use typed composables when you want a runtime type-safety check against the datafile's declared flag type:

import { useBoolFlag, useStringFlag, useNumberFlag, useJsonFlag } from '@avsbhq/vue'

const darkMode    = useBoolFlag('dark-mode', false)
const theme       = useStringFlag('theme', 'light')
const maxItems    = useNumberFlag('max-items', 10)
const config      = useJsonFlag<{ timeout: number }>('api-config', { timeout: 5000 })

All return ComputedRef<Flag<T>>.

Reactive flag key

useFlag (and useFlagValue) accept a Ref<string> or ComputedRef<string> as the key — the subscription updates automatically when the key changes:

const selectedFlag = ref('feature-a')
const flag = useFlag(selectedFlag, false)

useAllFlags — all evaluated flags

import { useAllFlags } from '@avsbhq/vue'

const flags = useAllFlags()
// flags is ComputedRef<Record<string, Flag>>
// Re-computes on any flagChange event.

Prefer individual useFlag composables in most components — useAllFlags triggers on any flag change and is best suited for debug panels.


7. Tracking events

import { useTrack } from '@avsbhq/vue'

const track = useTrack()

function onClick() {
  track('button_clicked', { location: 'header', variant: 'A' })
}

The function is defined once in setup — it is safe to use as an event handler without wrapping in a closure.


8. Error handling

Provider-level error state

<AvsbProvider> exposes a status that transitions to 'error' if onReady() rejects or if the client emits an 'error' event. Use useFlagReady to gate rendering:

<script setup lang="ts">
import { useFlagReady } from '@avsbhq/vue'
const ready = useFlagReady()
</script>

<template>
  <div v-if="!ready">Loading flags...</div>
  <MyApp v-else />
</template>

Custom logger

Pass a logger to suppress or redirect SDK output:

app.use(AvsbPlugin, {
  sdkKey: '...',
  logger: {
    debug: (msg, ...args) => myLogger.debug(msg, ...args),
    warn:  (msg, ...args) => myLogger.warn(msg, ...args),
    error: (msg, ...args) => myLogger.error(msg, ...args),
  },
})

9. SSR / Nuxt

For SSR, pre-fetch the datafile server-side and pass it as the bootstrap option to skip the initial network round-trip on the client:

// server.ts
import { AvsbClient } from '@avsbhq/browser'

const client = new AvsbClient({ sdkKey: '...', bootstrap: serverDatafile })
<!-- App.vue — client side -->
<AvsbProvider :sdk-key="sdkKey" :bootstrap="bootstrapDatafile">
  <NuxtPage />
</AvsbProvider>

Flag composables return a not_found sentinel during the hydration window so SSR output matches the client's initial render.


10. Graceful shutdown

When using <AvsbProvider> in Mode A (sdkKey prop), the client is closed automatically on component unmount. This flushes any queued events.

When using Mode B (passing a pre-built client prop), you own the lifecycle:

onUnmounted(async () => {
  await client.flush()
  await client.close()
})

The AvsbPlugin (Mode A) proxies app.unmount to close the client when the Vue app tears down.


11. Testing

Inject a mock context directly via provide — no need to mount the full provider:

import { defineComponent, h, provide } from 'vue'
import { mount } from '@vue/test-utils'
import { vi } from 'vitest'
import { AvsbInjectionKey } from '@avsbhq/vue'
import { notFoundFlag, createFlag } from '@avsbhq/core'

function makeMockClient() {
  return {
    subscribe: vi.fn((_key, cb) => { /* store cb */ return () => {} }),
    getSnapshot: vi.fn((key, def) => notFoundFlag(def, 'no data')),
    on: vi.fn(() => () => {}),
    onReady: vi.fn(() => Promise.resolve()),
    close: vi.fn(() => Promise.resolve()),
    track: vi.fn(),
    identify: vi.fn(),
    alias: vi.fn(() => Promise.resolve()),
    reset: vi.fn(),
  }
}

const Wrapper = defineComponent({
  setup() {
    provide(AvsbInjectionKey, {
      client: makeMockClient(),
      status: 'ready',
    })
  },
  render() {
    return h(MyComponent)
  },
})

const wrapper = mount(Wrapper)

Use createFlag() from @avsbhq/core to build typed flag fixtures:

import { createFlag } from '@avsbhq/core'

const FLAG_ON = createFlag<boolean>({
  value: true,
  variationKey: 'on',
  source: 'rule',
  ruleId: 'r1',
  ruleType: 'ab_test',
  reasons: ['matched rule'],
})

12. Migration from LaunchDarkly

| LaunchDarkly (React SDK) | @avsbhq/vue equivalent | |---------------------------------------|----------------------------------------------------| | <LDProvider clientSideID="..."> | <AvsbProvider sdkKey="..."> | | useLDClient() | useAvsbClient() | | useFlags() | useAllFlags() | | useLDFlag('key', default) | useFlag('key', default).value | | ldClient.identify(context) | useIdentify()(context) | | ldClient.track('event') | useTrack()('event') | | ldClient.variation('key', default) | useAvsbClient()?.getFlag('key', default) |

Key differences:

  • useFlag returns a Flag<T> object, not a raw T. Access .value for the primitive or .isEnabled() for a boolean gate. This gives you the evaluation metadata (source, variationKey, reasons) without a second call.
  • All getFlag variants require an explicit defaultValue. There is no untyped .variation().
  • Multi-context is a first-class concept — no adapter required.