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

@nextplus/js-sdk

v0.0.12

Published

A TypeScript SDK for interacting with the NextPlus API, automatically generated from OpenAPI specifications.

Readme

@nextplus/js-sdk

A TypeScript SDK for interacting with the NextPlus API, automatically generated from OpenAPI specifications.

Installation

npm install @nextplus/js-sdk

Usage

Authentication Methods

The SDK supports two authentication methods:

  1. Token-based authentication - Use an existing access token (recommended for React/browser apps)
  2. Credential-based authentication - Provide email/username + password (SDK handles login automatically)

Token-Based Authentication (Recommended for React/Browser Apps)

Perfect for apps where authentication is handled separately (e.g., OAuth, Firebase Auth, custom auth):

import { configure } from '@nextplus/js-sdk';

// With explicit baseURL
const sdk = configure({
  baseURL: 'https://your-nextplus-instance.com',
  accessToken: 'your-existing-token',
  returnType: 'data', // 'data' | 'raw'
});

// Auto-detect baseURL in browser (uses window.location.origin + '/api')
const sdk = configure({
  accessToken: userToken, // from your auth provider
  returnType: 'data',
});

// Use the SDK
const tables = await sdk.TableService.find({});

Credential-Based Authentication

The SDK automatically handles login and token refresh:

import { configure } from '@nextplus/js-sdk';

// With email
const sdk = configure({
  baseURL: 'https://your-nextplus-instance.com',
  email: '[email protected]',
  password: 'your-password',
  returnType: 'data',
});

// With username
const sdk = configure({
  baseURL: 'https://your-nextplus-instance.com',
  username: 'your-username',
  password: 'your-password',
  returnType: 'data',
});

Return Types

  • 'data': Returns only the response data (default behavior)
  • 'raw': Returns the full response object with { data, request, response }

Important: The returnType setting only applies when using service methods through the SDK instance (e.g., sdk.TableService.find()). When using sdk.client directly with individual service imports, responses are always in raw format ({ data, request, response }).

Error Handling

By default, non-OK responses return { error: ... } instead of throwing:

const response = await TableService.find({ limit: 10 });

if ('error' in response) {
  console.error('API Error:', response.error);
} else {
  console.log('Success:', response.data);
}

To make errors throw automatically, use throwOnError: true:

configure({
  accessToken: token,
  throwOnError: true, // Errors will throw
});

try {
  const response = await TableService.find({ limit: 10 });
  // Only success responses reach here
} catch (error) {
  // All API errors throw here
  console.error('API Error:', error);
}

| Configuration | Error Behavior | | ------------------------------- | --------------------------- | | returnType: 'data' (Full SDK) | ✅ Throws errors | | returnType: 'raw' (Full SDK) | ❌ Returns { error: ... } | | throwOnError: true | ✅ Throws errors | | Default (tree-shakeable) | ❌ Returns { error: ... } |

Usage Patterns

All patterns use the same configure() function!

Pattern 1: Full SDK (Convenient, with return type control)

import { configure } from '@nextplus/js-sdk';

const sdk = configure({
  accessToken: userToken,
  returnType: 'data', // Returns just the data
});

// Use service methods through SDK - returns transformed data
const tables = await sdk.TableService.find({ limit: 10 });
// tables = [{ ... }, { ... }] - just the array

Pattern 2a: Automatic Global Client (Cleanest - Recommended)

import { configure, TableService, UserModelService } from '@nextplus/js-sdk';

// Configure once - automatically becomes global default!
configure({
  accessToken: userToken,
  throwOnError: true, // Make errors throw (optional)
});

// Use anywhere in your app - no client parameter needed!
try {
  const response = await TableService.find({ limit: 10 });
  const user = await UserModelService.findById({ path: { id: '123' } });

  // Returns raw response format
  console.log(response.data); // The actual data
} catch (error) {
  // With throwOnError: true, errors are thrown
  console.error('API Error:', error);
}

Benefits:

  • ✅ Automatic - configure() sets global client automatically
  • ✅ No client parameter needed anywhere
  • ✅ Tree-shakeable - only import services you use
  • ✅ Optional error throwing with throwOnError: true
  • ✅ Clean code everywhere in your app

Pattern 2b: Bound Services (Per-component)

import { configure, TableService, UserModelService } from '@nextplus/js-sdk';

// Configure once
const sdk = configure({ accessToken: userToken });

// Bind services - no need to pass client every time!
const Tables = sdk.service(TableService);
const Users = sdk.service(UserModelService);

// Use bound services
const response = await Tables.find({ limit: 10 });
const user = await Users.findById({ path: { id: '123' } });

Pattern 2c: Manual Client (Explicit control)

const sdk = configure({ accessToken: userToken });

// Pass client explicitly each time
const response = await TableService.find({
  client: sdk.client,
  limit: 10,
});

Pattern 3: Manual Client Setup (Maximum control)

import { TableService } from '@nextplus/js-sdk/services';
import { createClient } from '@nextplus/js-sdk/sdk/client';

const client = createClient({
  baseUrl: window.location.origin + '/api',
});

// Add auth interceptor manually
client.interceptors.request.use((req) => {
  req.headers.set('Authorization', myToken);
  return req;
});

const response = await TableService.find({ client });

Comparison:

| Feature | Pattern 1: Full SDK | Pattern 2: Tree-shakeable | Pattern 3: Manual | | ------------------- | ------------------- | ------------------------- | ----------------- | | Function | configure() | configure() | createClient() | | Service access | sdk.ServiceName.* | Direct ServiceName.* | Direct | | Bundle size | Larger | Smaller | Smallest | | Return type control | ✅ 'data'/'raw' | ❌ Always raw | ❌ Always raw | | Auto-login | ✅ (credentials) | ✅ (credentials) | ❌ | | Complexity | Simple | Simple | More control | | Best for | Full apps | Modern bundlers | Advanced use |

Automatic Global Client

configure() automatically sets the global default client - no manual setup needed!

import { configure, TableService, UserModelService } from '@nextplus/js-sdk';

// Configure once - automatically becomes global default!
configure({ accessToken: token });

// Use anywhere in your app - no client needed!
const tables = await TableService.find({ limit: 10 });
const users = await UserModelService.find({ limit: 10 });

// No client parameter needed! ✨

Use Cases:

// React app initialization
function App() {
  useEffect(() => {
    // configure() automatically sets global client
    configure({ accessToken: getAuthToken() });

    return () => clearDefaultClient(); // Cleanup on unmount
  }, []);

  return <Routes />;
}

// Any component can now use services
function TableList() {
  const [tables, setTables] = useState([]);

  useEffect(() => {
    // No client parameter needed!
    TableService.find({ limit: 100 }).then(res => setTables(res.data));
  }, []);

  return <div>{/* render tables */}</div>;
}

Manual Control (Optional):

// Set global client manually
setDefaultClient(client);

// Get current global client
const client = getDefaultClient();

// Clear global client (useful for logout)
clearDefaultClient();

Client Override:

You can still pass a client parameter to override the global default:

configure({ accessToken: token1 }); // Sets global client

// Uses global client
await TableService.find({ limit: 10 });

// Uses specific client (overrides global)
await TableService.find({ client: customClient, limit: 10 });

Interceptors (Request/Response Middleware)

Add custom logic to all requests and responses:

import { configure } from '@nextplus/js-sdk';

const sdk = configure({ accessToken: token });

// Request interceptor - runs before every request
sdk.client.interceptors.request.use((request) => {
  console.log('Request:', request.url);
  // Add custom headers
  request.headers.set('X-Custom-Header', 'value');
  // Modify request
  return request;
});

// Response interceptor - runs after every successful response
sdk.client.interceptors.response.use((response) => {
  console.log('Response:', response.status);
  // Log or transform responses
  return response;
});

// Error interceptor - runs on any error
sdk.client.interceptors.error.use((error) => {
  console.error('API Error:', error);
  // Custom error handling, logging, etc.
  throw error; // Re-throw or handle
});

Common Use Cases:

// Add request ID to all requests
sdk.client.interceptors.request.use((request) => {
  request.headers.set('X-Request-ID', crypto.randomUUID());
  return request;
});

// Add retry logic
sdk.client.interceptors.error.use(async (error) => {
  if (error.response?.status === 429) {
    // Rate limited - wait and retry
    await new Promise((resolve) => setTimeout(resolve, 1000));
    // Retry logic here
  }
  throw error;
});

// Log all API calls
sdk.client.interceptors.request.use((request) => {
  console.log(`[API] ${request.method} ${request.url}`);
  return request;
});

Works with all patterns:

// Pattern 1: Full SDK
const sdk = configure({ accessToken: token });
sdk.client.interceptors.request.use(/* ... */);
await sdk.TableService.find({});

// Pattern 2: Tree-shakeable
const Tables = sdk.service(TableService);
await Tables.find({}); // Interceptors still apply!

// Pattern 3: Manual
await TableService.find({ client: sdk.client }); // Interceptors apply!

API Usage Examples

// Find with filters
const tables = await sdk.TableService.find({
  where: { name: 'my-table' },
  limit: 10,
  order: 'createdAt DESC',
});

// Find with filter object
const tables = await sdk.TableService.find({
  filter: {
    where: { name: 'my-table' },
    limit: 10,
  },
});

// Create a record
const newTable = await sdk.TableService.create({
  name: 'New Table',
  description: 'Table description',
});

// Update a record
const updated = await sdk.TableService.prototypePatchAttributes({
  path: { id: 'table-id' },
  name: 'Updated Name',
});

// With raw response type
const sdk = configure({
  accessToken: 'token',
  returnType: 'raw',
});

const response = await sdk.TableService.find({});
console.log(response.data); // Response data
console.log(response.request); // Request object
console.log(response.response); // Full HTTP response

Development

Prerequisites

  • Node.js (v18 or higher)
  • npm

Setup

# Install dependencies
npm install

# Generate SDK from OpenAPI spec and build
npm run generate

Available Scripts

  • npm run generate: Clean, generate from OpenAPI spec, and build
  • npm run build: Build TypeScript to JavaScript with type declarations
  • npm run clean: Remove the dist folder
  • npm run openapi-ts: Generate SDK from OpenAPI specification
  • npm run lint: Run ESLint

Development Workflow

  1. Make changes to the source code in src/
  2. Generate and build: npm run generate
  3. Test changes: npm run test (run smoke tests)
  4. Publish: npm publish (see Publishing section)

Code Generation

The SDK is automatically generated from OpenAPI specifications using @hey-api/openapi-ts. The generated code includes:

  • Type-safe API clients
  • Request/response type definitions
  • Authentication handling
  • Error handling

Generated files are located in src/sdk/ and should not be manually edited.

Testing

Test Commands

# Run full test suite (builds first, then runs tests)
npm test

# Run tests directly from TypeScript (faster for development)
npm run test:dev

# Run tests in watch mode (re-runs on file changes)
npm run test:watch

Test Suite

Make sure your NextPlus instance is running on localhost:3000 before running tests.

The test suite (src/smoke.ts) uses Node's built-in test runner and validates:

  • Token-based authentication
  • Email and username authentication
  • Different return types (data vs raw)
  • Tree-shakeable service imports
  • API calls to the TableService
  • Configuration validation and error handling

Manual Testing

// Test with token authentication
import { configure } from '@nextplus/js-sdk';

const sdk = configure({
  baseURL: 'http://localhost:3000',
  accessToken: 'your-test-token',
});

const result = await sdk.TableService.find({});
console.log(result);

// Test with credentials
const sdk2 = configure({
  baseURL: 'http://localhost:3000',
  email: '[email protected]',
  password: 'password',
});

const result2 = await sdk2.TableService.find({});
console.log(result2);

// Test tree-shakeable imports
import { configure, TableService } from '@nextplus/js-sdk';

const sdk = configure({
  accessToken: 'your-test-token',
});

const tables = await TableService.find({ client: sdk.client });
console.log(tables);

Publishing

Version Management

Update the version in package.json and publish:

# Bump version (patch, minor, or major)
npm version patch   # 0.0.3 -> 0.0.4
npm version minor   # 0.0.3 -> 0.1.0
npm version major   # 0.0.3 -> 1.0.0

# Publish to npm
npm publish

The prepublishOnly script automatically cleans and builds before publishing.

Publishing Steps

  1. Ensure you're logged in: npm whoami
  2. Build: npm run build (optional, done automatically)
  3. Publish: npm publish

Project Structure

├── src/
│   ├── index.ts           # Main SDK entry point
│   ├── smoke.ts           # Smoke test file
│   └── sdk/               # Generated SDK code (do not edit)
│       ├── client/        # API client implementations
│       ├── core/          # Core utilities and types
│       └── *.gen.ts       # Generated files
├── dist/                  # Built JavaScript and declarations
├── package.json
├── tsconfig.json
└── README.md

Configuration

OpenAPI Generation

Configure OpenAPI generation in openapi-ts.config.ts:

export default {
  input: 'path/to/openapi.json',
  output: './src/sdk',
  // ... other options
};

TypeScript

The project uses modern TypeScript with:

  • ES2020 target
  • ESNext modules
  • Strict type checking
  • Declaration file generation

License

MIT

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests: npm run test
  5. Build: npm run build
  6. Submit a pull request

Support

For issues and questions, please create an issue in the repository or contact the NextPlus team.