JSPM

catsa-janga

1.0.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 8
  • Score
    100M100P100Q33432F
  • License MIT

Save and restore data for long-running processes.

Package Exports

  • catsa-janga

Readme

catsa-janga

wakatime Node.js CI GitHub License GitHub Release codecov 0 Dependencies Size typescript Types npm npm GitHub issues GitHub stars Node & Bun Maintenance

A utility library for automatically saving and restoring progress in long-running Bun applications.

Features

  • 💾 Automatically saves progress data to a file
  • 🔄 Restores progress data when restarting a process
  • 🛑 Handles process termination signals (SIGINT, SIGTERM)
  • ⚠️ Captures unhandled exceptions and promise rejections
  • 🔍 Lightweight with no external dependencies
  • 📝 TypeScript support

Installation

# Using Bun
bun add catsa-janga

# Using npm
npm install catsa-janga

Usage

Basic Example - Using createWithRestore

The recommended way to use CatsaJanga is with the createWithRestore method:

import { CatsaJanga } from 'catsa-janga';

// Define your data structure
type MyData = {
    items: string[];
    processedCount: number;
    timestamp: Date;
};

// Create and restore in one step
const { saver, data } = await CatsaJanga.createWithRestore<MyData>({
    getData: () => ({
        ...data,
        timestamp: new Date(), // Update timestamp on save
    }),
    logger: console, // Use console as logger
    outputFile: 'progress.json',
    initialData: {
        items: [],
        processedCount: 0,
        timestamp: new Date(),
    },
});

// Your long-running process
async function processItems() {
    for (let i = 0; i < 1000; i++) {
        // Simulate work
        await new Promise((resolve) => setTimeout(resolve, 100));

        // Update data
        data.items.push(`Item ${i}`);
        data.processedCount++;

        // Optionally save progress periodically
        if (i % 100 === 0) {
            await saver.saveProgress();
        }
    }

    // Save final progress
    await saver.saveProgress();
}

// Start processing
await processItems();

Alternative Approach - Using Object.assign

If you prefer to have more control over initialization, you can use the traditional method:

import { CatsaJanga } from 'catsa-janga';

// Define your data structure
type MyData = {
    items: string[];
    processedCount: number;
    timestamp: Date;
};

// Create initial data
const data: MyData = {
    items: [],
    processedCount: 0,
    timestamp: new Date(),
};

// Create a progress saver
const saver = new CatsaJanga<MyData>({
    getData: () => ({
        ...data,
        timestamp: new Date(), // Update timestamp on save
    }),
    logger: console, // Use console as logger
    outputFile: 'progress.json',
});

// Restore previous progress if available
const restored = await saver.restore();
Object.assign(data, restored);

// Your long-running process
async function processItems() {
    for (let i = 0; i < 1000; i++) {
        // Simulate work
        await new Promise((resolve) => setTimeout(resolve, 100));

        // Update data
        data.items.push(`Item ${i}`);
        data.processedCount++;

        // Optionally save progress periodically
        if (i % 100 === 0) {
            await saver.saveProgress();
        }
    }

    // Save final progress
    await saver.saveProgress();
}

// Start processing
await processItems();

Real-world example

Here's how you might use it in a scraping or OCR application:

import { CatsaJanga } from 'catsa-janga';

// Define your data structure
type OCRResult = {
    pages: Array<{ page: number; text: string }>;
    timestamp: Date;
};

// Create initial data
const initialData: OCRResult = {
    pages: [],
    timestamp: new Date(),
};

// Create and restore in one step
const { saver, data } = await CatsaJanga.createWithRestore<OCRResult>({
    getData: () => ({
        ...data,
        pages: data.pages.toSorted((a, b) => a.page - b.page),
        timestamp: new Date(),
    }),
    logger: console,
    outputFile: 'ocr-progress.json',
    initialData,
});

// Process pages (if we crash, we'll resume where we left off)
for (const file of files) {
    if (data.pages.some((p) => p.page === file.pageNumber)) {
        console.log(`Skipping already processed page ${file.pageNumber}`);
        continue;
    }

    const result = await processOCR(file);
    data.pages.push({ page: file.pageNumber, text: result });

    // Save periodically
    if (data.pages.length % 10 === 0) {
        await saver.saveProgress();
    }
}

// Final save
await saver.saveProgress();

API

CatsaJanga

The main class for saving and restoring progress.

Constructor

constructor(options: CatsaJangaOptions<T>)

Options:

  • getData: Function that returns the current data to save
  • logger: Logger object with at least info and error methods (compatible with console, Pino, etc.)
  • outputFile: File path where progress will be saved
  • initialData (optional): Initial data to use if no saved data exists

Methods

restore
async restore(): Promise<T | undefined>

Checks for an existing progress file and restores data if present. Returns the restored data, the initialData (if provided and no saved data exists), or undefined.

saveProgress
async saveProgress(): Promise<void>

Saves the current progress to the output file.

createWithRestore (static)
static async createWithRestore<T>(options: CatsaJangaOptions<T>): Promise<{ saver: CatsaJanga<T>, data: T }>

Creates a CatsaJanga instance and immediately restores data if available. Returns both the saver instance and the restored or initial data.

Interfaces

Logger

interface Logger {
    error: (message: string, ...args: any[]) => void;
    info: (message: string, ...args: any[]) => void;
    warn?: (message: string, ...args: any[]) => void;
}

Compatible with console, Pino loggers, and other similar logging libraries.

CatsaJangaOptions

interface CatsaJangaOptions<T> {
    getData: () => T;
    logger: Logger;
    outputFile: string;
    initialData?: T;
}

Error Handling

catsa-janga automatically registers handlers for:

  • SIGINT (Ctrl+C)
  • SIGTERM (process termination)
  • uncaughtException (unhandled errors)
  • unhandledRejection (unhandled promise rejections)

When any of these events occur, the progress will be saved before the process exits.

License

MIT