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

@reinvented/sdk

v0.4.0

Published

Reinvented Platform SDK — error reporting for Reinvented apps

Readme

@reinvented/sdk

Official SDK for building apps on the Reinvented platform. Two entry points — one for server, one for client.

@reinvented/sdk/server  ← use in apps/api/
@reinvented/sdk/client  ← use in apps/desktop/ and apps/mobile/

Installation

pnpm add @reinvented/sdk

Already installed in the app template for all three apps (api, desktop, mobile).


Server SDK (@reinvented/sdk/server)

Use in your API backend (apps/api/). Reads environment variables automatically.

import { createServerSDK, initErrorReporting } from '@reinvented/sdk/server';

const platform = createServerSDK();  // zero-config, reads from env

const app = express();
// ... routes ...
initErrorReporting(app);  // DO NOT DELETE — reports errors to platform
app.listen(4000);

Environment Variables (auto-read)

| Variable | Required | Description | |---|---|---| | PLATFORM_SERVICE_TOKEN | Yes | Per-app authentication token | | PLATFORM_API_URL | No | API URL (defaults to https://api.reinvented.com) |

Both are automatically injected into every app's environment during provisioning.

Explicit Config (optional)

const platform = createServerSDK({
  serviceToken: 'my-token',
  platformUrl: 'https://api.reinvented.com',
});

Client SDK (@reinvented/sdk/client)

Use in your frontend apps (apps/desktop/, apps/mobile/).

// main.jsx — just importing auto-installs error reporting
import '@reinvented/sdk/client';

If you also need to call platform services from the client:

import { createClientSDK } from '@reinvented/sdk/client';

const platform = createClientSDK({
  serviceToken: 'your-token',  // required — browsers have no env vars
});

Services

Both server and client SDKs provide the same three services:

platform.storage — File Storage (Google Cloud Storage)

storage.importFromUrl(url, options?)

Download a file from any URL and store it on the platform CDN.

| Param | Type | Description | |---|---|---| | url | string | Source URL to download from | | options.contentType | string? | Override content type | | options.extension | string? | Override file extension |

Returns: { url: string, id: string, objectName: string }

const { url } = await platform.storage.importFromUrl('https://example.com/photo.jpg');
// url → 'https://storage.reinvented.cloud/<uuid>/original.jpg'

platform.email — Transactional Email (Amazon SES)

email.send({ userId, subject, html?, text? })

Send an email to a platform user. The platform resolves their email address from the user ID.

| Param | Type | Description | |---|---|---| | userId | string | Platform user ID (not an email address) | | subject | string | Email subject line | | html | string? | HTML email body | | text | string? | Plain text body (auto-generated from HTML if omitted) |

Returns: { ok: boolean, messageId: string }

Emails are sent from "App Name <[email protected]>".

await platform.email.send({
  userId: 'abc-123',
  subject: 'Your report is ready',
  html: '<h1>Weekly Report</h1><p>Click below to view.</p>',
});

platform.ai — AI Tools (Google Gemini)

Default model: gemini-2.5-flash. All inference runs server-side on the platform.

ai.generateJSON({ prompt, schema?, model?, temperature? }) ⭐ Primary

Generate structured JSON from a prompt. This is the most commonly used AI method.

| Param | Type | Default | Description | |---|---|---|---| | prompt | string | — | What to generate | | schema | object? | — | Gemini-format JSON schema | | model | string? | gemini-2.5-flash | Gemini model ID | | temperature | number? | 0.7 | 0.0 = deterministic, 1.0 = creative |

Returns: Parsed JSON matching the schema.

Schema types: STRING, NUMBER, INTEGER, BOOLEAN, ARRAY, OBJECT

const product = await platform.ai.generateJSON({
  prompt: 'Extract: "Nike Air Max 90, Size 10, $129.99"',
  schema: {
    type: 'OBJECT',
    properties: {
      name: { type: 'STRING' },
      size: { type: 'STRING' },
      price: { type: 'NUMBER' },
    },
  },
});
// → { name: 'Nike Air Max 90', size: '10', price: 129.99 }

ai.generateText({ prompt, model?, temperature?, maxTokens? })

Generate free-form text.

Returns: { text: string }

const { text } = await platform.ai.generateText({
  prompt: 'Write a welcome email for a new user named Sarah',
});

ai.generateImage({ prompt, aspectRatio? })

Generate an image. Auto-uploaded to platform storage.

Returns: { url: string, id: string, objectName: string }

const { url } = await platform.ai.generateImage({
  prompt: 'A minimalist logo for a health tech startup',
  aspectRatio: '1:1',
});

Error Handling

All SDK methods throw PlatformSDKError on failure:

import { PlatformSDKError } from '@reinvented/sdk/server';
// or: import { PlatformSDKError } from '@reinvented/sdk/client';

try {
  await platform.ai.generateJSON({ prompt: '...' });
} catch (err) {
  if (err instanceof PlatformSDKError) {
    console.error(err.message);  // Human-readable error description
    console.error(err.code);     // Machine-readable error code (see table below)
    console.error(err.status);   // HTTP status code (0 for network errors)
  }
}

| Error Code | Meaning | Common Cause | |---|---|---| | MISSING_TOKEN | No service token provided | Forgot to set PLATFORM_SERVICE_TOKEN or pass serviceToken | | NETWORK_ERROR | Can't reach the platform API | Network issue, wrong PLATFORM_API_URL, platform down | | API_ERROR | Platform returned an error | Bad request data, rate limit, server error (check status and message) | | INVALID_RESPONSE | Platform returned non-JSON | Platform bug or network corruption |


Error Reporting

The SDK includes automatic error reporting that catches uncaught errors and sends them to the platform for investigation. This is how the platform knows when an app is broken.

How It Works

Server (@reinvented/sdk/server)

Error reporting operates at two levels:

  1. Process-level handlers (automatic on import):

    • uncaughtException → logs, reports to platform, exits with code 1
    • unhandledRejection → logs, reports to platform, continues running

    These are installed the moment you import anything from @reinvented/sdk/server. No setup required. They catch errors that escape Express (startup errors, async code outside request handlers, etc.).

  2. Express middleware (requires initErrorReporting(app)):

    • Catches errors thrown in Express route handlers and middleware
    • Reports each error with the HTTP method and path (e.g., POST /graphql)
    • Calls next(err) so your own error handler still runs
    // MUST be added AFTER all routes and other middleware
    initErrorReporting(app);

initErrorReporting() reads PLATFORM_API_URL and APP_SLUG from env vars. If the slug is missing, it silently no-ops (safe for local dev without platform env). No auth token is required — the platform API accepts error reports without authentication.

Client (@reinvented/sdk/client)

Error reporting is fully automatic on import. It installs three handlers:

  1. window.error — catches uncaught runtime errors (e.g., TypeError: Cannot read property 'x' of null)
  2. window.unhandledrejection — catches unhandled promise rejections
  3. console.error interception — catches framework-swallowed errors (React, Vue, etc. often catch errors and log them via console.error instead of letting them propagate)

Errors are sent directly to the platform API via fetch('https://api.reinvented.com/api/app-errors'). The app slug is derived from the URL path. No authentication is required.

The client includes built-in dedup (5 unique errors per session max) to avoid flooding the API during error loops.

This activates on any page — it no longer requires an iframe context.

// main.jsx — just import, error reporting is active immediately
import '@reinvented/sdk/client';

What Gets Reported

Every error report includes:

| Field | Description | |---|---| | message | Error message (truncated to 500 chars) | | stack | Stack trace (truncated to 4000 chars) | | url / context | Where the error occurred (server: HTTP method + path; client: page URL) | | appSlug | Which app had the error |

Error Reporting Flow

App Error
    │
    ├─ Server ──→ POST /api/app-errors ──→ Platform stores + deduplicates
    │              (no auth required)
    │
    └─ Client ──→ POST /api/app-errors ──→ Platform stores + deduplicates
                   (no auth required, app slug from URL)

Errors are deduplicated by fingerprint (SHA-256 of message + first stack frame). The platform's autonomous bug-fix agent uses MCP tools to triage, investigate, and resolve errors.


Architecture

Your App                     Platform API              Cloud Services
─────────                    ────────────              ──────────────
                                                       
platform.storage.import()  → POST /sdk/storage/import → Google Cloud Storage
platform.email.send()      → POST /sdk/email/send     → Amazon SES
platform.ai.generateJSON() → POST /sdk/ai/generate-json → Google Gemini
platform.ai.generateText() → POST /sdk/ai/generate-text → Google Gemini
platform.ai.generateImage()→ POST /sdk/ai/generate-image → Gemini + GCS

The SDK is a thin HTTP client. All heavy lifting happens server-side on the platform API:

  • No cloud credentials needed in your app
  • No dependencies — zero npm dependencies
  • Works everywhere — anywhere fetch exists