Design Trade-offs
mimOE is designed to run on any device, from phones to servers, with a minimal footprint. To achieve this portability, the runtime makes deliberate trade-offs: a lightweight runtime instead of a full Node.js environment. Understanding these trade-offs helps you build mims that work reliably across every platform mimOE supports.
JavaScript Runtime
Not a Node.js Runtime
The mimOE JavaScript runtime is not Node.js. It is a lightweight ES5-based runtime built for portability across all supported platforms. Node.js built-in modules are not available.
The most common mistake developers make is trying to import Node.js modules:
// ❌ Node.js modules are NOT available
const fs = require('fs'); // Not available
const path = require('path'); // Not available
const http = require('http'); // Not available
const net = require('net'); // Not available
const crypto = require('crypto'); // Not available
const child_process = require('child_process'); // Not available
Instead, use the mimOE runtime APIs provided via the context object:
// ✅ Use mimOE runtime APIs
app.get('/data', (request, response) => {
// HTTP requests via context.http (with callbacks)
context.http.request({
url: 'https://api.example.com/data',
success: (result) => {
// Storage via context.storage (synchronous)
context.storage.setItem('key', result.data);
response.end(result.data);
},
error: (err) => {
response.statusCode = 500;
response.end(err.message);
}
});
});
For the complete list of available APIs, see the JavaScript mim Runtime API.
ES5 Runtime with Transpilation
The mimOE JavaScript runtime is ES5-compatible. However, you can write modern ES6+ JavaScript by using Webpack with Babel to transpile your code before deployment:
// You can write modern JavaScript
const add = (a, b) => a + b;
const message = `Hello ${name}`;
async function fetchData() { ... }
// Webpack + Babel transpiles to ES6 for deployment
See Toolchain Setup for configuration details.
What's Available vs. What's Not
| Available | Not Available |
|---|---|
context.http | fetch, XMLHttpRequest |
context.storage | fs, localStorage |
console.log (debugging) | process, __dirname |
Stateless Execution
mimOE uses a serverless execution model for efficiency and predictability.
No State Persists Between Requests
// ❌ WRONG - State is lost after each request
var requestCount = 0;
app.get('/count', (request, response) => {
requestCount++; // Always 1!
response.end(JSON.stringify({ count: requestCount }));
});
// ✅ CORRECT - Use context.storage
app.get('/count', (request, response) => {
var count = parseInt(context.storage.getItem('requestCount') || '0');
var newCount = count + 1;
context.storage.setItem('requestCount', String(newCount));
response.end(JSON.stringify({ count: newCount }));
});
Timers Within Execution Quota
setTimeout is available and runs within the request's execution quota. When the quota expires, all timers are terminated.
// ✅ Works within the execution quota
setTimeout(function() {
context.storage.setItem('delayed', 'true');
}, 1000);
// ❌ Not yet available (planned)
setInterval(function() {
// Use setTimeout in a loop as an alternative
}, 5000);
For long-running or recurring tasks, use external schedulers (cron jobs, cloud functions) to trigger mims via HTTP.
WASM Runtime
No WASI Support
mimOE's WebAssembly runtime does not support WASI (WebAssembly System Interface).
// ❌ WASI functions not available
use std::fs::File; // Won't work
use std::env; // Won't work
Alternative: Use mimOE's custom imported functions:
// ✅ Use mimOE imports
extern "C" {
fn storage_get(key_ptr: *const u8, key_len: usize) -> i32;
fn http_get(url_ptr: *const u8, url_len: usize) -> i32;
}
See WASM mims for more information (detailed API reference coming soon).
Networking
No Direct Socket Access
mims cannot create sockets or listen on ports:
// ❌ Not available
const net = require('net');
const server = net.createServer();
Alternative: Use context.http for outbound HTTP requests. Inbound requests are handled by the runtime.
Built-in API Gateway
mimOE provides a built-in API gateway that handles all web server concerns. Every mim receives HTTP requests automatically, so you only need to handle request events:
// No web server setup needed. Just handle requests.
app.get('/hello', (request, response) => {
response.end(JSON.stringify({ message: 'Hello from my mim!' }));
});
app.post('/data', (request, response) => {
var body = request.body;
context.storage.setItem('data', JSON.stringify(body));
response.end(JSON.stringify({ status: 'saved' }));
});
For outbound requests, use context.http which supports both HTTP and HTTPS:
context.http.request({
url: 'https://api.example.com/data',
success: (result) => {
response.end(result.data);
},
error: (err) => {
response.statusCode = 500;
response.end(err.message);
}
});
Streaming Support
Server-Sent Events (SSE) and chunked transfer encoding are supported. WebSocket support is planned for a future release.
// ✅ SSE and chunked transfer supported
response.setHeader('Content-Type', 'text/event-stream');
response.setHeader('Transfer-Encoding', 'chunked');
// ❌ WebSockets not yet supported
const ws = new WebSocket('ws://example.com');
Storage
Key-Value Store Only
context.storage is a key-value store with tag support, not a relational database:
// ✅ Simple key-value operations (synchronous)
context.storage.setItem('user:123', JSON.stringify({ name: 'Alice' }));
var user = JSON.parse(context.storage.getItem('user:123'));
// ✅ Tagged storage for collections
context.storage.setItemWithTag('user:123', JSON.stringify(user), 'users');
// ✅ Paginated queries with filters
context.storage.getJsonItemsPaginated(0, 10, callback, {
tag: 'users',
filters: [{ jsonPath: '$.age', comparisonOperator: '>', value: '18' }]
});
// ❌ SQL queries not available
context.storage.query('SELECT * FROM users WHERE age > 18'); // Not available
Alternative: For complex relational queries, use an external database via context.http.
Cross-Platform Considerations
Mobile Platform Differences
On iOS and Android, mimOE runs embedded within an application:
- Integrated within your app (not standalone)
- Background execution follows OS guidelines
- App sandbox restrictions apply
Workarounds and Best Practices
Use Polyfills
For missing features, use polyfills via Webpack:
// webpack.config.js
module.exports = {
resolve: {
fallback: {
"promise": require.resolve("promise-polyfill"),
"buffer": require.resolve("buffer/")
}
}
};
Optimize for Stateless
Design mims for stateless execution:
- Use
context.storagefor any data that must persist - Keep request handlers pure functions when possible
- Cache expensive computation results in storage
- Validate all inputs (don't assume previous state)
Use Transactions for Consistency
Use lockExecute for atomic operations:
// ❌ Not atomic - could be inconsistent if interrupted
context.storage.setItem('balance:alice', String(aliceBalance - amount));
context.storage.setItem('balance:bob', String(bobBalance + amount));
// ✅ Atomic - all operations execute together
context.storage.lockExecute(function() {
context.storage.setItem('balance:alice', String(aliceBalance - amount));
context.storage.setItem('balance:bob', String(bobBalance + amount));
});
Summary
| Trade-off | Why | Alternative |
|---|---|---|
| Not Node.js | Lightweight, portable runtime | Use context.* APIs |
| ES5 runtime | Runs on all platforms | Use Webpack + Babel for ES6 |
| Stateless | Efficient serverless execution | context.storage |
| No WASI | Cross-platform WASM compatibility | Custom imports |
| No WebSockets (planned) | SSE and chunked transfer supported | Polling or external service |
| KV storage only | Minimal resource footprint | External database via HTTP |
Next Steps
Now that you understand the design trade-offs:
- JavaScript Development: Build with JavaScript
- WASM Development: Build with WebAssembly
- Getting Started: Set up your environment
These trade-offs are what make mimOE run anywhere, from phones to servers to embedded devices, with a minimal footprint.