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

@ouidesigner/ouider-device

v0.0.7

Published

Typed device feature modules for the OUID bridge.

Readme

OUIDer Device

@ouidesigner/ouider-device adds typed, modular device APIs on top of the OUID bridge. Importing the package installs device modules on the default OUID instance without changing the low-level bridge behavior.

import '@ouidesigner/ouider-device'

const photo = await OUID.camera.takePicture({ quality: 80 })
const samePhoto = await OUID.camera().takePicture()
const file = await OUID.filePicker.pickFile({ mimeTypes: ['application/pdf'] })
const images = await OUID.imagePicker.pickImages({ maxWidth: 1200, includeDataUrl: true })

await OUID.fileSystem.writeText('notes/today.txt', 'Hello from OUIDDevice')
const note = await OUID.fileSystem.readText('notes/today.txt')
const entries = await OUID.fileSystem.readdir('notes')

const camera = await OUID.camera.createSession({ width: 320, height: 240, fps: 8, forScan: true })
await camera?.setTorch(true)
await camera?.setZoom(2)
const offQr = await camera?.onQRCode(result => console.log(result.rawValue))
const offFrame = await camera?.onFrame((frame) => {
  canvasContext.drawImage(dataUrlToImage(frame.dataUrl), 0, 0)
})
await camera?.start()
const savedImage = await camera?.saveFrame()
await camera?.startRecording()
const video = await camera?.stopRecording()
await offFrame?.()
await offQr?.()
await camera?.close()

const stopGyroscope = await OUID.gyroscope.listen((reading) => {
  console.log(reading.x, reading.y, reading.z)
})

const heading = await OUID.compass.read()
const auth = await OUID.biometry.authenticate({ title: 'Unlock', reason: 'Confirm your identity' })
const offBluetooth = await OUID.bluetooth.ble.onDeviceFound(device => console.log(device.id, device.name))
await OUID.bluetooth.ble.startScan()
const offBeacon = await OUID.bluetooth.beacon.onFound(beacon => console.log(beacon.type, beacon.rssi))
await OUID.bluetooth.beacon.startScan()
const offNfc = await OUID.nfc.onTag(tag => console.log(tag.id, tag.techTypes))
await OUID.nfc.startScan({ techs: ['ndef', 'nfcisodep'] })
const ndef = await OUID.nfc.ndef.read()
const apdu = await OUID.nfc.nfcisodep.transceive({ hex: '00A4040000' })
const offWifi = await OUID.wifi.onChange(state => console.log(state.connected))
const networks = await OUID.wifi.scanResults()
const position = await OUID.location.current()
const memory = await OUID.memory.read()
const qr = await OUID.qrScan.scan({ timeoutMs: 15000 })
await OUID.keyboard.hide()
await OUID.screen.setCaptureProtection(true)
await OUID.screen.setBrightness(0.8)
await OUID.screen.lockOrientation('landscape')
await OUID.screen.setImmersiveMode(true)
await OUID.media.audio.play('/assets/click.mp3')
const preview = OUID.media.video('#video-preview')
await preview.setSrc('/assets/intro.mp4')
await preview.play()
const nativeVideo = OUID.media.nativeVideo('#native-video')
await nativeVideo.attach({ src: 'assets/intro.mp4', fit: 'contain' })
await nativeVideo.play()
await nativeVideo.sync()
await nativeVideo.load({
  url: 'https://example.com/live/stream.m3u8',
  fit: 'cover',
  headers: { Authorization: 'Bearer token' },
  minBufferMs: 15000,
  maxBufferMs: 50000
})
const recording = await OUID.recording.manager({ bitRate: 128000 })
await recording?.start()
const audioFile = await recording?.stop()
const player = await OUID.audioPlayer.play({ path: audioFile?.path, volume: 0.8 })
await OUID.audioPlayer.release(player?.playerId)
const pickedVideo = await OUID.media.pickVideo({ copyToCache: true, compress: true })
const compressedVideo = await OUID.media.compressVideo({ path: pickedVideo?.file?.path, preset: 'medium' })
const image = await OUID.imagePicker.pickImage({ copyToCache: true })
const compressedImage = await OUID.media.compressImage({ path: image?.file?.path, maxWidth: 1200, quality: 82 })
await OUID.clipboard.writeText('copied from mini app')
const pickedContact = await OUID.contact.pick()
await OUID.contacts.add({ givenName: 'Awa', familyName: 'Traore', phone: '+22370000000', mode: 'auto' })
await OUID.calendar.createEvent({
  title: 'Customer visit',
  start: Date.now() + 3600000,
  end: Date.now() + 7200000
})
await OUID.accessibility.announce('Saved')
await OUID.share.text('Receipt ready')
await OUID.share.file({ path: 'receipts/latest.pdf', directory: 'documents', mimeType: 'application/pdf' })
await offWifi()

The host runtime must provide the matching native implementation. For example, OUID.camera.takePicture() calls the host method _ouid_camera with the takePicture action, OUID.filePicker.pick() calls _ouid_filePicker, and OUID.accelerometer.listen() subscribes through OUID.onHostEvent('accelerometerchange', ...).

Manifest Permissions

Mini apps must ship a manifest.json next to index.html, main.bundle.js, and preload.bundle.js. The host SDK reads it before exposing native module calls and host events. Missing permissions are rejected by the bridge before the native module runs.

{
  "schemaVersion": 1,
  "id": "com.example.app",
  "name": "Example App",
  "version": "1.0.0",
  "permissions": {
    "camera": { "reason": "Capture receipts" },
    "biometry": { "reason": "Protect sensitive actions", "access": ["authenticate"] },
    "contacts": { "reason": "Pick or create a customer", "access": ["pick", "add"] },
    "wifi": { "reason": "Show connectivity", "access": ["read", "scan", "events"] },
    "location": { "reason": "Show nearby service points", "access": ["read", "events"] },
    "calendar": { "reason": "Create appointment reminders", "access": ["createEvent"] },
    "memory": { "reason": "React to memory pressure", "access": ["read", "events"] },
    "qrScan": { "reason": "Scan check-in QR codes", "access": ["scan", "decode", "events"] },
    "keyboard": { "reason": "Adjust forms around the keyboard", "access": ["events", "hide"] },
    "screen": { "reason": "Protect sensitive content", "access": ["setCaptureProtection", "setBrightness", "events"] },
    "media": { "reason": "Record audio and process local media", "access": ["audioContext", "recording", "nativeVideo", "pickVideo", "compressImage", "events"] },
    "share": { "reason": "Share generated files", "access": ["text", "file", "files"] }
  }
}

The schema is available at schemas/ouid-manifest.schema.json. OS-level permissions are still requested by the native module; the manifest only declares which bridge capabilities the mini app is allowed to use.

Device APIs

  • OUID.wifi: read Wi-Fi status, request/open settings, scan/connect on Android, and listen to Wi-Fi events.
  • OUID.location: read the current position, start/stop location updates, and listen to locationchange.
  • OUID.calendar: list calendars, list events, create events, update events, and delete events.
  • OUID.memory: read memory state and listen to memorywarn.
  • OUID.qrScan / OUID.qr: scan QR codes from the camera or decode from image paths/base64.
  • OUID.keyboard: observe keyboard height, hide the keyboard, and read or set focused input selection range.
  • OUID.screen: read orientation, lock/unlock orientation, toggle immersive mode, set per-window brightness, keep the screen awake, protect sensitive content from capture where the OS allows it, and listen to screenshot/recording state events. On Android, screenshot events require API 34+, the DETECT_SCREEN_CAPTURE permission, and a real user screenshot; ADB or emulator-tool screenshots do not trigger the callback.
  • OUID.media: use WebView AudioContext, control HTML video, render native underlay video, stream remote video, pick videos, compress images/videos, play native audio files, and record audio.
  • OUID.recording: create managed audio recording sessions or use unmanaged start(), pause(), resume(), and stop() calls.
  • OUID.audioPlayer: play, pause, seek, stop, and release native file audio players.
  • OUID.bluetooth: read Bluetooth status, use Android classic discovery and paired-device checks, scan/connect/read/write BLE devices, and scan BLE beacons.
  • OUID.nfc: scan NFC tags, read/write NDEF, and transceive through NFC-A/B/F/V, ISO-DEP, and MiFare helpers (nfcmifire is accepted as a MiFare alias).
  • OUID.biometry: check biometric availability and authenticate with Face ID, Touch ID, fingerprint, or device credential fallback.
  • OUID.compass: start/read/stop heading updates and listen to compasschange.
  • OUID.clipboard: read, write, check, and clear text clipboard content.
  • OUID.contact / OUID.contacts: request permission, list/search contacts, open the native picker, and create contacts.
  • OUID.accessibility: read accessibility state, announce text, open settings, and listen to accessibilitychange.
  • OUID.share: open the native share sheet for text, URLs, and local files. Remote image/file fetching is intentionally not performed by the module.

Bluetooth Platform Notes

Android supports classic Bluetooth paired-device listing, classic discovery, bond-change events, BLE scanning/GATT operations, and beacon scanning. iOS supports BLE scanning/GATT operations and beacon scanning through CoreBluetooth, but iOS does not expose classic Bluetooth discovery, Bluetooth MAC addresses, a general paired-device list, or pairing state to apps. On iOS, pairedDevices(), isPaired(), and classic discovery helpers return an unsupported success payload or an empty list; use OUID.bluetooth.ble or OUID.bluetooth.beacon for cross-platform behavior.

Android-only classic Bluetooth APIs: pairedDevices(), bondedDevices(), isPaired(), isBonded(), getDevice(), startDiscovery(), discover(), stopDiscovery(), foundDevices(), discoveredDevices(), isDiscovering(), onDeviceFound(), onDevicesFound(), onDiscoveryChange(), and onBondChange(). The related classic events bluetoothdevicefound, bluetoothdevicesfound, bluetoothdiscoverychange, and bluetoothbondchange are not emitted on iOS. Use BLE scan/connection APIs for shared Android/iOS behavior.

Native Video Notes

OUID.media.nativeVideo() accepts local bundle paths, file:// or content:// URIs, and http:// or https:// URLs. Android uses Media3 ExoPlayer and supports progressive streams, HLS .m3u8, DASH .mpd, and SmoothStreaming manifests. iOS uses AVPlayer and supports the formats provided by AVFoundation, including HLS. For remote sources, the host app must declare INTERNET on Android. Plain http:// streams also require Android cleartext network policy and iOS App Transport Security exceptions when the host allows them.

Use headers and userAgent for authenticated Android HTTP streams. Buffer options are in milliseconds: minBufferMs, maxBufferMs, bufferForPlaybackMs, and bufferForPlaybackAfterRebufferMs.

NFC Platform Notes

Android uses NFC reader mode and supports NDEF, NFC-A, NFC-B, NFC-F, NFC-V, ISO-DEP, and MiFare transceive when the device chipset exposes the tag technology. iOS uses CoreNFC, requires NFCReaderUsageDescription plus NFC entitlements in the host app, and always displays the system NFC sheet. iOS supports NDEF, MiFare command packets, FeliCa/NFC-F commands, ISO-DEP APDU commands, and ISO15693 custom commands; it does not expose raw NFC-B transceive, and raw NFC-A is only available when CoreNFC reports the tag as MiFare.

FileSystem

OUID.fileSystem provides app-private file access without requiring broad storage permissions. OUID.file and OUID.fs are aliases. Relative paths are resolved under a directory root:

  • data / files: private app files
  • documents: app document storage
  • cache: app cache
  • tmp / temp: temporary files
  • external / externalCache: Android app-specific external storage; mapped to app document/cache roots on iOS

Supported operations include readFile, writeFile, appendFile, deleteFile, mkdir, rmdir, readdir, stat, exists, rename, copy, and getUri. Use encoding: 'base64' for binary payloads, or includeDataUrl: true when a read result should include a data URL.

On Android, UI-backed features such as camera, image picker, file picker, and runtime permission prompts need an activity host. Keep the runtime context as an application context if desired, then install the native module with the current FragmentActivity:

OUI.setup(applicationContext, ...)
OUIDDevice.install(this)

If the host manages activity lifecycles separately, install with a provider instead:

OUIDDevice.install { currentActivity }

For Flutter hosts, use FlutterFragmentActivity and pass that activity to the native OUIDDevice.install(...).

For custom bridge instances:

import { installOUIDevice } from '@ouidesigner/ouider-device'

const device = installOUIDevice(customBridge)
await device.vibration.vibrate(120)