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

@more-ink/irt-edge

v2.1.1

Published

IRT Edge API client SDK for JavaScript/TypeScript frontends.

Downloads

51

Readme

@more-ink/irt-edge

Two packages in one:

  1. SDK - Lightweight API client for JavaScript/TypeScript frontends (published to npm)
  2. Backend Server - Production HTTP API server built with Hono for Aliyun Function Compute (not published)

Table of Contents


SDK Usage (Frontend)

Installation

npm install @more-ink/irt-edge @more-ink/irt-core
# or
yarn add @more-ink/irt-edge @more-ink/irt-core

Note: @more-ink/irt-core is a peer dependency that provides type definitions.

Quick Start

import { IrtClient } from '@more-ink/irt-edge'

const client = new IrtClient({
  baseUrl: 'https://your-api.example.com',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN' // Optional
  },
  timeout: 10000 // Optional (default: 10000ms)
})

// Record an answer and get the next item
const result = await client.recordAnswer({
  userId: 'user123',
  skillId: 'math',
  itemId: 'item456',
  score: 0.8,
  timestamp: Date.now()
})

console.log('Updated ability:', result.theta)
console.log('Next item:', result.nextItem)

Configuration

IrtClientConfig

interface IrtClientConfig {
  baseUrl: string                      // API server base URL (required)
  headers?: Record<string, string>     // Custom headers (e.g., auth tokens)
  timeout?: number                     // Request timeout in ms (default: 10000)
}

API Methods

recordAnswer()

Record a user's response and get the next recommended item.

async recordAnswer(params: RecordAnswerRequest): Promise<RecordAnswerResponse>

Parameters:

interface RecordAnswerRequest {
  userId: string          // User identifier
  skillId: string         // Skill identifier
  itemId: string          // Item identifier
  score: number           // Response score [0,1] (0=wrong, 1=correct)
  timestamp?: number      // When response occurred (ms)
  updateOptions?: Partial<UpdateOptions>      // Override learning rates
  selectionOptions?: Partial<NextItemOptions> // Override selection behavior
}

Returns: Updated ability (theta), standard error (se), next item, and updated states.

Example:

const result = await client.recordAnswer({
  userId: 'alice',
  skillId: 'geometry',
  itemId: 'q100',
  score: 1.0,
  timestamp: Date.now()
})

console.log(`Ability: ${result.theta.toFixed(2)} ± ${result.se.toFixed(2)}`)
if (result.nextItem) {
  console.log(`Next question: ${result.nextItem.id}`)
}

recordMultiSkillAnswers()

Record multiple skill scores that came from a single multi-skill item. This is useful when one interaction yields separate sub-skill scores (e.g., integrated tasks that grade both reading and writing).

async recordMultiSkillAnswers(
  params: RecordMultiSkillAnswersRequest,
): Promise<RecordMultiSkillAnswersResponse>

Parameters:

interface RecordMultiSkillAnswersRequest {
  userId: string
  itemId: string
  timestamp?: number
  updateOptions?: Partial<UpdateOptions>
  skillScores: Array<{
    skillId: string
    score: number // [0,1]
    updateOptions?: Partial<UpdateOptions>
  }>
}

Returns: Array of per-skill updates with theta, SE, updated user/item snapshots.

Example:

const multi = await client.recordMultiSkillAnswers({
  userId: 'alice',
  itemId: 'essay-22',
  skillScores: [
    { skillId: 'reading', score: 0.9 },
    { skillId: 'writing', score: 0.6 },
  ],
})

multi.results.forEach((entry) => {
  console.log(entry.skillId, entry.theta, entry.se)
})

recordAnswerOnly()

Record a user's response without requesting the next recommended item (useful when you already control sequencing).

async recordAnswerOnly(params: RecordAnswerRequest): Promise<RecordAnswerOnlyResponse>
await client.recordAnswerOnly({
  userId: 'alice',
  skillId: 'geometry',
  itemId: 'q100',
  score: 1.0,
  timestamp: Date.now()
})

selectNextItem()

Get the next recommended item without recording a response.

async selectNextItem(params: SelectNextItemRequest): Promise<SelectNextItemResponse>

getUserState() / getUserStates()

Get current user ability estimates.

async getUserState(userId: string, skillId: string): Promise<UserStateResponse>
async getUserStates(userId: string): Promise<UserStatesResponse>

getItemState() / getItemStates()

Get item parameters and metadata.

async getItemState(itemId: string, skillId: string): Promise<ItemStateResponse>
async getItemStates(itemId: string): Promise<ItemStatesResponse>

deleteUser() / deleteItem()

Delete a user (and their skill states) or an item (and all per-skill calibrations). These are mainly for integration tests and fixture cleanup.

async deleteUser(userId: string): Promise<DeleteUserResponse>
async deleteItem(itemId: string): Promise<DeleteItemResponse>

health()

Check API server health status.

async health(): Promise<HealthResponse>

See examples/sdk-usage.ts for complete working examples.

Error Handling

All methods throw errors for network failures, HTTP errors, timeouts, and invalid responses.

try {
  const result = await client.recordAnswer({...})
  // Handle success
} catch (error) {
  if (error instanceof Error) {
    console.error('API error:', error.message)
    if (error.message.includes('timeout')) {
      // Retry logic
    }
  }
}

Best Practices

  1. Reuse client instances - Create one client and reuse it
  2. Use timestamps - Always provide client-side timestamps for accurate analytics
  3. Handle errors gracefully - Show user-friendly messages on errors
  4. Check for null items - The API may return null if no suitable item is available
const result = await client.selectNextItem({...})
if (result.nextItem) {
  // Show item to user
} else {
  // No more items available
}

Backend Server Setup

The backend server is not published to npm. It runs as a service on Aliyun Function Compute.

Features

  • RESTful IRT API backed by PostgreSQL via Prisma (Redis route kept only for diagnostics)
  • Aliyun FC lifecycle hooks (/initialize, /pre-stop)
  • Graceful shutdown and health checks

Development Setup

# From repo root
npm install

# Create .env file with:
# UPSTASH_REDIS_REST_URL=https://...
# UPSTASH_REDIS_REST_TOKEN=...

# Run dev server
npm run --workspace @more-ink/irt-edge dev

# Seed data
npm run --workspace @more-ink/irt-edge seed

Backend Environment Variables

# Aliyun Function Compute
ALIYUN_ACCESS_KEY="YOUR_ALIYUN_ACCESS_KEY"
ALIYUN_SECRET_ACCESS_KEY="YOUR_ALIYUN_SECRET_KEY"

# Database (PostgreSQL via Prisma)
DATABASE_URL="postgres://user:pass@host:port/db?schema=public"
# If using PgBouncer / pooled connections, also set DIRECT_URL for Prisma CLI commands
# DIRECT_URL="postgres://user:pass@host:port/db?schema=public"

# Feishu (Lark) Integration
FEISHU_APP_ID="YOUR_FEISHU_APP_ID"
FEISHU_APP_SECRET="YOUR_FEISHU_APP_SECRET"
FEISHU_CHAT_ID="YOUR_FEISHU_CHAT_ID"

# Optional legacy Redis diagnostics route
REDIS_URL=""
REDIS_DB=2

# Debug mode for Function Compute
DEBUG_FC="true"

# Server port (optional, default: 9000)
PORT=9000

See src/index.ts for default IRT engine parameters (learning rates, selection options).

API Endpoints

IRT Operations:

  • POST /api/irt/answer - Record response and get next item
  • POST /api/irt/answer-multi - Record multiple skill responses for one item
  • POST /api/irt/next-item - Get next item without recording response
  • DELETE /api/irt/users/:userId - Delete a user and all skill states
  • DELETE /api/irt/items/:itemId - Delete an item and its per-skill calibrations
  • GET /api/irt/health - Health check

Aliyun FC Lifecycle:

  • POST /initialize - Instance startup (verifies Prisma DB and Redis diag route if configured)
  • GET /pre-stop - Instance shutdown (closes Prisma DB and Redis if used)

System:

  • GET / - Service info

Backend Deployment (Aliyun FC)

Deploy the backend server to Aliyun FC:

# From root (recommended)
npm run dp

# Or from package dir
npm run --workspace @more-ink/irt-edge deploy

How Deployment Works

Deployment now runs directly from the package root with npm-installed node_modules (no flattening step needed):

  1. Run npm run --workspace @more-ink/irt-edge deploy (runs prisma generate, then build, then fc-deploy from the package root)
  2. Upload from the package root; node_modules already contains real files.

Ensure DATABASE_URL (and DIRECT_URL if pooling) is set in the function env.


SDK Publishing (npm)

Publish the SDK to npm (backend code stays private):

# From repo root (recommended)
npm run pub

# Or from package directory
cd packages/irt-edge
npm run publish:sdk

# Or using npm directly
npm publish --access public

What Gets Published

Published to npm:

  • sdk/ - Compiled SDK code (~40KB unpacked)
  • README.md, CHANGELOG.md - Documentation
  • examples/ - Usage examples
  • package.json - Package metadata

NOT published (stays private):

  • ❌ Backend server code (src/index.ts, routes.ts, storage/)
  • ❌ Scripts and tests (scripts/, tests/)
  • ❌ Config files (.env, tsconfig.json, etc.)
  • ❌ Backend build output (dist/)

The .npmignore file ensures only SDK files are published.

Publishing Checklist

Before publishing:

  1. Version Management

    • Update version in package.json (follow semver)
    • Update CHANGELOG.md with changes
  2. Code Quality

    • Build SDK: npm run --workspace @more-ink/irt-edge build:sdk
    • Run tests: npm run --workspace @more-ink/irt-edge test
    • Check TypeScript: tsc -p tsconfig.sdk.json --noEmit
  3. Verify Package

    • Dry-run: npm pack --dry-run
    • Check package size (<50KB)
    • Verify only SDK files included
  4. Publish

    • npm run pub (auto-builds before publishing)
  5. Post-Publishing

    • Verify on npm: https://www.npmjs.com/package/@more-ink/irt-edge
    • Tag release: git tag v1.0.0 && git push origin v1.0.0
    • Create GitHub release

Test Installation

mkdir /tmp/test-irt-sdk && cd /tmp/test-irt-sdk
npm init -y
npm install @more-ink/irt-edge @more-ink/irt-core
node -e "const { IrtClient } = require('@more-ink/irt-edge'); console.log('OK')"

Package Scripts

Development & Backend

  • npm run --workspace @more-ink/irt-edge dev - Run dev server with hot reload
  • npm run --workspace @more-ink/irt-edge build - Build backend server to dist/
  • npm run --workspace @more-ink/irt-edge start - Start production backend server
  • npm run --workspace @more-ink/irt-edge seed - Seed Redis with test data
  • npm run --workspace @more-ink/irt-edge deploy - Deploy backend to Aliyun FC

SDK Publishing

  • npm run --workspace @more-ink/irt-edge build:sdk - Build SDK to sdk/
  • npm run --workspace @more-ink/irt-edge publish:sdk - Build and publish SDK to npm
  • npm run pub - Shortcut for npm run --workspace @more-ink/irt-edge publish:sdk (from root)

Testing

  • npm run --workspace @more-ink/irt-edge test - Run test suite
  • npm run --workspace @more-ink/irt-edge test:watch - Run tests in watch mode

Architecture

irt-edge/
├── src/
│   ├── sdk/              # ✅ SDK source (published)
│   │   ├── types.ts      # Type definitions
│   │   ├── client.ts     # IrtClient class
│   │   └── index.ts      # Public exports
│   ├── index.ts          # ❌ Backend server (not published)
│   ├── routes.ts         # ❌ Backend routes
│   └── storage/          # ❌ Backend storage layer
├── sdk/                  # ✅ Compiled SDK (published)
├── dist/                 # ❌ Backend build (not published)
├── examples/             # ✅ SDK examples (published)
├── tsconfig.json         # Backend build config
└── tsconfig.sdk.json     # SDK build config

License

Proprietary - All Rights Reserved