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

@enopax/resource-api

v1.0.0

Published

Script-based resource API framework for Enopax platform

Readme

Enopax Resource API

Bridge your infrastructure to the Enopax platform using bash scripts. No complex frameworks, no SDK dependencies—just simple scripts that provision, monitor, and manage resources.

Purpose

The Enopax Resource API lets you integrate any infrastructure with the platform without writing application code. Whether you manage Git repositories, databases, Kubernetes clusters, or custom infrastructure, this API turns your operational knowledge into platform-ready resources.

Core Philosophy: Scripts over code. Configuration over compilation. Simplicity over complexity.

Quick Start

# Install dependencies
pnpm install

# Start the server (runs with example providers)
pnpm dev

# In another terminal, test it
curl http://localhost:3001/providers/info

The server starts with two example providers ready to explore:

  • Example Provider (/v1/resources) - Skeleton implementation with logging
  • Git Provider (/v1/git) - Real Git repository management

How It Works

Platform → API Server → Bash Scripts → Your Infrastructure
  1. Platform calls your API with resource requests
  2. API executes your bash scripts with JSON input
  3. Scripts manage actual infrastructure (Docker, cloud APIs, databases)
  4. Scripts return JSON with resource details
  5. Platform gets structured response to show users

Architecture

One API instance serves multiple providers, each handling one resource type:

Provider API (localhost:3001)
  ├── /v1/resources → scripts/example/
  └── /v1/git → scripts/git-repo/

Each provider is self-contained:

  • Independent scripts folder
  • Own configuration
  • Separate endpoint
  • Can be added/removed without downtime

Installation

pnpm install

Running

Development (with output)

pnpm dev

Production (background)

# Start
pnpm start

# Stop
pnpm stop

Server runs on http://localhost:3001

Configuration

config.json defines server settings, authentication, and providers:

{
  "server": {
    "port": 3001,
    "host": "localhost"
  },
  "authentication": {
    "enabled": false,
    "apiKey": ""
  },
  "providers": [
    {
      "apiVersion": "v1",
      "endpoint": "/resources",
      "scriptsFolder": "./scripts/example"
    },
    {
      "apiVersion": "v1",
      "endpoint": "/git",
      "scriptsFolder": "./scripts/git-repo"
    }
  ]
}

Enable Authentication (Production)

{
  "authentication": {
    "enabled": true,
    "apiKey": "your-secure-api-key-here"
  }
}

Generate secure keys:

openssl rand -hex 32

Clients include API key in requests:

curl -H "X-API-Key: your-key" http://localhost:3001/v1/resources

Note: /providers/info is always public (no auth required).

See docs/authentication.md for details.

API Endpoints

Discovery (Public)

GET /providers/info

Returns all available providers with their metadata, schemas, and endpoints.

Resource Operations (Protected when auth enabled)

Each provider gets its own endpoint:

POST   /{apiVersion}/{endpoint}                                # Create resource
GET    /{apiVersion}/{endpoint}?org={org}&project={project}    # List resources (requires org+project)
GET    /{apiVersion}/{endpoint}/:id                            # Get status
GET    /{apiVersion}/{endpoint}/:id/metrics                    # Get metrics
PUT    /{apiVersion}/{endpoint}/:id                            # Update resource
DELETE /{apiVersion}/{endpoint}/:id                            # Delete resource

Examples:

  • POST /v1/resources → Example provider (create)
  • GET /v1/resources?org=ACME%20Corp&project=Web%20App → Example provider (list)
  • POST /v1/git → Git provider (create)
  • GET /v1/git?org=ACME%20Corp&project=Web%20App → Git provider (list)

Security Note: List endpoint requires both org and project query parameters to prevent information leakage across organisations.

Usage Examples

Provision a Resource

curl -X POST http://localhost:3001/v1/resources \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-resource",
    "sshKeys": ["ssh-rsa AAAAB3..."],
    "userId": "user_123",
    "projectId": "my_project",
    "projectName": "My Project",
    "organizationId": "my_org",
    "organisationName": "My Org"
  }'

Response:

{
  "success": true,
  "id": "my_org-my_project-my_resource-abc123de",
  "name": "my-resource",
  "status": "active",
  "message": "Resource created successfully",
  "access": "http://localhost:3001/my_org-my_project-my_resource-abc123de"
}

ID Format: orgslug-projectslug-resourceslug-randomstring

  • Hyphens separate components (org, project, resource name, random string)
  • Underscores allowed within slugs
  • Random string ensures uniqueness (8 characters)

Create a Git Repository

curl -X POST http://localhost:3001/v1/git \
  -H "Content-Type: application/json" \
  -d '{
    "name": "backend-api",
    "sshKeys": ["ssh-rsa AAAAB3..."],
    "userId": "user_123",
    "projectName": "Web App",
    "organisationName": "My Org"
  }'

List Resources

# List example resources for a project
curl "http://localhost:3001/v1/resources?org=My%20Org&project=Web%20App"

# List git repositories for a project
curl "http://localhost:3001/v1/git?org=My%20Org&project=Web%20App"

Important: Both org and project parameters are required for security.

Get Resource Status

curl http://localhost:3001/v1/git/my_org-web_app-backend_api-abc123de

Get Metrics

curl http://localhost:3001/v1/git/my_org-web_app-backend_api-abc123de/metrics?period=7d

Update Configuration

curl -X PUT http://localhost:3001/v1/git/my_org-web_app-backend_api-abc123de \
  -H "Content-Type: application/json" \
  -d '{
    "configuration": {
      "repositoryName": "backend-api-v2"
    }
  }'

Delete Resource

curl -X DELETE http://localhost:3001/v1/git/my_org-web_app-backend_api-abc123de

Directory Structure

provider-api/
├── server.js                          # Express API server
├── config.json                        # Server, auth, and provider configuration
├── package.json                       # Dependencies
├── bin/
│   ├── start.sh                       # Start server in background
│   └── stop.sh                        # Stop background server
├── scripts/
│   ├── example/                       # Skeleton provider (learning/demos)
│   │   ├── config.json                # Provider and resource type definition
│   │   ├── provision.sh               # Create resource
│   │   ├── status.sh                  # Get status
│   │   ├── metrics.sh                 # Get metrics
│   │   ├── update.sh                  # Update resource
│   │   └── deprovision.sh             # Delete resource
│   └── git-repo/                      # Git repository provider
│       ├── common.sh                  # Shared configuration
│       ├── config.json                # Provider and resource type definition
│       └── *.sh scripts               # Git operations
└── docs/
    ├── architecture.md                # System architecture
    ├── concept.md                     # Core concepts and philosophy
    ├── authentication.md              # Authentication guide
    └── testing.md                     # Testing guide

Creating Your Own Provider

1. Create Scripts Folder

mkdir -p scripts/my-provider
cd scripts/my-provider

2. Define Provider Configuration

Create config.json:

{
  "typeId": "my-resource-type",
  "displayName": "My Resource Type",
  "description": "What this resource provides",
  "category": "DATABASE",
  "providerId": "my-provider",
  "providerName": "My Provider",
  "version": "1.0.0",
  "website": "https://example.com",
  "supportEmail": "[email protected]",
  "supportedRegions": ["local"],
  "status": "operational",
  "configSchema": {
    "type": "object",
    "properties": {
      "instanceName": {
        "type": "string",
        "title": "Instance Name"
      }
    },
    "required": ["instanceName"]
  },
  "estimatedProvisioningTime": 60
}

3. Create Scripts

provision.sh - Create resource:

#!/bin/bash
set -e

# Load common configuration and helper functions
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"

read -r INPUT

# Parse input from flat structure
NAME=$(echo "$INPUT" | jq -r '.name // empty')
ORG_NAME=$(echo "$INPUT" | jq -r '.organisationName // "default"')
PROJECT_NAME=$(echo "$INPUT" | jq -r '.projectName // "default"')

# Slugify names and generate ID using helper functions
ORG_SLUG=$(slugify "$ORG_NAME")
PROJECT_SLUG=$(slugify "$PROJECT_NAME")
NAME_SLUG=$(slugify "$NAME")
ID=$(generate_id "$ORG_SLUG" "$PROJECT_SLUG" "$NAME_SLUG")

# Create your resource here
# (call APIs, create Docker containers, etc.)

# Output JSON
cat <<EOF
{
  "success": true,
  "id": "$ID",
  "name": "$NAME",
  "status": "active",
  "message": "Resource created successfully",
  "access": "https://my-resource.example.com/$ID"
}
EOF

Create similar scripts for:

  • status.sh - Check resource status
  • metrics.sh - Collect metrics
  • update.sh - Update resource
  • deprovision.sh - Delete resource

Make scripts executable:

chmod +x *.sh

4. Register Provider

Add to config.json:

{
  "providers": [
    {
      "apiVersion": "v1",
      "endpoint": "/my-resource",
      "scriptsFolder": "./scripts/my-provider"
    }
  ]
}

5. Test

# Restart server
pnpm stop && pnpm start

# Test your provider
curl -X POST http://localhost:3001/v1/my-resource \
  -H "Content-Type: application/json" \
  -d '{"resourceId":"test","typeId":"my-resource-type","configuration":{"instanceName":"test"}}'

Script Interface

Input (stdin)

Scripts receive JSON via stdin (flat structure):

{
  "name": "resource-name",
  "sshKeys": ["ssh-rsa AAAAB3...", "ssh-rsa AAAAC4..."],
  "userId": "user_123",
  "projectId": "my_project",
  "projectName": "My Project",
  "organizationId": "my_org",
  "organisationName": "My Org"
}

Note: projectId and organizationId are slugified names (lowercase, underscores), not UUIDs.

Output (stdout)

Scripts output JSON to stdout:

Success (exit code 0):

{
  "success": true,
  "id": "my_org_my_project_resource_abc123",
  "name": "resource-name",
  "status": "active",
  "message": "Resource created successfully",
  "access": "https://..."
}

Error (exit code non-zero):

{
  "success": false,
  "error": "Error message"
}

Script Requirements

All scripts must:

  • ✅ Read JSON from stdin
  • ✅ Output valid JSON to stdout
  • ✅ Exit with 0 on success, non-zero on error
  • ✅ Be executable (chmod +x)
  • ✅ Handle errors gracefully

Example Provider

The included example provider demonstrates the script interface with informative logging:

# Watch the execution flow
pnpm dev

# In another terminal
curl -X POST http://localhost:3001/v1/resources \
  -H "Content-Type: application/json" \
  -d '{"resourceId":"demo","typeId":"example-resource","configuration":{"resourceName":"demo","size":"small"}}'

Server output shows script execution:

[provision.sh] Starting resource provisioning...
[provision.sh] Received input, parsing fields...
[provision.sh] Resource: demo (size: small)
[provision.sh] Generated orchestrator ID: example_1234_abc
[provision.sh] Creating resource...
[provision.sh] Resource created successfully!
[provision.sh] Returning JSON response...

Perfect for learning the flow and building your own provider.

Git Repository Provider

The Git provider is a complete implementation that:

  • Provisions - Creates bare Git repositories
  • Status - Reports repository health and metadata
  • Metrics - Returns storage size, commit count, branches
  • Update - Modifies repository configuration
  • Deprovision - Soft deletes with 30-day grace period

Features:

  • Shared configuration via common.sh
  • Organised by organisation/project/repository
  • Configurable retention periods
  • SSH access URLs

See scripts/git-repo/ for implementation details.

Testing

Quick Test

# Start server
pnpm dev

# Run test script (tests all endpoints)
./test.sh

Manual Testing

# Test provider discovery
curl http://localhost:3001/providers/info | jq

# Test provisioning
curl -X POST http://localhost:3001/v1/resources \
  -H "Content-Type: application/json" \
  -d '{"resourceId":"test","typeId":"example-resource","configuration":{"resourceName":"test"}}' | jq

# Test status
curl http://localhost:3001/v1/resources/example_123 | jq

# Test metrics
curl http://localhost:3001/v1/resources/example_123/metrics | jq

# Test deletion
curl -X DELETE http://localhost:3001/v1/resources/example_123 | jq

Script Testing

Test scripts independently without the API:

echo '{"name":"test","organizationId":"my_org","projectId":"my_project","sshKeys":[]}' | \
  bash provider/git-repo/scripts/provision.sh

See docs/testing.md for comprehensive testing guide.

Documentation

Platform Integration

The Enopax platform integrates with providers via this API:

  1. Discovery - Platform calls /providers/info to discover available resources
  2. Provisioning - Platform calls provider endpoints to create resources
  3. Monitoring - Platform polls status endpoints for resource health
  4. Metrics - Platform collects usage data for billing and capacity planning
  5. Updates - Platform applies configuration changes via PUT requests
  6. Cleanup - Platform deprovisions resources when users delete them

The platform handles:

  • User interface generation (from JSON schemas)
  • Authentication and access control
  • Credential encryption and storage
  • Billing and usage tracking
  • Multi-tenancy and organisation management

Common Configuration Pattern

Create common.sh to share settings and helper functions across scripts:

#!/bin/bash

# Get the directory of this script
COMMON_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Shared configuration
RESOURCES_BASE="$(cd "$COMMON_SCRIPT_DIR" && cd ../../../ && pwd)/data/resources"
mkdir -p "$RESOURCES_BASE"

# Slugify function: convert names to URL-safe identifiers
slugify() {
  echo "$1" | \
    sed 'y/äöüßÄÖÜ/aousAOU/' | \
    sed 's/[^a-z0-9]/_/g' | \
    tr '[:upper:]' '[:lower:]' | \
    sed 's/__*/_/g' | \
    sed 's/^_//; s/_$//'
}

# Parse ID components (ID format: orgslug-projectslug-resourceslug-randomstring)
get_org_from_id() {
  local id=$1
  IFS='-' read -ra parts <<< "$id"
  [ ${#parts[@]} -eq 4 ] && echo "${parts[0]}"
}

get_project_from_id() {
  local id=$1
  IFS='-' read -ra parts <<< "$id"
  [ ${#parts[@]} -eq 4 ] && echo "${parts[1]}"
}

get_name_from_id() {
  local id=$1
  IFS='-' read -ra parts <<< "$id"
  [ ${#parts[@]} -eq 4 ] && echo "${parts[2]}"
}

# Generate unique ID
generate_id() {
  local org_slug=$1
  local project_slug=$2
  local name_slug=$3
  local random_str=$(echo $RANDOM | md5sum | head -c 8)
  echo "${org_slug}-${project_slug}-${name_slug}-${random_str}"
}

# Construct resource path
get_resource_path() {
  local org_slug=$1
  local project_slug=$2
  local id=$3
  echo "$RESOURCES_BASE/$org_slug/$project_slug/$id.txt"
}

get_resource_path_by_id() {
  local id=$1
  local org_slug=$(get_org_from_id "$id")
  local project_slug=$(get_project_from_id "$id")
  get_resource_path "$org_slug" "$project_slug" "$id"
}

Source in scripts:

#!/bin/bash
set -e

# Load common configuration and helper functions
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"

# Use shared variables and functions
ORG_SLUG=$(slugify "$ORG_NAME")
PROJECT_SLUG=$(slugify "$PROJECT_NAME")
NAME_SLUG=$(slugify "$NAME")
ID=$(generate_id "$ORG_SLUG" "$PROJECT_SLUG" "$NAME_SLUG")
RESOURCE_FILE=$(get_resource_path "$ORG_SLUG" "$PROJECT_SLUG" "$ID")

Benefits:

  • Single source of truth for configuration
  • Consistent ID format across all resources
  • Helper functions reduce code duplication
  • Easy to parse IDs for resource lookup
  • Organised directory structure by org/project

See scripts/example/common.sh and scripts/git-repo/common.sh for full implementations.

Production Deployment

Enable Authentication

{
  "authentication": {
    "enabled": true,
    "apiKey": "generated-secure-key"
  }
}

Use HTTPS

Run behind reverse proxy (Nginx, Caddy, Traefik):

server {
    listen 443 ssl;
    server_name provider.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Process Management

Use systemd, PM2, or Docker:

systemd service:

[Unit]
Description=Enopax Provider API
After=network.target

[Service]
Type=simple
User=provider
WorkingDirectory=/opt/provider-api
ExecStart=/usr/bin/node server.js
Restart=always

[Install]
WantedBy=multi-user.target

Monitoring

  • Check /providers/info for health
  • Monitor script execution times
  • Track API response codes
  • Log errors for debugging

Security Considerations

Production Checklist

  • ✅ Enable authentication
  • ✅ Use strong API keys
  • ✅ Run behind HTTPS
  • ✅ Validate all inputs
  • ✅ Never log credentials
  • ✅ Use environment variables for secrets
  • ✅ Rotate API keys periodically
  • ✅ Monitor for suspicious activity
  • ✅ Implement rate limiting
  • ✅ Keep dependencies updated

Script Security

  • Validate all inputs
  • Escape user-provided values
  • Use secure temporary files
  • Clean up sensitive data
  • Handle errors safely
  • Log operations for audit trail

Troubleshooting

Server won't start

  • Check port 3001 is available
  • Verify config.json is valid JSON
  • Ensure scripts folders exist
  • Check file permissions

Scripts fail

  • Test scripts manually
  • Verify scripts are executable
  • Check JSON output is valid
  • Review script logs (stderr)

Authentication errors

  • Verify API key matches config
  • Check X-API-Key header format
  • Remember: /providers/info is always public
  • Disable auth for testing

Script debugging

# Enable debug mode
bash -x scripts/example/provision.sh

# Test with verbose output
echo '{"test":"data"}' | bash -x scripts/example/provision.sh 2>&1

Contributing

We welcome contributions! Whether it's:

  • New provider examples
  • Bug fixes
  • Documentation improvements
  • Feature suggestions

Please open issues or PRs on GitHub.

License

MIT


Built for developers, by developers. Simple, flexible, and powerful infrastructure integration.