🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@dotuix/core

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@dotuix/core

Core library for packing, unpacking, and validating .uix files

Source
npmnpm
Version
0.1.0
Version published
Weekly downloads
6
-14.29%
Maintainers
1
Weekly downloads
 
Created
Source

@dotuix/core

Core library for creating, reading, and validating .uix files.

A .uix file is a ZIP archive containing an HTML app, assets, and optional SQLite databases. Think of it like a PDF — but interactive, offline, and self-contained in a single file.

Install

npm install @dotuix/core
# or
pnpm add @dotuix/core

Requires Node.js ≥ 22.

Quick Start

import { UIX } from "@dotuix/core";

// Pack a project folder into a .uix archive
await UIX.pack("./my-app", "./dist/myshop.uix");

// Unpack to a directory
await UIX.unpack("./myshop.uix", "./extracted/");

// Validate
const result = await UIX.validate("./myshop.uix");
console.log(result.valid, result.errors, result.warnings);

// Read the manifest
const manifest = await UIX.manifest("./myshop.uix");
console.log(manifest.name, manifest.version);

// Open the embedded read-only database
const data = await UIX.openData("./myshop.uix", { permissions: [] });
if (data) {
  const products = data.find({
    type: "product",
    where: { category: "burgers" },
  });
  data.close();
}

// Create / load state.db in memory
const state = await UIX.createState({ uixVersion: "1.0", permissions: [] });
const id = state.insert({
  type: "cart_item",
  body: { productId: "p:001", qty: 2 },
});
const item = state.get(id);
const bytes = state.export(); // serialize for repacking
state.close();

API

Packing & Unpacking

pack(srcDir, outputPath)

Pack a folder into a .uix file on disk (Node.js).

  • Reads manifest.json from srcDir and validates it.
  • Compresses HTML/CSS/JS/JSON with DEFLATE. Stores .db, images, and media with STORE (no compression).
  • Writes atomically via .tmp → rename.
await UIX.pack("./my-app", "./dist/myshop.uix");

packBuffer(files)

Pack an in-memory file map into a Uint8Array (universal — browser + Node.js).

const encoder = new TextEncoder();
const buf = await UIX.packBuffer({
  "manifest.json": encoder.encode(JSON.stringify(manifest)),
  "index.html": encoder.encode("<html>…</html>"),
});

unpack(uixPath, outDir)

Extract a .uix archive to a directory on disk (Node.js).

await UIX.unpack("./myshop.uix", "./extracted/");

unpackBuffer(data)

Extract a .uix buffer into an in-memory file map (universal).

const files = UIX.unpackBuffer(data); // Record<string, Uint8Array>
const html = new TextDecoder().decode(files["index.html"]);

Validation

validate(uixPath) / validateBuffer(data)

Returns { valid: boolean; errors: string[]; warnings: string[] }.

Checks:

  • manifest.json exists and is valid (required fields, id format, expiry)
  • Entry file declared in manifest exists in the archive
  • File has not expired
  • (Warning, not error) Media/document files found outside assets/ or files/
  • (Warning) security.encryptedPaths lists a file not present in the archive
  • (Warning) security.auth: "pin" declared but encryptedPaths or keySalt missing
const result = await UIX.validate("./myshop.uix");
if (!result.valid) console.error(result.errors);
if (result.warnings.length) console.warn(result.warnings);

Manifest

manifest(uixPath) / manifestFromBuffer(data)

Read and parse the manifest from an archive.

const m = await UIX.manifest("./myshop.uix");
// m.id, m.name, m.version, m.entry, m.mode, m.permissions, …

parseManifest(raw) / safeParseManifest(raw)

Validate a raw manifest object using Zod. parseManifest throws on invalid input; safeParseManifest returns a Zod SafeParseReturnType.

Databases

Both data.db (read-only, creator-shipped) and state.db (read-write, user-owned) share the same schema:

CREATE TABLE records (
  id         TEXT    PRIMARY KEY,
  type       TEXT    NOT NULL,
  body       TEXT    NOT NULL,   -- JSON, shape decided by the .uix app
  created_at INTEGER NOT NULL DEFAULT (unixepoch()),
  updated_at INTEGER NOT NULL DEFAULT (unixepoch())
);

openData(uixPath, opts?) / openDataBuffer(data, opts?)

Open data.db from a .uix archive. Returns UIXDataDB | null (null if the archive has no data.db).

const db = await UIX.openData("./myshop.uix", { permissions: ["raw-sql"] });
if (db) {
  db.find({ type: "product" });
  db.find({ type: "product", where: { category: "مشويات" }, limit: 10 });
  db.get("product:001");
  db.raw("SELECT body FROM records WHERE type = ? ORDER BY rowid", ["product"]);
  db.close();
}

createState(opts)UIXStateDB

Create a fresh state.db in memory, or load from a seed.

const state = await UIX.createState({ uixVersion: "1.0" });

// With a seed (from manifest.state.seed = true)
const seed = files["state.db"]; // Uint8Array from unpackBuffer
const state = await UIX.createState({
  uixVersion: "1.0",
  seed,
  permissions: [],
});

openStateFromFile(statePath, opts?)UIXStateDB

Load an existing state.db file from disk (Node.js). Useful for CLI export commands.

UIXDataDB methods

MethodDescription
find(query)Find records by type, with optional where, orderBy, limit
get(id)Get a single record by id, or null
raw(sql, params?)Execute a SELECT/WITH statement. Requires "raw-sql" permission.
close()Release the database

UIXStateDB methods

MethodDescription
find(query)Find records by type
get(id)Get a single record by id, or null
insert({ type, body })Insert a record. Returns the generated id ({type}:{uuid}).
update(id, body)Update a record's body. Bumps updated_at.
delete(id)Delete a record by id
raw(sql, params?)Execute any SQL. Requires "raw-sql" permission.
purge({ type, olderThan })Delete records older than a duration ('30d', '12h', '1y'). Returns count.
export()Serialize the database to Uint8Array for repacking.
close()Release the database

FindQuery

interface FindQuery {
  type: string;
  where?: Record<string, unknown>; // json_extract filters on body fields
  orderBy?: string; // column name or body field
  limit?: number;
}

Format

Archive structure

myapp.uix (ZIP)
├── manifest.json        ← required
├── index.html           ← entry point
├── app.js
├── style.css
├── assets/              ← media files (images, video, audio, fonts)
│   ├── images/
│   ├── videos/
│   ├── audio/
│   └── fonts/
├── files/               ← any other file: PDF, JSON, CSV, plain text, …
├── data.db              ← optional: read-only SQLite (creator data)
└── state.db             ← optional: read-write SQLite (user session)

assets/ and files/ are conventions, not requirements. Files can live anywhere in the archive and are referenced via normal relative HTML paths. The validator emits a warning (never an error) if media files are found outside these folders.

manifest.json

Minimal (restaurant, shop, any regular app):

{
  "uix": "1.0",
  "id": "com.almadina.menu",
  "name": "Al Madina Restaurant Menu",
  "version": "2.1.0",
  "entry": "index.html",
  "mode": "kiosk",
  "permissions": ["local-storage", "print"],
  "network": "blocked",
  "author": "emad@domain.com",
  "expires": null,
  "state": { "seed": false }
}

With optional security block (government / classified use case — omit entirely for regular apps):

{
  "uix": "1.0",
  "id": "gov.qa.briefing.classified",
  "name": "Ministry Briefing Q2 2026",
  "version": "1.0.0",
  "entry": "index.html",
  "mode": "kiosk",
  "permissions": [],
  "network": "blocked",
  "expires": "2026-06-30",
  "security": {
    "auth": "pin",
    "encryptedPaths": ["data.db", "files/annex-a.pdf"],
    "kdf": "PBKDF2-SHA256",
    "kdfIterations": 200000,
    "keySalt": "base64url-random-salt",
    "maxOpens": 3,
    "screenshot": false
  },
  "signature": {
    "algorithm": "Ed25519",
    "publicKey": "base64url-public-key",
    "value": "base64url-signature",
    "signedAt": "2026-05-19T10:00:00Z"
  }
}

mode: kiosk (locked UI, no browser chrome) or window (developer preview).

permissions: local-storage, print, clipboard-write, fullscreen, raw-sql.

network: blocked (default) or allowed.

security fields (all optional — omit the block for regular apps):

FieldDefaultDescription
auth"none""pin" — viewer prompts for PIN before opening
encryptedPaths[]Paths inside the archive encrypted with AES-256-GCM
kdf"PBKDF2-SHA256"Key derivation function
kdfIterations200000PBKDF2 iterations (higher = slower brute-force)
keySaltBase64url random salt stored in manifest (safe to store publicly)
maxOpensunlimitedMax opens tracked by the viewer locally — file cannot bypass this
screenshotfalsetrue = viewer blocks OS screenshot API (desktop only)

Compression

File typeZIP method
HTML, CSS, JS, JSON, textDEFLATE (level 6)
PNG, JPG, JPEG, WEBP, GIF, SVG, MP4, MP3, WEBM, WASMSTORE
.db filesSTORE
PDF, DOCX, XLSX and other already-compressed formatsSTORE

License

MIT

Keywords

uix

FAQs

Package last updated on 19 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts