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

@orca-scan/orca-scan-node

v1.2.1

Published

The official node client for the Orca Scan API

Readme

orca-scan-node

The official Node.js client for the Orca Scan barcode tracking system.

Full API Reference: Barcode Scanning REST API

Key concepts

Orca Scan feels like a spreadsheet, but developers should think of each sheet as a database and each column as a strongly typed field.

  • Sheet: A table that stores rows of data
  • Row: A single record in a sheet, such as an inventory item
  • Field: A typed column in a sheet, such as name or quantity
  • Hook: A webhook that notifies you when data changes

With this Node SDK you can:

  • Sheets: Create and manage sheets
  • Rows: Add, update, delete, and count rows
  • Fields: Manage fields and their properties
  • History: Track changes to sheets and rows
  • Users: Manage user access and permissions
  • Hooks: Configure webhook notifications

Quick Start

var OrcaScanNode = require('@orca-scan/orca-scan-node');
var orca = new OrcaScanNode('your-api-key');

async function main() {

  // 1. Create a sheet
  var sheet = await orca.sheets.create({ name: 'Inventory' });

  // 2. Add some fields
  await orca.fields.create(sheet._id, { label: 'Product Name', format: 'text' });
  await orca.fields.create(sheet._id, { label: 'Quantity', format: 'number' });

  // 3. Add some rows
  await orca.rows.add(sheet._id, [
    { 'Product Name': 'Laptop', Quantity: 5 },
    { 'Product Name': 'Chair', Quantity: 10 }
  ]);

  // 4. Add a user
  await orca.users.add(sheet._id, { email: '[email protected]', canUpdate: true });

  // 5. Get the rows
  var rows = await orca.rows.list(sheet._id);

  console.log('Rows:', rows);
}

main().catch(console.error);

Install

npm install @orca-scan/orca-scan-node

Usage

var OrcaScanNode = require('@orca-scan/orca-scan-node');

// get your API key from cloud.orcascan.com > account settings
var orca = new OrcaScanNode('your-api-key', {
    endpoint: 'https://api.orcascan.com/v1', // API endpoint (default)
    timeoutMs: 30000,                        // Request timeout (default: 30 sec)
    maxRetries: 3                            // Max retry attempts (default: 3)
});

API

Sheets

// list all sheets
orca.sheets.list().then(function(sheets) {
    console.log(sheets);
});

// create new sheet
orca.sheets.create({
    name: 'Inventory',
    templateName: 'inventory'  // optional
}).then(function(sheet) {
    console.log('Sheet created:', sheet);
});

// clear all rows in a sheet
orca.sheets.clear('sheet-id').then(function(result) {
    console.log('Sheet cleared');
});

// rename a sheet
orca.sheets.rename('sheet-id', { 
    name: 'New Sheet Name',
    description: 'Optional description'  // optional
}).then(function(result) {
    console.log('Sheet renamed');
});

// delete sheet
orca.sheets.delete('sheet-id').then(function(result) {
    console.log('Sheet deleted');
});

Settings

// get sheet settings
orca.settings.get('sheet-id').then(function(settings) {
    console.log('Sheet settings:', settings);
});

// update sheet settings
orca.settings.update('sheet-id', {}).then(function(settings) {
    console.log('Sheet settings updated:', settings);
});

Fields

// list all fields in a sheet
orca.fields.list('sheet-id').then(function(fields) {
    console.log('Sheet fields:', fields);
});

// create a new field
orca.fields.create('sheet-id', {
    label: 'Product Code',
    format: 'text',
    required: true,
    placeholder: 'Enter product code'
})
.then(function(field) {
    console.log('Field created:', field);
});

// create field with advanced options
orca.fields.create('sheet-id', {
    label: 'Product Photo',
    format: 'photo',
    required: false,
    hiddenWeb: true,
    useInMobileSearch: false,
    useValueInList: true
})
.then(function(field) {
    console.log('Advanced field created:', field);
});

// update a field
orca.fields.update('sheet-id', 'field-key', {
    label: 'Updated Label',
    required: false
})
.then(function(field) {
    console.log('Field updated:', field);
});

// delete a field
orca.fields.delete('sheet-id', 'field-key').then(function(result) {
    console.log('Field deleted');
});

// upsert multiple fields - creates a field if it does not exist, otherwise updates it
orca.fields.upsert('sheet-id', [
    { label: 'Quantity', format: 'number' },
    { label: 'Notes', format: 'text', required: true }
])
.then(function(fields) {
    console.log('Fields upserted:', fields);
});

Note: create, update, delete, and upsert require canAdmin: true for the API key's user on the sheet. Attempting these without admin rights returns a 403 Forbidden.

Field options

| Name | Type | Description | |:--------------------|:----------|:------------------------------------------------------------------------------------------| | key | string | Internal identifier (readonly) | | label | string | Title of the field in the app | | type | string | Data type | | format | string | See Field formats below ↓ | | default | any | Default value for the field when empty | | listOptions | array | If dropdown, options to present to users | | multiSelect | boolean | If true, allows multiple selection | | formula | string | Calculation for “formula” fields | | currencyType | string | Currency code for “currency” fields, following the ISO 4217 standard (e.g. USD, EUR, GBP) | | locked | boolean | Prevent users changing field properties | | minLength | integer | Minimum number of characters allowed | | maxLength | integer | Maximum number of characters allowed | | minimum | integer | Minimum number allowed | | maximum | integer | Maximum number allowed | | placeholder | string | Guidance to the user when field is empty | | prefix | string | If Unique ID, text before value | | suffix | string | If Unique ID, text after value | | length | integer | If Unique ID, total length of ID | | required | boolean | User must provide a value (default: false) | | autofocus | boolean | Auto select this field first (default: false) | | autoselect | boolean | Highlight existing text on focus (default: false) | | emptyOnEdit | boolean | Clear value when record edited (default: false) | | emptyOnScan | boolean | Remove existing value on scan (default: false) | | hiddenMobile | boolean | Hide the field on mobile (default: false) | | hiddenWeb | boolean | Hide the field on web (default: false) | | readonlyWeb | boolean | Prevent user input on web (default: false) | | readonlyMobile | boolean | Prevent user input on mobile (default: false) | | useInMobileSearch | boolean | Include value in mobile search (default: false) | | useValueInList | boolean | Show field value in mobile list (default: false) | | index | integer | Display order of the field (default: -1) |

Field formats

| Format | Description | |:---------------------------------|:--------------------------------------------------| | text | Plain text | | barcode | Barcode value populated on scan | | number | Stores a number (integer or decimal) | | number (auto increase on scan) | Number that auto increases on scan | | number (auto decrease on scan) | Number that auto decreases on scan | | date | Date field the user can set manually | | date (automatic) | Date field that auto sets on scan | | date time | Date and Time field the user can set manually | | date time (automatic) | Date and Time that auto sets on scan | | time | Time field the user can set manually | | email | Capture an email address | | gps location | User assigned GPS location | | gps location (automatic) | Auto assigned GPS location on scan | | true/false | True or False toggle field | | currency | Stores a monetary value | | drop-down list | List of options to present to users | | formula | Calculates the value of two or more fields | | signature | Captures a signature with date, time and location | | unique id | Generates a unique ID per record | | photo | Allows a user to add a photo | | attachment | Allows a user to upload a file | | url | Allows a user to enter a URL | | created by | Auto email of user who created the record | | created date | Auto date/time the record was created | | last modified by | Auto email of user who last modified the record | | last modified date | Auto date/time the record was last updated |

Rows

var options = { withTitles: true };

// list all rows in a sheet
orca.rows.list('sheet-id', options).then(function(rows) {
    console.log(rows);
});

// get a single row
orca.rows.get('sheet-id', 'row-id', options).then(function(row) {
    console.log(row);
});

// add single row
orca.rows.add('sheet-id', {
    name: 'Laptop',
    quantity: 5
}, options)
.then(function(row) {
    console.log('Row added:', row);
});

// add row with photo (base64 encoded)
orca.rows.add('sheet-id', {
    name: 'Product with Photo',
    photo: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ...',
    quantity: 1
}, options)
.then(function(row) {
    console.log('Row with photo added:', row);
});

// add row with attachment (base64 encoded)
orca.rows.add('sheet-id', {
    name: 'Product with Manual',
    manual: 'data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwo...',
    quantity: 1
}, options)
.then(function(row) {
    console.log('Row with attachment added:', row);
});

// add multiple rows
orca.rows.add('sheet-id', [
    { name: 'Item 1', quantity: 5 },
    { name: 'Item 2', quantity: 10 }
], options)
.then(function(rows) {
    console.log('Rows added:', rows);
});

// update one row (partial: true updates only provided fields, leaving others intact)
orca.rows.updateOne('sheet-id', 'row-id', {
    quantity: 15
}, { partial: true })
.then(function(row) {
    console.log('Row updated:', row);
});

// update many rows
orca.rows.updateMany('sheet-id', [
    { _id: 'row1', quantity: 15 },
    { _id: 'row2', quantity: 20 }
], { partial: true })
.then(function(rows) {
    console.log('Rows updated:', rows);
});

// delete one row
orca.rows.deleteOne('sheet-id', 'row-id').then(function(result) {
    console.log('Row deleted');
});

// delete multiple rows
orca.rows.deleteMany('sheet-id', ['row1', 'row2']).then(function(result) {
    console.log('Rows deleted');
});

// get row count
orca.rows.count('sheet-id').then(function(result) {
    console.log('Total rows:', result.count);
});

Each rows method accepts an optional options object. Supported options:

  • withTitles: Return field titles instead of field keys
  • partial: Update only the provided fields and leave all others unchanged (supported by add, updateOne, and updateMany)

History

// get sheet history
orca.history.sheet('sheet-id').then(function(entries) {
    console.log(entries);
});

// get row history
orca.history.row('sheet-id', 'row-id').then(function(entries) {
    console.log(entries);
});

Users

// list users on a sheet
orca.users.list('sheet-id').then(function(users) {
    console.log(users);
});

// add a user to a sheet
orca.users.add('sheet-id', {
    email: '[email protected]',
    canUpdate: true,
    canDelete: false,
    canExport: true,    // optional
    canAdmin: false     // optional
})
.then(function(user) {
    console.log('User added:', user);
});

// update a user on a sheet
orca.users.update('sheet-id', 'user-id', {
    canUpdate: false,
    canDelete: true
})
.then(function(user) {
    console.log('User updated:', user);
});

// remove a user from a sheet
orca.users.remove('sheet-id', 'user-id').then(function(result) {
    console.log('User removed');
});

Hooks

// get supported hook events
orca.hooks.events('sheet-id').then(function(events) {
    console.log(events);
});

// list all hooks on a sheet
orca.hooks.list('sheet-id').then(function(hooks) {
    console.log(hooks);
});

// get a single hook
orca.hooks.get('sheet-id', 'hook-id').then(function(hook) {
    console.log(hook);
});

// create a hook
orca.hooks.create('sheet-id', {
    eventName: 'rows:add',
    targetUrl: 'https://example.com/webhook'
})
.then(function(hook) {
    console.log('Hook created:', hook);
});

// update a hook
orca.hooks.update('sheet-id', 'hook-id', {
    targetUrl: 'https://example.com/new-webhook'
})
.then(function(hook) {
    console.log('Hook updated:', hook);
});

// delete a hook
orca.hooks.delete('sheet-id', 'hook-id').then(function(result) {
    console.log('Hook deleted');
});

Error Handling

The SDK automatically unwraps API responses. If the API returns { data: ... }, your .then(...) handler receives the inner value directly. Here's how you can handle errors in your code:

orca.sheets.list().then(function(sheets) {

    // Success! 'sheets' contains the list of sheets
    console.log('Success!', sheets);
})
.catch(function(error) {

    // All errors have a 'message'.
    console.error('Error message:', error.message);

    // If the error is from the API (like 400, 401, 404), these will also be set:
    if (error.status) {
        console.error('HTTP Status:', error.status); // e.g. 404
    }
    if (error.body) {
        console.error('Response body:', error.body); // More details from the server
    }

    // For network errors or timeouts, 'status' and 'body' may be undefined
});

// Example error object for a 404:
// {
//   message: 'HTTP 404',
//   status: 404,
//   body: { error: 'Resource not found' }
// }

Errors

| Error | What it means | How to fix | |:---------------------|:-------------------|:--------------------------------------| | apiKey is required | Missing API key | Add your API key when creating client | | http 401 | Invalid API key | Check your API key is correct | | http 403 | Permission denied | Verify your access rights | | http 429 | Too many requests | Requests are automatically retried | | http 404 | Resource not found | Check sheet/row/field ID is correct | | http 400 | Bad request | Check required fields and data types |

Automatic Retries

The client will automatically retry on:

  • Rate limits (429)
  • Service unavailable (503)
  • Server errors (5xx)

Default: 3 retry attempts with linear backoff (500ms, 1000ms, 1500ms), or respects the Retry-After header if present

Request Timeouts

Use timeoutMs to control how long the SDK waits before rejecting a request. The timeout is applied to the SDK promise. If the timeout is reached, the promise rejects with request timeout, but the underlying HTTP request is not actively aborted.

File Uploads

The client supports file uploads for photo and attachment fields:

  • Photos: .jpg, .png, .gif, .bmp, .webp, .tiff, .svg
  • Attachments: .doc, .docx, .csv, .txt, .ppt, .pptx, .pdf, .xls, .xlsx, .mp4

Files should be provided as base64 strings with appropriate data URI format.

Rate Limits

API rate limit: 15 requests per second. The client automatically handles rate limiting with retries and respects the Retry-After header when provided.

Running Tests

npm test

Need Help?

License

Licensed under MIT License © Orca Scan -> Barcode Tracking Software.