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

@cred-repo/sdk

v1.1.1

Published

Node.js SDK for the Cred Platform API — events, commitments, actors, and credibility.

Readme

@cred-repo/sdk

TypeScript SDK for the Cred Platform API. Build credibility-tracked prediction apps.

Quickstart

import { createCredClient } from "@cred-repo/sdk";

// apiKey MUST be an app API key (prefix: cr_live_).
// CLI login tokens (cpat_*) and OAuth tokens (oa_live_*) will NOT work.
const cred = createCredClient({
  baseUrl: "https://cred-repo.com",
  apiKey: process.env.CRED_API_KEY!, // cr_live_...
});

// 1. Create an actor (idempotent by externalUserId)
const actor = await cred.createOrGetActor({
  externalUserId: "user-123",
  handle: "alice",
});

// 2. Ensure an event exists (key = shared question, NEVER include userId)
await cred.ensureEvent({
  key: "weather:rain:chicago:2026-04-01",
  title: "Will it rain in Chicago?",
  resolutionConfigSlug: "weather.rain",
  locksAt: "2026-04-01T00:00:00Z",
  overrideParams: { date: "2026-04-01" },
});

// 3. Submit a commitment (idempotent upsert — updates if exists)
const commitment = await cred.submitCommitment({
  actorId: actor.actorId,
  eventKey: "weather:rain:chicago:2026-04-01",
  probability: 0.75,
  resolutionDate: "2026-04-01",
  question: "Will it rain in Chicago on April 1?",
});

// 4. Read commitments
const result = await cred.getCommitments({
  actorId: actor.actorId,
  resolved: true,
});

// 5. Check resolution status
const status = await cred.getResolutionStatus("weather:rain:chicago:2026-04-01");
// status.state: "pending" | "resolved"

That's the complete integration path. Every first-party app (NBACred, WeatherCred, PolyCred) uses exactly this flow.

Visibility (v1.1.0)

// Submit with visibility tier (defaults to "public" if omitted)
const commitment = await cred.submitCommitment({
  actorId: actor.actorId,
  eventKey: "weather:rain:chicago:2026-04-01",
  probability: 0.75,
  resolutionDate: "2026-04-01",
  question: "Will it rain in Chicago on April 1?",
  visibility: "restricted", // "restricted" | "public"
});

// Promote visibility (can only expand, never contract)
await cred.promoteCommitment({
  commitmentId: commitment.commitmentId,
  visibility: "public",
});

Tiers: restricted (actor + admins only), public (external, verifiable). Visibility is set once at creation and can only expand via promote. Non-public commitments are not yet enabled in production.

Scoring: Only commitments with visibility_at_resolution = 'public' enter public calibration. Promoting after resolution does not retroactively change scoring.

Commitment Semantics

These are platform-enforced behaviors, not SDK opinions.

  • Uniqueness: One commitment per actor per event, keyed on (actor_id, canonical_event_id).
  • Behavior: Last-write-wins upsert. Resubmitting updates probability and question. Returns the same commitmentId.
  • History: Not retained at the platform level. Previous probabilities are overwritten. Apps that need amendment history must track locally.
  • Guarantee: Idempotent. Safe to retry on network failure. Calling submitCommitment twice with the same parameters is a no-op.
  • Scoring: brierScore, isCorrect, predictedSide are computed by the platform and returned in the API response. Do not recompute these locally.

Error Handling

import { isCredError } from "@cred-repo/sdk";

try {
  await cred.submitCommitment({ ... });
} catch (err) {
  if (isCredError(err)) {
    switch (err.code) {
      case "CRED_EVENT_LOCKED":
        // Prediction window closed
        break;
      case "CRED_ALREADY_RESOLVED":
        // Event already has an outcome
        break;
      case "CRED_EVENT_CONFLICT":
        // Event exists with different immutable fields
        break;
      case "CRED_UNAUTHORIZED":
        // Invalid API key
        break;
    }
  }
}

Never match on err.message. Always use err.code.

Webhook Verification

import { verifyWebhookSignature } from "@cred-repo/sdk";

// In your webhook handler:
const body = await request.text();

verifyWebhookSignature({
  rawBody: body,
  signatureHeader: request.headers.get("webhook-signature"),
  secret: process.env.CRED_WEBHOOK_SECRET!,
  webhookId: request.headers.get("webhook-id")!,
  timestamp: request.headers.get("webhook-timestamp")!,
});

// If it doesn't throw, the signature is valid.
const payload = JSON.parse(body);

The SDK handles signing key derivation, HMAC computation, and timestamp tolerance internally. Pass the raw webhook secret — do not pre-hash it.

Real App Patterns

Three production apps use this SDK. Each represents a different integration shape.

Pattern 1: User Prediction App (NBACred)

User submits predictions on NBA games. Resolution via external cron.

  • Actor: created at OAuth login, cached locally
  • Events: created per prediction (one per team per game)
  • Commitments: user-initiated, one at a time
  • Resolution: webhook from Cred resolver
  • Key format: nba:winner:{gameId}-{team}:{date}

Pattern 2: Scheduled Data App (WeatherCred)

Cron creates daily events. NOAA reference forecaster submits baselines.

  • Actor: human (users) + reference (NOAA)
  • Events: batch-created by nightly cron (6 cities x 7 days)
  • Commitments: user-initiated + NOAA reference (cron)
  • Resolution: webhook from Cred resolver
  • Key format: weather:rain:{city}:{date}
  • Reference actor: cred.createOrGetActor({ actorType: "reference" })

Pattern 3: System-Driven Predictions (PolyCred)

AI models forecast hundreds of prediction markets. High volume, continuous ingestion.

  • Actors: human (users) + AI agents (4 LLM providers)
  • Events: created per market (500+ active)
  • Commitments: user-initiated + AI cron (batch of 10, every 5 min)
  • Resolution: polling via raw getResolvedEvents() (not yet in SDK)
  • Key format: polymarket:{conditionId}:{slug}:{date} or kalshi:{ticker}:{date}
  • AI actors: cred.createOrGetActor({ actorType: "ai_agent" })

What the SDK Does NOT Do

Be explicit about boundaries:

  • Does not build event keys. Each app owns its key format. The SDK validates nothing about key structure beyond "non-empty string." Event keys must represent shared questions (e.g., stockcred:close:AAPL:2026-04-01), never per-user state. Including userId in a key creates one event per user, destroying crowd aggregation and calibration.
  • Does not handle OAuth or sessions. Identity is an app concern. The SDK provides createOrGetActor for the data layer only.
  • Does not provide analytics or aggregation endpoints. Crowd averages, credibility scores, and leaderboard data are app-specific reads.
  • Does not batch requests. Rate-aware batching belongs in the app layer. The SDK makes one call at a time.
  • Does not cache results. The SDK returns fresh data on every call. Apps cache locally as needed.
  • Does not manage your database. Local caching of cred_actor_id, cred_commitment_id, outcomes, and Brier scores is the app's responsibility.

Common Mistakes

Based on migrating three production apps:

  • Don't use CLI tokens with the SDK. The SDK requires an app API key (cr_live_*). CLI login tokens (cpat_*) will return 401 on all write operations.
  • Don't use a config from a different domain. weather.rain only works with weather:* keys. nba.game_winner only works with nba:* keys. For new domains, use manual.binary which accepts any key format.
  • Don't put the config slug in your event key. The key should be stockcred:close:AAPL:2026-04-01, NOT manual:binary:stockcred:2026-04-01. The config slug goes in resolutionConfigSlug, never in the key itself.
  • Don't put userId in event keys. Events are shared questions (stockcred:close:AAPL:2026-04-01). Actors differentiate users. A per-user key creates isolated single-commitment events — no crowd, no calibration, no leaderboard value.
  • Don't implement your own retry logic. The SDK retries transient failures (5xx, network errors) with exponential backoff. Customize via maxRetries and retryBackoffMs in client options.
  • Don't manually construct auth headers. Pass apiKey to createCredClient and forget about it.
  • Don't compute Brier scores locally. The API returns authoritative evaluation.brierScore and evaluation.isCorrect on every commitment. Trust them.
  • Don't string-match error messages. Use isCredError(err) and check err.code. Error messages may change; codes are stable.
  • Don't assume append-only. Commitments are last-write-wins upsert. Submitting again updates the existing commitment, not creates a new one.
  • Don't deduplicate commitments in your app. The platform handles it. Your app's "amend" flow is just another submitCommitment call.

Config Discovery

const configs = await cred.listConfigs();
// Returns active resolution configs with slugs, preconditions, and timing.

Use this to discover available resolutionConfigSlug values instead of hardcoding.

Critical: Config ↔ Event Key Coupling

Resolution configs are not interchangeable. Each config expects a specific event key format and domain. Using the wrong config for your key format will fail with wc_canonical_key_format_check or namespace_not_allowed.

// ✅ Correct — weather config with weather-style key
await cred.ensureEvent({
  key: "weather:rain:chicago:2026-04-01",
  resolutionConfigSlug: "weather.rain",    // matches weather:* keys
  ...
});

// ❌ Wrong — weather config with stock-style key
await cred.ensureEvent({
  key: "stockcred:close:AAPL:2026-04-01",
  resolutionConfigSlug: "weather.rain",    // FAILS: key format mismatch
  ...
});

If you are building a new app domain (stocks, sports, etc.), use manual.binary — the universal config that works with any domain and any key format.

Pattern 4: Custom Domain App (manual.binary)

For new domains where no automated connector exists yet. Your app resolves events itself.

// 1. Use manual.binary — works with ANY key format
await cred.ensureEvent({
  key: "stockcred:close:AAPL:2026-04-01",  // YOUR domain, YOUR format
  title: "Will AAPL close above $150 on April 1?",
  resolutionConfigSlug: "manual.binary",     // Universal config
  locksAt: "2026-04-01T16:00:00Z",
});

// 2. Submit commitments as normal
await cred.submitCommitment({
  actorId: actor.actorId,
  eventKey: "stockcred:close:AAPL:2026-04-01",
  probability: 0.65,
  resolutionDate: "2026-04-01",
  question: "Will AAPL close above $150?",
});

// 3. Resolve with structured evidence (requires resolver token)
await fetch(`${baseUrl}/api/v1/events/stockcred:close:AAPL:2026-04-01/resolve`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${resolverToken}`,  // resolver credential, not app key
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    outcome: true,
    evidence_type: "app_reported",           // REQUIRED
    evidence_payload: {                       // REQUIRED — no bare { outcome: true }
      source: "stockcred",
      symbol: "AAPL",
      close_price: 152.30,
      threshold: 150.00,
      data_source: "yahoo_finance",
    },
  }),
});

Key format rules for manual.binary:

  • Use YOUR domain prefix: stockcred:close:AAPL:2026-04-01, NOT manual:binary:stockcred:2026-04-01
  • The config slug (manual.binary) goes in resolutionConfigSlug, never in the key
  • Keys must be shared questions — one event per real-world question, not per user
  • Format: {domain}:{metric}:{entity}:{YYYY-MM-DD}

Trust tier: Manual resolution is labeled evidence_class: "app_reported" on all surfaces. This distinguishes it from connector-verified resolution (public_api, first_party_source). Evidence is still hashed, immutable, and stored in the receipt — but it is not independently verifiable by a third party.

Resolution is Not a Simple Outcome Write

The SDK does not expose a resolve() method. Resolution is handled by the platform's resolver service, which:

  • Fetches evidence from external data sources
  • Verifies preconditions (e.g., game is final, market is closed)
  • Computes evidence hashes for tamper detection
  • Scores all commitments atomically

If you need custom resolution for a new domain, you need a resolver credential (cr_live_* with credential_type: resolver) and must POST structured evidence to /api/v1/events/{key}/resolve with evidence_type and evidence_payload fields. This is an advanced integration — most apps should rely on platform-managed resolution via webhooks or polling.

Resolution Status

const status = await cred.getResolutionStatus("weather:rain:chicago:2026-04-01");

Returns state: "pending" or state: "resolved" with receipt info. v1 is truth-only — intermediate diagnostic states (preconditions, connector status) are not yet exposed.

For polling:

const result = await cred.waitForResolution({
  eventKey: "weather:rain:chicago:2026-04-01",
  timeoutMs: 60 * 60 * 1000,
});
// Resolves when state reaches a terminal state.
// Throws on timeout or abort.

Contract Version

The SDK sends X-Cred-SDK-Version and validates X-Cred-Contract-Version: 1 from the API. If the contract version changes, the SDK warns once at startup.