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

oraku-sdk

v1.7.0

Published

SDK for the Oraku engagement engine

Readme

oraku-sdk

SDK for the Oraku engagement engine. Send activity events from your app, register custom detectors for your domain, and get back personalised push notifications driven by behavioural pattern detection.


Install

npm install oraku-sdk

Setup

import OrakuSDK from 'oraku-sdk'

const oraku = new OrakuSDK({
  apiUrl: 'https://your-oraku-api.com',
  apiKey: 'your-api-key'
})

| Option | Type | Description | | -------- | ------ | ----------------------------------- | | apiUrl | string | Base URL of your Oraku API instance | | apiKey | string | Your project API key |


Methods

loadInformation(events)

Sends activity events to the Oraku engine. Events are grouped by externalRef, pattern detectors run per group, and results are stored ready to be pulled as notifications.

await oraku.loadInformation([
  {
    externalRef: 'user-123',
    category: 'fitness',
    subcategory: 'cardio',
    log: '5km morning run',
    createdAt: '2026-03-13T07:30:00Z',
    meta: {
      username: 'Emma'
    }
  }
])

Event fields:

| Field | Type | Description | | ------------- | ----------------- | ----------------------------------------------------------------------------------------------- | | externalRef | string | Groups events by user — pass a userId, session ID, or any identifier. Required for routing. | | category | string | Top-level activity type (e.g. fitness, meals, health) | | subcategory | string | More specific type (e.g. cardio, lunch, checkup) | | log | string | Human-readable description of what happened | | createdAt | string (ISO 8601) | When the event occurred — critical for streak and pattern detection | | meta | object | Arbitrary metadata. meta.username is used in notification copy. |

Important: externalRef is how the engine groups events per user. All events for the same user must share the same externalRef.


generateEngagementPulls(filter, options?)

Fetches notifications generated from the last loadInformation call, optionally filtered to a specific user.

const notifications = await oraku.generateEngagementPulls(
  { externalRef: 'user-123' },
  { limit: 3 }
)
// [{ ref: 'user-123', detector: 'StreakDetector', type: 'reminder', message: "You've hit a 7-day fitness streak — keep it going." }, ...]

Returns Notification[] — each object is a ready-to-send push notification.

interface Notification {
  ref: string       // the externalRef this notification is for
  detector: string  // which detector produced it
  type: string      // notification type: reminder | warning | insight | etc.
  message: string   // the notification copy
}

| Field | Type | Description | | ------------- | ------ | -------------------------------------------- | | externalRef | string | The user to fetch notifications for | | limit | number | Max number of notifications to return |


detectors.add(builder)

Registers a custom detector for your project. Use DetectorBuilder to define what to detect and which events it should see. Detectors are stored server-side and applied automatically on every loadInformation call.

import { DetectorBuilder } from 'oraku-sdk'

One instance per detector type:

// streak-ongoing — predicts next occurrence of a repeating pattern
const fitnessStreak = new DetectorBuilder('fitness-streak', 'streak-ongoing')
  .addMarker('fitness')
  .minRepeat(3)
  .notificationType('reminder')

// streak-break — flags when a repeating pattern stops
const routineBreak = new DetectorBuilder('routine-break', 'streak-break')
  .addMarker('routine')
  .minRepeat(3)
  .notificationType('warning')

// checklist — fires when expected items are missing from today's events
const dailyMeds = new DetectorBuilder('daily-meds', 'checklist')
  .addMarker('health')
  .expected(['medication', 'vitamins'])
  .todayOnly()
  .notificationType('warning')

// milestone — fires when a user hits specific achievement markers
const mealVariety = new DetectorBuilder('meal-variety', 'milestone')
  .addMarker('meals')
  .expected(['salad', 'protein', 'fruit'])
  .notificationType('achievement')

// threshold — fires when a numeric value extracted from events doesn't meet a target
const calorieGoal = new DetectorBuilder('calorie-goal', 'threshold')
  .addMarker('nutrition')
  .extract({ path: 'meta.calories' })
  .operator('lt')
  .value(1500)
  .aggregate('sum')
  .notificationType('warning')

// item-analysis — looks up properties of each item, aggregates them, reports gaps
const daycareNutrition = new DetectorBuilder('daycare-nutrition', 'item-analysis')
  .addMarker('meals')
  .extract({ path: 'meta.foodsServed' })
  .lookup({
    map: {
      apple: { protein: 0.3, vitamin_c: 8, calcium: 6 },
      milk:  { protein: 3.4, calcium: 125 }
    }
    // or use an API:
    // api: { urlTemplate: 'https://nutrition-api.com/food?name={item}', responsePath: 'nutrients' }
  })
  .targets({ protein: 10, calcium: 200, vitamin_c: 15 })
  .notificationType('nudge')
  .scheduleAt('16:00')  // deliver at 16:00 UTC instead of the default for this notification type

await oraku.detectors.add(fitnessStreak)
await oraku.detectors.add(routineBreak)
await oraku.detectors.add(dailyMeds)
await oraku.detectors.add(mealVariety)
await oraku.detectors.add(calorieGoal)
await oraku.detectors.add(daycareNutrition)

Builder methods:

| Method | Type | Description | | ------------------------ | ------------------------------------------------- | ---------------------------------------------------------- | | addMarker(expr) | string | Filter which events this detector sees (see Markers below) | | notificationType(type) | reminder | warning | nudge | suggestion | achievement | insight | Type of notification produced | | minRepeat(n) | number | Minimum consecutive occurrences to trigger (streak types) | | expected(items) | string[] | Items expected to be present (checklist / milestone) | | todayOnly() | — | Only consider events from today | | extract(config) | { path: string } | Dot-notation path to extract a value from events | | operator(op) | lt | lte | gt | gte | eq | Comparison direction for threshold detectors | | value(n) | number | Target value to compare against | | aggregate(fn) | sum | avg | count | min | max | How to combine values across events | | lookup(config) | { map?, api? } | Where to look up item properties (item-analysis) | | targets(map) | Record<string, number> | Minimum required value per property (item-analysis) | | scheduleAt(time) | string (e.g. '16:00') | UTC time to deliver the notification — overrides the default for the notification type |

Markers

Markers filter which events a detector sees. They support boolean expressions matching against any string field of the event:

.addMarker('fitness')                // events where any field === 'fitness'
.addMarker('fitness or cardio')      // either value
.addMarker('health and not mental')  // health events excluding mental
.addMarker('meals or nutrition')     // multiple categories

Without a marker, the detector runs against all events.


detectors.remove(name)

Removes a registered detector by name.

await oraku.detectors.remove('fitness-streak')

project.setSettings(settings)

Stores a webhook URL for your project. When set, Oraku pushes notifications to your endpoint instead of waiting to be polled.

await oraku.project.setSettings({
  webhookUrl: 'https://yourapp.com/oraku-webhook',
  webhookAuthKey: 'optional-secret'
})

project.setCron(cron)

Configures a schedule for Oraku to automatically run the pipeline on a recurring basis.

await oraku.project.setCron({ cron: '0 9 * * *' })

How it works

Your app
  → loadInformation(events)
      → events grouped by externalRef
      → custom detectors run (scoped by marker)
      → ActivityPatternAnalyzer runs as fallback
      → findings converted to personalised notifications
  → generateEngagementPulls({ externalRef: userId })
      → returns that user's notifications as Notification[]

Notifications are scoped per user — each user only receives notifications based on their own activity history. The engine handles all detection and copy generation; you just send events and display the output.