Getting Started

Install StickCode v6.0.15, activate your license, and encrypt data in one API call.

Installation

Install from npm. Prebuilt native binaries are bundled for most platforms — no compiler required on macOS x64. Linux may compile from source if no matching prebuild exists.

npm install stickcode

Add StickCode to your project with a caret range so future updates work with npm update:

npm install stickcode --save
# package.json will contain:
# "stickcode": "^6.0.15"

Requires Node.js 18+. Verify the CLI:

npx stick --help

Updating StickCode

After the vendor publishes a new release, update your installation with standard npm commands. Patch and minor releases within 6.x stay backward compatible — your existing .scnp files keep working without re-encryption.

1. Use a caret range in package.json

The ^ prefix tells npm it may install newer compatible versions (6.0.15, 6.1.0, etc.) when you run npm update:

{
  "dependencies": {
    "stickcode": "^6.0.15"
  }
}
✅ Recommended "stickcode": "^6.0.15"
npm update stickcode works automatically
❌ Avoid exact pin "stickcode": "6.0.14"
npm update will not upgrade — you must edit package.json manually

2. Run the update

# Update StickCode only (recommended)
npm update stickcode

# Or update all dependencies in the project
npm update

# Install a specific latest 6.x release
npm install stickcode@^6.0.15

3. Verify the new version

npm list stickcode
node -e "console.log(require('stickcode/package.json').version)"

What you do not need to change

  • License file (*.lic) — same file, same path
  • Application codeinitFromFile(), encrypt(), decrypt() API unchanged within 6.x
  • Encrypted archives — existing .scnp files decrypt with the new SDK (version compatibility)
  • Device activation — local .device_registry in node_modules/stickcode/ is preserved across updates on the same machine

License activation

Production builds require a signed *.lic file. Place it in your project root, ~/.config/stickcode/, or /etc/stickcode/, then initialize once per process:

const stickcode = require('stickcode');

await stickcode.initFromFile();
// or: await stickcode.initFromFile('/etc/stickcode/license.lic');

The AES key is derived via HKDF-SHA256 from the server-signed activation token — never hard-code keys in production. CLI requires --license or STICKCODE_LICENSE_FILE (no default passphrase).

Processing modes

v6.0.x unifies buffer and stream pipelines under one module. Choose the right path for your payload size.

1. Encrypted (default)

Preprocess → Brotli → AES-256-GCM. Wire format version 0x05. Ideal for PII, backups, and exports.

const packed = stickcode.encrypt(data, { quality: 6 });
const plain = stickcode.decrypt(packed);

2. Compression only

Brotli without AES. Wire format version 0x00. Use when data is already secured or for storage-only pipelines.

const blob = stickcode.compressOnly(data, { quality: 6 });

Streaming large files

For DB dumps, video, and archives — constant memory via stream helpers. Output uses the .scnp convention.

const fs = require('fs');

await stickcode.pipeEncrypt(
  fs.createReadStream('backup.sql'),
  fs.createWriteStream('backup.sql.scnp'),
  { quality: 6 }
);

await stickcode.pipeDecrypt(
  fs.createReadStream('backup.sql.scnp'),
  fs.createWriteStream('backup.sql.restored')
);

Versioning & backward compatibility

StickCode uses two separate version concepts. This section explains both, what decrypt() detects automatically, and what you never need to pass as a parameter.

1. npm package version

The SDK release you install, e.g. stickcode@^6.0.15. Upgrading the package does not require re-encrypting existing archives — as long as they were created with the 6.x wire format below.

2. Wire format version byte

The first byte of every .scnp output. Tells the engine whether the payload is encrypted or compress-only. decrypt() reads this byte automatically — you never pass it.

Wire format version bytes (current engine)

Byte Meaning Created by
0x05 Encrypted — Brotli + AES-256-GCM encrypt() · pipeEncrypt()
0x00 Compress-only — Brotli, no AES compressOnly()

On encrypt — always the current format

Every new encryption uses the latest wire format. There is no option to write an older layout.

  • encrypt() and pipeEncrypt() always write version byte 0x05
  • compressOnly() always writes version byte 0x00
  • Brotli quality (0–11) is your choice at write time; default is 6

On decrypt — three things detected automatically

Call decrypt(buffer) or pipeDecrypt() with no version or quality parameters. The native engine inspects the payload and decides:

① Wire version byte (byte 0)

0x05 → decrypt AES-GCM, then decompress Brotli. 0x00 → decompress Brotli only. Any other value → decrypt fails.

② Brotli compression level (quality 0–11)

Embedded inside the Brotli bitstream. The decoder reads dictionary and token metadata from the payload itself — you do not pass quality to decrypt(). A file compressed at quality 4 opens correctly even if you now encrypt new data at quality 11.

③ Buffer vs stream layout (CLI only)

Two physical layouts exist for where the GCM auth tag sits:

Buffer:  [version][iv:12][tag:16][ciphertext…]   ← encrypt()
Stream:  [version][iv:12][ciphertext…][tag:16]   ← pipeEncrypt()

In application code, use the matching API: decrypt() for buffer output, pipeDecrypt() for stream output. The CLI command stick dec tries buffer layout first, then falls back to stream — automatically.

Behind the scenes — decrypt pipeline

decrypt(input)
  │
  ├─ Read byte[0]  →  version (0x05 or 0x00)
  │
  ├─ If 0x05 (encrypted):
  │     Parse IV (12 B) + auth tag (16 B) + ciphertext
  │     Verify AES-256-GCM tag  →  fail fast if tampered
  │     Decompress Brotli  →  quality read from bitstream (not from caller)
  │
  └─ If 0x00 (compress-only):
        Decompress Brotli directly  →  quality read from bitstream

Compatibility matrix

Scenario Works automatically?
Decrypt archive created with 0x05 on any 6.x package Yes
Decrypt archive created with 0x00 (compress-only) Yes
Open file compressed at quality 1 after upgrading SDK to 6.0.15 Yes — no re-encryption needed
Mix quality levels in the same database (some Q4, some Q9) Yes — each blob self-describes its compression
CLI stick dec on unknown buffer/stream layout Yes — auto-detects layout
Legacy wire format 0x04 (pre-6.x JavaScript engine) No — re-encrypt with 6.x or contact support for migration

Summary for developers

  • Encrypt: always writes 0x05 (or 0x00 for compress-only) — you choose quality only.
  • Decrypt: pass the buffer or stream only — version byte, compression level, and (in CLI) layout are resolved internally.
  • Upgrade SDK: existing 6.x .scnp files keep working; no migration step required.

Compression quality & CPU latency

Brotli quality runs from 0 (fastest) to 11 (smallest output). API and CLI default is 6. Quality is write-onlydecrypt() reads the bitstream without needing the original level.

⚠️ Maximum quality (10–11) — offline / batch only Shrinks files to the mathematical minimum but introduces severe CPU cost. Use on worker threads or scheduled jobs, not live request paths.
⚙️ Standard quality (5–9) — scheduled archives Stronger dictionary matching with manageable latency (hundreds of ms on MB-scale payloads). Good for log rotation and ETL batches.
⚡ Low quality (0–4) — live applications Excellent savings on text with sub-100ms times on typical API payloads. Recommended for real-time encrypt/compress in request handlers.
🔄 Asymmetric decryption

The native decoder reads Brotli metadata embedded in the payload. You can rotate quality tiers across datasets without breaking backward compatibility — no quality flag needed on decrypt().

Quick Start

Full production flow — license, buffer encrypt, and CLI equivalent:

const fs = require('fs');
const stickcode = require('stickcode');

// 1. Activate license (once per process)
await stickcode.initFromFile();

// 2. Encrypt JSON / text in memory
const input = fs.readFileSync('report.json');
const packed = stickcode.encrypt(input, { quality: 6 });
fs.writeFileSync('report.json.scnp', packed);

// 3. Decrypt — quality not required
const restored = stickcode.decrypt(packed);

// CLI equivalent:
// npx stick enc report.json --license ./license.lic
// npx stick dec report.json.scnp

💾 Storage & networking

Always treat output as binary — never base64-encode unless your transport requires it.

  • 1. Saving to disk

    fs.writeFileSync('data.scnp', packed);
  • 2. Network transfers

    await axios.post(url, packed, {
      headers: { 'Content-Type': 'application/octet-stream' }
    });
  • 3. Database storage

    MongoDB (Mongoose):

    encryptedData: { type: Buffer }

    PostgreSQL (Sequelize):

    payload: DataTypes.BLOB