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

@ticatec/script-loader

v0.1.4

Published

A powerful TypeScript dynamic script loading and management library with real-time script updates, caching management, and timestamp persistence.

Readme

@ticatec/script-loader

Node.js Version TypeScript License: MIT

A powerful TypeScript dynamic script loading and management library with real-time script updates, caching management, and timestamp persistence.

Features

  • 🚀 Dynamic Script Loading - Runtime dynamic loading and updating of JavaScript scripts
  • Timestamp Persistence - Automatically save and restore last update timestamp
  • 🔄 Real-time Updates - Periodically check for script updates and apply them automatically
  • 💾 Smart Caching - In-memory caching of script modules with require cache management
  • 🔥 Hot Reload - Support for script hot reloading without application restart
  • 🧩 Singleton Manager - Centralized script management with DynaModuleManager
  • 🛡️ Error Handling - Comprehensive error handling and logging with log4js
  • 🔒 Concurrency Protection - Prevent race conditions in duplicate loading operations
  • 📝 TypeScript Support - Complete type definitions and interfaces

Installation

npm install @ticatec/script-loader

Quick Start

Step 1: Implement BaseScriptLoader

Create your custom script loader by extending BaseScriptLoader and implementing the getUpdatedScripts method:

import { BaseScriptLoader } from '@ticatec/script-loader';
import type { DynaScript } from '@ticatec/script-loader/lib/DynaModuleManager';

class MyScriptLoader extends BaseScriptLoader {

  /**
   * Fetch updated scripts from your data source
   * @param anchor - Get scripts updated after this timestamp
   * @returns Array of DynaScript objects
   */
  protected async getUpdatedScripts(anchor: Date): Promise<DynaScript[]> {
    // Example: Fetch from database
    const scripts = await db.query(
      'SELECT * FROM scripts WHERE updated_at > ?',
      [anchor]
    );

    return scripts.map(script => ({
      keyCode: script.id,           // Unique identifier
      fileName: script.name,         // Filename without extension
      active: script.status === 'active',
      latestUpdated: script.updated_at,
      scriptCode: script.content     // JavaScript code
    }));
  }
}

Step 2: Initialize the DynaModuleManager

import DynaModuleManager from '@ticatec/script-loader';

// Initialize the singleton manager
await DynaModuleManager.initialize(
  MyScriptLoader,           // Your loader class
  './scripts',              // Script storage directory
  5000                      // Poll interval in milliseconds
);

Step 3: Use Loaded Scripts

import DynaModuleManager from '@ticatec/script-loader';

// Get the initialized manager instance
const manager = DynaModuleManager.getInstance();

// Get a script module by its keyCode
const myScript = manager.get('script-key-123');

if (myScript) {
  // Use the loaded module
  // If your script exports functions/classes, use them directly
  myScript.someFunction();

  // Or if it exports default
  const result = myScript.default();
}

API Documentation

DynaScript Interface

The DynaScript interface defines the structure for script metadata:

interface DynaScript {
  keyCode: string;        // Unique identifier for the script
  fileName: string;       // Script filename (without .js extension)
  active: boolean;        // Whether the script is active
  latestUpdated: Date;    // Last update timestamp
  scriptCode: string;     // JavaScript code content
}

DynaModuleManager

Static Methods

initialize<Args>(loaderConstructor, ...args): Promise<DynaModuleManager>

Initialize the singleton instance of DynaModuleManager. This method must be called before using getInstance().

  • Parameters:
    • loaderConstructor - Constructor of your BaseScriptLoader subclass
    • ...args - Arguments to pass to the loader constructor (typically scriptDir and pollIntervalMs)
  • Returns: Promise that resolves to the DynaModuleManager instance
  • Example:
    await DynaModuleManager.initialize(MyScriptLoader, './scripts', 5000);
getInstance(): DynaModuleManager

Get the singleton instance of DynaModuleManager. Throws an error if not initialized.

  • Returns: The DynaModuleManager instance
  • Throws: Error if initialize() hasn't been called yet
  • Example:
    const manager = DynaModuleManager.getInstance();

Instance Methods

get(key: string): any | null

Retrieve a loaded script module by its keyCode.

  • Parameters: key - Script's unique identifier (keyCode)
  • Returns: The loaded module, or null if not found

BaseScriptLoader

Constructor

protected constructor(
  scriptHome: string,      // Script storage directory
  pollIntervalMs: number   // Polling interval in milliseconds
)

Abstract Method (Must Implement)

getUpdatedScripts(anchor: Date): Promise<Array<DynaScript>>

Fetch updated scripts from your data source.

  • Parameters: anchor - Timestamp to fetch scripts updated after this time
  • Returns: Promise resolving to an array of DynaScript objects

Public Methods

init(): Promise<void>

Initialize the script loader. This is called automatically by DynaModuleManager.

getModule(key: string): any | null

Get a loaded module by its keyCode.

  • Parameters: key - Script's unique identifier
  • Returns: The loaded module, or null if not found
stopWatching(): void

Stop the periodic script update monitoring.

How It Works

Initialization Flow

  1. Directory Setup: Creates plugins directory under scriptHome
  2. Timestamp Loading: Reads .last_update_timestamp file or starts from Unix epoch
  3. Initial Load: Fetches and loads all scripts updated since the last timestamp
  4. Watch Start: Begins periodic polling for script updates

Script Lifecycle

┌─────────────────┐
│  getUpdatedScripts  │
│  (from your DB/API) │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Process Scripts    │
│  • active=true      │──► Write to file & cache module
│  • active=false     │──► Delete file & clear cache
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ Update Timestamp    │
│ Save to .last_      │
│ update_timestamp    │
└─────────────────┘

Directory Structure

scriptHome/
├── .last_update_timestamp    # Timestamp persistence file
└── plugins/                  # Script files directory
    ├── script1.js
    ├── script2.js
    └── ...

Module Caching

  • Scripts are written as .js files in the plugins directory
  • Modules are loaded using Node.js require()
  • Require cache is cleared before reloading to ensure fresh module load
  • Inactive scripts are removed from both filesystem and require cache

Advanced Usage

Custom Polling Interval

// Check for updates every 10 seconds
await DynaModuleManager.initialize(
  MyScriptLoader,
  './scripts',
  10000  // 10 seconds
);

const manager = DynaModuleManager.getInstance();

Implementing Script Versioning

class VersionedScriptLoader extends BaseScriptLoader {
  protected async getUpdatedScripts(anchor: Date): Promise<DynaScript[]> {
    const scripts = await this.fetchScripts(anchor);

    return scripts.map(script => ({
      keyCode: `${script.id}-v${script.version}`,
      fileName: `${script.name}-v${script.version}`,
      active: script.active,
      latestUpdated: script.updated_at,
      scriptCode: script.code
    }));
  }
}

Handling Script Exports

Your dynamic scripts can export in various ways:

// Option 1: Named exports
module.exports = {
  execute: function() { /* ... */ },
  config: { /* ... */ }
};

// Option 2: Default export
module.exports = function() { /* ... */ };

// Option 3: ES6-style (transpiled)
exports.default = class MyPlugin { /* ... */ };

Then use them:

const script = manager.get('my-script');

// For named exports
script.execute();

// For default export
script();

// For ES6 default
new script.default();

Error Handling

The library includes comprehensive error handling:

  • Timestamp Errors: Falls back to Unix epoch if timestamp file is corrupted
  • File Operations: Logs errors and continues operation
  • Script Loading: Catches and logs require() errors, returns null on failure
  • Concurrency: Prevents simultaneous loading operations with isLoading flag

Requirements

  • Node.js: >= 16.0.0
  • TypeScript: ^5.0.0 (for development)
  • log4js: ^6.7.0 (optional peer dependency)

Development

# Build the library
npm run build

# Type checking
npm run typecheck

# Clean build artifacts
npm run clean

# Publish to npm
npm run publish-public

Best Practices

  1. Implement Error Handling: Always handle potential null returns from manager.get()
  2. Script Format: Ensure your scripts follow Node.js module format
  3. Unique Keys: Use unique and stable keyCode values
  4. Active Status: Properly manage the active flag to enable/disable scripts
  5. Timestamps: Ensure your data source provides accurate update timestamps

Troubleshooting

Scripts Not Loading

  • Check that getUpdatedScripts() returns valid DynaScript objects
  • Verify scriptCode contains valid JavaScript
  • Check log4js output for error messages

Module Returns Null

  • Ensure the script file was created in the plugins directory
  • Check for syntax errors in your script code
  • Verify the keyCode matches exactly

Hot Reload Not Working

  • Confirm pollIntervalMs is set appropriately
  • Verify latestUpdated timestamps are increasing
  • Check that require cache is being cleared

License

MIT License - see LICENSE file for details.

Author

Henry Feng

Repository

Support

If this project helps you, please consider: