Files
ior-resolver/README.md
Chris Daßler e1fb6e6acc Initial commit
2025-08-29 04:22:52 +02:00

9.4 KiB

@metatrom/ior-resolver

IOR (Interoperable Object Reference) resolver for Metro bundler and Node.js with support for local and remote component fetching.

Features

  • 🚀 Metro Bundler Support - Seamlessly integrate IOR resolution with React Native projects
  • 🌐 Remote Component Fetching - Load components from GitHub, Gitea, IPFS, and P2P networks
  • 📦 Local Component Resolution - Resolve local components using package.json metadata
  • 🔄 Hot Reload Support - Automatic mapping updates during development
  • 📝 TypeScript Support - Auto-generate type declarations for IOR components
  • Caching - Intelligent caching of remote components for better performance
  • 🛠️ Pre-build Script - Generate types before development starts
  • 🎯 Shared Core - Consolidated functions to avoid duplication

Installation

npm install @metatrom/ior-resolver

Project Structure

@metatrom/ior-resolver/
├── bin/                      # Executable scripts
│   ├── prebuild-ior-types.js   # Pre-build script for type generation
│   └── NodeImportLoader.ts      # Node.js loader implementation
├── lib/                      # Core library files
│   ├── ior-core.js             # Shared core functions
│   ├── metro-ior-resolver.js   # Metro resolver implementation
│   └── fetch-remote-component.js # Remote fetching utility
├── index.js                  # Main entry point
├── index.d.ts               # TypeScript definitions
└── package.json

Usage

Metro Configuration (React Native)

In your metro.config.js:

const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const { createHotReloadableResolver } = require('@metatrom/ior-resolver');

const defaultConfig = getDefaultConfig(__dirname);

const config = {
  resolver: {
    resolveRequest: createHotReloadableResolver(__dirname),
  },
};

module.exports = mergeConfig(defaultConfig, config);

Node.js Loader

For Node.js projects using TypeScript and IOR imports:

// In your loader file
import { resolve, load } from '@metatrom/ior-resolver/node';

// Or register the loader
import { register } from 'node:module';
import { pathToFileURL } from 'node:url';

register('@metatrom/ior-resolver/node', pathToFileURL('./'));

Pre-build Script

Add to your package.json scripts to generate TypeScript declarations before development:

{
  "scripts": {
    "prebuild": "prebuild-ior-types",
    "dev": "npm run prebuild && npm start"
  }
}

Or run directly:

npx prebuild-ior-types

IOR Format

IOR (Interoperable Object Reference) provides a unified way to reference components across different sources:

Local Components

import Logger from 'ior:esm:com.metatrom.examples.logger@1.0.0';

Remote Components

GitHub

import Component from 'ior:github:owner/repo:componentname@version';

Gitea

import Component from 'ior:gitea:instance.com:owner/repo:componentname@version';
// Alternative format for repos with slashes in name:
import Component from 'ior:gitea:instance.com:owner/repo/componentname@version';

IPFS

import Component from 'ior:ipfs:QmHash:componentname@version';

P2P (Coming Soon)

import Component from 'ior:p2p:peer-id:componentname@version';

Component Structure

Local components should follow this structure:

src/components/
└── componentname/
    └── version/
        ├── package.json
        ├── index.ts (or componentname.ts)
        └── componentname.d.ts (optional)

package.json Example

{
  "name": "logger",
  "version": "1.0.0",
  "main": "index.ts",
  "metatrom": {
    "ior": "com.metatrom.examples.logger@1.0.0"
  }
}

API Reference

Core Functions (ior-core.js)

The shared core module provides common functionality used by both Metro and Node.js implementations:

  • parseRemoteIOR(ior) - Parse remote IOR strings
  • parsePackageJson(path) - Synchronously parse package.json
  • parsePackageJsonAsync(path) - Asynchronously parse package.json
  • fetchUrl(url) - Fetch content from URL
  • fetchUrlBuffer(url) - Fetch URL as Buffer
  • fetchFromGitHub(config) - Fetch from GitHub
  • fetchFromGitea(config) - Fetch from Gitea
  • fetchFromIPFS(config) - Fetch from IPFS
  • extractArchive(buffer, dir) - Extract tar.gz archives
  • findEntryPoint(dir, name) - Find component entry point
  • generateCacheHash(ior) - Generate SHA256 hash for caching
  • buildLocalIORMappings(root) - Build local component mappings

Metro Resolver Functions

createIORResolver(projectRoot: string)

Creates a basic IOR resolver for Metro.

createHotReloadableResolver(projectRoot: string)

Creates an IOR resolver with hot reload support that watches for package.json changes.

fetchRemoteComponent(ior: string)

Fetches and caches a remote component.

clearRemoteCache()

Clears all cached remote components.

Node.js Loader Functions

resolve(specifier, context, defaultResolve)

Node.js loader resolve hook for IOR imports.

load(url, context, defaultLoad)

Node.js loader load hook for TypeScript transpilation.

clearCache(ior?: string)

Clears cache for a specific IOR or all cached components.

setCacheTTL(ttl: number)

Sets the cache time-to-live for remote components.

preloadComponent(ior: string)

Pre-fetches a remote component for faster access.

Configuration

Environment Variables

  • DEBUG=true - Enable debug logging for the Node.js loader
  • NODE_ENV=development - Enable hot reload for Metro resolver

Cache Configuration

The resolver uses different cache locations for different environments:

  • Metro: .ior-cache/remote/ in project root
  • Node.js: OS temp directory under metatrom-components/remote/
  • Default TTL: 1 hour (3600000ms)

Cache Persistence

Metro resolver maintains a persistent cache mapping in .ior-cache/mappings.json for faster startup times.

Architecture

The package is designed with a shared core architecture:

  1. ior-core.js - Contains all shared functionality for parsing, fetching, and caching
  2. metro-ior-resolver.js - Metro-specific implementation using the shared core
  3. NodeImportLoader.ts - Node.js-specific implementation using the shared core

This design eliminates code duplication and ensures consistency across different environments.

Migration from Direct Implementation

If you're migrating from having these files directly in your project:

  1. Install the package:

    npm install @metatrom/ior-resolver
    
  2. Update metro.config.js to use the package import:

    const { createHotReloadableResolver } = require('@metatrom/ior-resolver');
    
  3. Update package.json scripts:

    {
      "scripts": {
        "prebuild": "prebuild-ior-types"
      }
    }
    
  4. Remove the old files from your project:

    • metro-ior-resolver.js
    • scripts/prebuild-ior-types.js
    • fetch-remote-component.js
    • NodeImportLoader.ts

TypeScript Support

The package automatically generates TypeScript declarations for IOR components:

  • Local components: Types are read from .d.ts files in the component directory
  • Remote components: Types are fetched from the remote repository
  • Auto-generated types are saved to src/types/auto-generated.d.ts

Security Considerations

  • Remote components are fetched over HTTPS
  • Components are cached locally with SHA256 hash verification
  • Cache TTL ensures components are refreshed periodically
  • No automatic code execution - components must be explicitly imported

Performance

  • Caching: Components are cached locally to avoid repeated network requests
  • Parallel fetching: Multiple components can be fetched in parallel
  • Hot reload: Development mode watches for changes without restart
  • Type generation: Types are generated asynchronously without blocking

Troubleshooting

Common Issues

  1. "Cannot resolve IOR module"

    • Ensure the component exists in the expected location
    • Check the IOR format is correct
    • Verify network connectivity for remote components
  2. "Failed to fetch remote component"

    • Check network connectivity
    • Verify the repository exists and is accessible
    • Ensure the version tag exists
  3. Types not generating

    • Run npx prebuild-ior-types manually
    • Check for .d.ts files in component directories
    • Verify src/types/ directory exists

Debug Mode

Enable debug logging:

DEBUG=true npm start

Clear Cache

If you encounter stale cache issues:

// In your code
const { clearRemoteCache } = require('@metatrom/ior-resolver');
clearRemoteCache();

Or manually delete:

rm -rf .ior-cache
rm -rf /tmp/metatrom-components  # Node.js cache

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

  1. Clone the repository
  2. Install dependencies: npm install
  3. Build TypeScript: npm run build
  4. Run tests: npm test

Code Structure

  • Keep shared functionality in lib/ior-core.js
  • Environment-specific code in respective files
  • Maintain TypeScript types for all exports
  • Follow existing code style

License

MIT

Support

For issues and feature requests, please use the GitHub issue tracker.