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

@objectql/platform-node

v4.2.2

Published

Node.js platform utilities for ObjectQL - File system integration, YAML loading, and plugin management

Downloads

712

Readme

@objectql/platform-node

Node.js platform utilities for ObjectQL - File system integration, YAML loading, and plugin management.

Features

  • 📂 File System Metadata Loader - Automatically discover and load .object.yml, .validation.yml, .permission.yml files from directories
  • 🔌 Plugin System - Dynamic loading and management of ObjectQL plugins
  • 📦 Module System - Package and module discovery for organized project structures
  • 🚀 Driver Registration - Simplified database driver configuration
  • 🔍 Convention-Based Discovery - Automatic metadata scanning using glob patterns
  • ⚡ Hot Reload Ready - File watching support for development workflows

Installation

npm install @objectql/platform-node @objectql/core @objectql/types

Quick Start

Basic Metadata Loading

import { ObjectQL } from '@objectql/core';
import { ObjectLoader } from '@objectql/platform-node';
import * as path from 'path';

// Initialize ObjectQL
const app = new ObjectQL({
    datasources: {
        default: new SqlDriver({ /* config */ })
    }
});

// Create loader and load metadata from directory
const loader = new ObjectLoader(app.metadata);
loader.load(path.join(__dirname, 'src/objects'));

await app.init();

With Custom Directory Structure

import { ObjectLoader } from '@objectql/platform-node';

const loader = new ObjectLoader(app.metadata);

// Load from multiple directories
loader.load('./src/core/objects');
loader.load('./src/plugins/crm/objects');
loader.load('./src/plugins/project/objects');

// Load specific file types
loader.load('./src/validations', {
    include: ['**/*.validation.yml']
});

API Reference

ObjectLoader

The main class for loading metadata files from the file system.

Constructor

new ObjectLoader(registry: MetadataRegistry)

Parameters:

  • registry - The MetadataRegistry from ObjectQL instance

Methods

load(dirPath: string, options?: LoadOptions): void

Load metadata files from a directory.

loader.load('./src/objects');

// With options
loader.load('./src', {
    include: ['**/*.object.yml', '**/*.validation.yml'],
    exclude: ['**/node_modules/**', '**/test/**']
});

Options:

  • include?: string[] - Glob patterns to include (default: all supported types)
  • exclude?: string[] - Glob patterns to exclude
use(plugin: LoaderPlugin): void

Register a custom loader plugin for handling additional file types.

loader.use({
    name: 'custom-metadata',
    glob: ['**/*.custom.yml'],
    handler: (ctx) => {
        const data = yaml.load(ctx.content);
        // Process and register custom metadata
    }
});

Plugin Loading

Load external plugins dynamically.

loadPlugin(packageName: string): ObjectQLPlugin

import { loadPlugin } from '@objectql/platform-node';

const plugin = loadPlugin('@objectql/plugin-audit');
app.use(plugin);

The plugin loader:

  • Resolves the package from node_modules
  • Supports both class-based and instance-based plugins
  • Automatically instantiates classes if needed
  • Searches default export and named exports

Driver Registration

Simplified driver registration for Node.js environments.

import { registerDriver } from '@objectql/platform-node';
import { SqlDriver } from '@objectql/driver-sql';

registerDriver(app, 'default', new SqlDriver({
    client: 'postgresql',
    connection: {
        host: 'localhost',
        port: 5432,
        database: 'myapp',
        user: 'postgres',
        password: 'password'
    }
}));

Supported Metadata File Types

The loader automatically handles these file patterns:

| Pattern | Description | Status | |---------|-------------|--------| | **/*.object.yml | Object/Entity definitions | ✅ Fully Supported | | **/*.object.yaml | Object definitions (YAML format) | ✅ Fully Supported | | **/*.validation.yml | Validation rules | ✅ Fully Supported | | **/*.permission.yml | Permission/RBAC rules | ⚠️ Loaded (requires manual enforcement) | | **/*.hook.yml | Lifecycle hooks metadata | ✅ Fully Supported | | **/*.action.yml | Custom action definitions | ✅ Fully Supported | | **/*.workflow.yml | Workflow automation | ⚠️ Loaded (no runtime execution) | | **/*.app.yml | Application configuration | ✅ Fully Supported | | **/*.data.yml | Initial/seed data | ✅ Fully Supported |

Note: Permission and workflow files can be loaded, but require application-layer implementation. See Implementation Status for details.

Project Structure Examples

Standard Structure

my-app/
├── src/
│   ├── objects/
│   │   ├── user.object.yml
│   │   ├── project.object.yml
│   │   └── task.object.yml
│   ├── validations/
│   │   ├── user.validation.yml
│   │   └── project.validation.yml
│   └── permissions/
│       ├── user.permission.yml
│       └── project.permission.yml
└── objectstack.config.ts

Modular Structure

my-app/
├── src/
│   ├── modules/
│   │   ├── crm/
│   │   │   ├── objects/
│   │   │   │   ├── customer.object.yml
│   │   │   │   └── opportunity.object.yml
│   │   │   └── validations/
│   │   │       └── customer.validation.yml
│   │   └── project/
│   │       ├── objects/
│   │       │   ├── project.object.yml
│   │       │   └── milestone.object.yml
│   │       └── permissions/
│   │           └── project.permission.yml
└── objectstack.config.ts

Complete Example

objectstack.config.ts

import { ObjectQL } from '@objectql/core';
import { SqlDriver } from '@objectql/driver-sql';
import { ObjectLoader, loadPlugin } from '@objectql/platform-node';
import * as path from 'path';

// Initialize ObjectQL
const app = new ObjectQL({
    datasources: {
        default: new SqlDriver({
            client: 'sqlite3',
            connection: {
                filename: path.join(__dirname, 'dev.sqlite3')
            },
            useNullAsDefault: true
        })
    }
});

// Load metadata from file system
const loader = new ObjectLoader(app.metadata);

// Load core objects
loader.load(path.join(__dirname, 'src/objects'));

// Load module-specific metadata
loader.load(path.join(__dirname, 'src/modules/crm'));
loader.load(path.join(__dirname, 'src/modules/project'));

// Load plugins
try {
    const auditPlugin = loadPlugin('@objectql/plugin-audit');
    app.use(auditPlugin);
} catch (e) {
    console.log('Audit plugin not installed');
}

export default app;

Advanced Usage

Custom Loader Plugin

Create custom handlers for specialized file types:

import { LoaderPlugin } from '@objectql/types';
import * as yaml from 'js-yaml';

const customPlugin: LoaderPlugin = {
    name: 'report-loader',
    glob: ['**/*.report.yml'],
    handler: (ctx) => {
        const report = yaml.load(ctx.content);
        
        // Validate report structure
        if (!report.name || !report.query) {
            console.warn(`Invalid report in ${ctx.file}`);
            return;
        }
        
        // Register report in metadata
        ctx.registry.addEntry('report', report.name, {
            ...report,
            _source: ctx.file
        });
    }
};

loader.use(customPlugin);

Conditional Loading

Load different metadata based on environment:

const loader = new ObjectLoader(app.metadata);

// Always load core
loader.load('./src/objects');

// Environment-specific
if (process.env.NODE_ENV === 'development') {
    loader.load('./src/dev-objects');
    loader.load('./src/test-data');
} else if (process.env.NODE_ENV === 'production') {
    loader.load('./src/production-objects');
}

Error Handling

const loader = new ObjectLoader(app.metadata);

try {
    loader.load('./src/objects');
} catch (error) {
    console.error('Failed to load metadata:', error);
    
    if (error.code === 'ENOENT') {
        console.error('Directory not found. Creating...');
        fs.mkdirSync('./src/objects', { recursive: true });
    }
    
    throw error;
}

File Watching (Development)

While the loader doesn't include built-in file watching, you can easily add it:

import * as chokidar from 'chokidar';

const loader = new ObjectLoader(app.metadata);
const watchPath = path.join(__dirname, 'src/objects');

// Initial load
loader.load(watchPath);

// Watch for changes
if (process.env.NODE_ENV === 'development') {
    const watcher = chokidar.watch('**/*.object.yml', {
        cwd: watchPath,
        ignoreInitial: true
    });
    
    watcher.on('change', (filePath) => {
        console.log(`Reloading ${filePath}...`);
        
        // Clear and reload
        app.metadata.clear();
        loader.load(watchPath);
        
        // Re-initialize
        app.init();
    });
}

Module Discovery

The platform-node package includes utilities for discovering packages and modules:

import { discoverModules } from '@objectql/platform-node';

// Discover all modules in a directory
const modules = discoverModules('./src/modules');

for (const module of modules) {
    console.log(`Loading module: ${module.name}`);
    loader.load(module.path);
}

Best Practices

1. Organize by Feature

src/
  modules/
    users/
      objects/
      validations/
      permissions/
      hooks/
    projects/
      objects/
      validations/

2. Use Consistent Naming

  • Match file names to object names: user.object.yml for object "user"
  • Use singular names: project, not projects
  • Use lowercase with underscores: project_task, not ProjectTask

3. Separate Concerns

Keep different metadata types in separate files:

  • user.object.yml - Object structure
  • user.validation.yml - Validation rules
  • user.permission.yml - Access control

4. Environment Configuration

// Load base configuration
loader.load('./src/objects');

// Add environment-specific overrides
if (process.env.NODE_ENV === 'production') {
    loader.load('./src/objects/production');
}

Troubleshooting

Files Not Loading

Problem: Metadata files are not being loaded.

Solutions:

  • Verify file extensions match: .yml or .yaml
  • Check file names follow conventions: *.object.yml, *.validation.yml
  • Ensure directory path is correct (absolute or relative to process.cwd())
  • Check for YAML syntax errors in files

Plugin Loading Fails

Problem: loadPlugin() throws "Failed to resolve plugin" error.

Solutions:

  • Ensure plugin package is installed: npm install @objectql/plugin-name
  • Verify package name is correct
  • Check that plugin exports a valid ObjectQL plugin
  • Try using absolute path if relative resolution fails

Performance Issues

Problem: Slow metadata loading on startup.

Solutions:

  • Limit glob patterns to specific directories
  • Use exclude patterns to skip unnecessary directories
  • Consider lazy loading modules
  • Cache parsed metadata in production

TypeScript Support

Full TypeScript support with type definitions:

import { 
    ObjectLoader, 
    LoaderPlugin, 
    LoaderHandlerContext,
    loadPlugin
} from '@objectql/platform-node';

const loader: ObjectLoader = new ObjectLoader(app.metadata);

const plugin: LoaderPlugin = {
    name: 'custom',
    glob: ['**/*.custom.yml'],
    handler: (ctx: LoaderHandlerContext) => {
        // Fully typed context
        console.log(ctx.file, ctx.content, ctx.registry);
    }
};

loader.use(plugin);

Related Packages

Environment Requirements

  • Node.js: 14.x or higher
  • TypeScript: 4.5 or higher (for TypeScript projects)

Dependencies

  • fast-glob - Fast file system glob matching
  • js-yaml - YAML parsing
  • @objectql/types - Core type definitions
  • @objectql/core - Core utilities

License

MIT - Same as ObjectQL

Contributing

Contributions are welcome! Please see the main repository README for guidelines.

See Also