- Added documentation for cache TTL configuration - Included usage examples for development scenarios - Added cache management section with practical examples
12 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/ # Compiled executable scripts
│ ├── prebuild-ior-types.js # Pre-build script for type generation
│ └── NodeImportLoader.js # Compiled Node.js loader
├── docs/ # Documentation
│ └── IOR_RESOLVER.md # Detailed IOR resolver documentation
├── lib/ # Core library files
│ ├── ior-core.js # Shared core functions
│ ├── metro-ior-resolver.js # Metro resolver implementation
│ └── fetch-remote-component.js # Remote fetching utility
├── plugins/ # Babel and bundler plugins
│ └── babel-plugin-ior.js # Babel plugin for IOR imports
├── src/ # Source files
│ └── loaders/
│ └── NodeImportLoader.ts # Node.js loader TypeScript source
├── 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 stringsparsePackageJson(path)- Synchronously parse package.jsonparsePackageJsonAsync(path)- Asynchronously parse package.jsonfetchUrl(url)- Fetch content from URLfetchUrlBuffer(url)- Fetch URL as BufferfetchFromGitHub(config)- Fetch from GitHubfetchFromGitea(config)- Fetch from GiteafetchFromIPFS(config)- Fetch from IPFSextractArchive(buffer, dir)- Extract tar.gz archivesfindEntryPoint(dir, name)- Find component entry pointgenerateCacheHash(ior)- Generate SHA256 hash for cachingbuildLocalIORMappings(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 loaderNODE_ENV=development- Enable hot reload for Metro resolverIOR_CACHE_TTL- Control cache duration in millisecondsIOR_CACHE_TTL=0- Disable caching (always fetch fresh)IOR_CACHE_TTL=60000- 1 minute cache (useful during development)- Default: 3600000 (1 hour)
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) - configurable via
IOR_CACHE_TTL
Cache Persistence
Metro resolver maintains a persistent cache mapping in .ior-cache/mappings.json for faster startup times.
Cache Management During Development
When working with frequently changing remote components:
# Disable cache completely (always fetch fresh)
IOR_CACHE_TTL=0 npm start
# Use short cache duration (1 minute)
IOR_CACHE_TTL=60000 npm start
# Clear cache manually
rm -rf .ior-cache/remote/*
# Or add to package.json scripts:
"scripts": {
"dev:no-cache": "IOR_CACHE_TTL=0 npm start",
"dev:short-cache": "IOR_CACHE_TTL=60000 npm start",
"clear-cache": "rm -rf .ior-cache/remote/*"
}
Architecture
The package is designed with a shared core architecture:
- ior-core.js - Contains all shared functionality for parsing, fetching, and caching
- metro-ior-resolver.js - Metro-specific implementation using the shared core
- NodeImportLoader.ts - Node.js-specific implementation using the shared core (TypeScript source compiled to JavaScript)
This design eliminates code duplication and ensures consistency across different environments. The Node.js loader is written in TypeScript and compiled to JavaScript during the build process.
Migration from Direct Implementation
If you're migrating from having these files directly in your project:
-
Install the package:
npm install @metatrom/ior-resolver -
Update
metro.config.jsto use the package import:const { createHotReloadableResolver } = require('@metatrom/ior-resolver'); -
Update
package.jsonscripts:{ "scripts": { "prebuild": "prebuild-ior-types" } } -
Remove the old files from your project:
metro-ior-resolver.jsscripts/prebuild-ior-types.jsfetch-remote-component.jsNodeImportLoader.ts
TypeScript Support
The package automatically generates TypeScript declarations for IOR components:
- Local components: Types are read from
.d.tsfiles 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
-
"Cannot resolve IOR module"
- Ensure the component exists in the expected location
- Check the IOR format is correct
- Verify network connectivity for remote components
-
"Failed to fetch remote component"
- Check network connectivity
- Verify the repository exists and is accessible
- Ensure the version tag exists
-
Types not generating
- Run
npx prebuild-ior-typesmanually - Check for
.d.tsfiles in component directories - Verify
src/types/directory exists
- Run
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
- Clone the repository
- Install dependencies:
npm install - Build TypeScript:
npm run build - Build Node.js loader:
npm run build:loader - Run tests:
npm test
Note: The prepublishOnly script automatically runs both build commands before publishing.
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
TODO: Missing Features
The following features are documented in docs/IOR_RESOLVER.md but not yet implemented in the codebase:
High Priority
-
Authentication for Private Repositories
- GitHub authentication via
GITHUB_TOKENenvironment variable - Gitea authentication with instance-specific tokens
- Add Authorization headers to fetch requests
- Impact: Currently cannot access private repositories
- GitHub authentication via
-
Error Recovery & Resilience
- Implement retry logic with exponential backoff for network failures
- Add
IORResolutionErrorclass for better error categorization - Implement fallback strategies for failed fetches
- Impact: Single network failures cause immediate errors
Medium Priority
- Security Enhancements
- HTTPS certificate validation for Git sources
- Content sanitization and pattern scanning
- Component signature verification
- Sandboxing options with configurable restrictions:
- Allowed protocols whitelist
- Allowed domains whitelist
- Maximum component size limits
- Impact: Limited security validation of fetched components
Low Priority
- Advanced Features
- Per-source cache TTL configuration
- Component dependency resolution
- Version conflict resolution
- Cross-platform compatibility checks
- Progress reporting for large downloads
Future Roadmap (from docs)
- P2P protocol implementation (libp2p)
- Decentralized component registry
- Smart contract integration for Web3
- Component marketplace
- AI-assisted component discovery
Support
For issues and feature requests, please use the GitHub issue tracker.