6. Node Compatibility
Enable Node.js core APIs and npm library support in TitanPL applications.
@titanpl/node
Node.js compatibility layer for the TitanPL Gravity Runtime.
This package enables selected Node.js core APIs to work inside TitanPL applications by mapping them to Titanβs native Rust-powered runtime. It allows many existing npm libraries (sync-based) to run inside TitanPL without modification.
Why This Exists
TitanPL runs on:
- V8 isolates
- Rust core Gravity runtime
- No Node.js process
- No libuv
- No Node event loop
Because of this, Node built-ins like fs, crypto, or process do not exist by default. @titanpl/node provides compatibility shims that redirect Node imports to Titan-native implementations.
π Quick Start (Important)
To enable Node compatibility in an action, import the globals shim first:
import "@titanpl/node/globals";This sets up:
processBuffer- global compatibility utilities
Then you can use Node-style imports normally:
import fs from "fs";
import path from "path";Supported Core Modules (Sync APIs)
The following modules are mapped to Titan's native implementations:
| Node API | Titan Core Mapping | Current Status |
|---|---|---|
fs | t.fs | Full (Sync) |
path | t.path | Full |
crypto | t.crypto | Full |
process | t.proc | Partial |
os | t.os | Partial |
Buffer | t.buffer | Full |
util | Pure JS Shims | Partial |
events | basic EventEmitter | Stable |
Sync Only
Only synchronous APIs are supported. Async Node APIs (callbacks/promises) are not supported because Titan uses drift() for async orchestration.
Example β Basic File Usage
import "@titanpl/node/globals";
import fs from "fs";
import path from "path";
export const hello = defineAction(() => {
const file = path.join("data", "hello.txt");
fs.writeFileSync(file, "Hello Titan");
const content = fs.readFileSync(file, "utf-8");
return { content };
});π¦ Supported npm Libraries
Many popular utility libraries work out-of-the-box because they rely on synchronous logic or the core modules listed above.
1. Environment Variables (dotenv)
Since dotenv uses fs.readFileSync and process.env, it works perfectly.
import "@titanpl/node/globals";
import dotenv from "dotenv";
dotenv.config();
export const config = defineAction(() => {
return { apiKey: process.env.API_KEY };
});2. Password Hashing (bcryptjs)
bcryptjs is a pure JavaScript implementation of bcrypt that works with Titan's random number generators.
import "@titanpl/node/globals";
import bcrypt from "bcryptjs";
export const hash = defineAction(() => {
const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync("secret-password", salt);
return {
hash,
isValid: bcrypt.compareSync("secret-password", hash)
};
});3. Querying with GraphQL
You can use graphql to parse schemas and execute queries synchronously against local data or in-memory resolvers.
import "@titanpl/node/globals";
import { graphql, buildSchema } from "graphql";
const schema = buildSchema(`
type Query {
hello: String
}
`);
const rootValue = { hello: () => "Hello from Titan GraphQL!" };
export const runQuery = defineAction(() => {
// Note: We use the sync execution pattern
const response = graphql({
schema,
source: "{ hello }",
rootValue
});
return response;
});4. Schema Validation (zod or joi)
These libraries are pure JavaScript and work seamlessly for validating inputs in your Titan Actions.
import "@titanpl/node/globals";
import { z } from "zod";
const UserSchema = z.object({
id: z.string().uuid(),
name: z.string().min(3)
});
export const validate = defineAction((input) => {
const result = UserSchema.safeParse(input);
return result;
});More Examples
Day.js
import "@titanpl/node/globals";
import dayjs from "dayjs";
export const now = defineAction(() => {
return { time: dayjs().format() };
});Lodash
import "@titanpl/node/globals";
import _ from "lodash";
export const shuffle = defineAction(() => {
return { arr: _.shuffle([1,2,3,4,5]) };
});UUID
import "@titanpl/node/globals";
import { v4 as uuid } from "uuid";
export const id = defineAction(() => {
return { id: uuid() };
});How It Works
During bundling, Titan rewrites imports like:
import fs from "fs";into:
import fs from "@titanpl/node/fs";This ensures zero overhead at runtime while preserving the developer experience you're used to in Node.js.
Detailed API Surface
Globals (@titanpl/node/globals)
Once imported, the following globals are injected into the environment:
processβ Full process shim withenv,argv, andpid.Bufferβ The classic Node-styleBufferfor binary data handling.__dirnameβ Maps to the current directory (project root during execution).cryptoβ WebCrypto-compatible surface exposinggetRandomValuesandrandomUUID.
fs (File System)
The fs module is a direct mapping to t.fs methods, targeting synchronous Node.js aliases.
readFileSync(path, encoding?)β Reads file contents.writeFileSync(path, data)β Writes data to a file.existsSync(path)β Checks if a path exists.readdirSync(path)β Lists directory entries.mkdirSync(path)β Creates directories.statSync(path)β Returns metadata object.rmSync(path)β Deletes a file or directory.
path
Full utility module for cross-platform path manipulation.
join(...parts)resolve(...parts)dirname(path)basename(path)extname(path)
crypto
Full Node-style crypto utilities backed by Titan's Rust core.
createHash(algo)β Supportingsha256,sha512,md5.createHmac(algo, key)β High-performance HMAC hashing.randomBytes(size)β Generates cryptographically secure bytes.randomUUID()β Native UUID v4 generator.createCipheriv(algo, key, iv)β Encrypt data using native Rust crypto.createDecipheriv(algo, key, iv)β Decrypt data.timingSafeEqual(a, b)β Constant-time string comparison.
buffer
The Buffer shim provides compatibility for libraries expecting the Node.js Buffer class.
Buffer.from(input, encoding?)β Support for UTF-8 and Base64 source.Buffer.toString(bytes, encoding?)β Conversions to shell strings or data strings.
util
Lightweight utility shims for common internal logic.
inspect(value)β JSON-based visualizer for debugging.inherits(ctor, superCtor)β Proto-based inheritance.format(...args)β String formatter for logs and outputs.
π« What Will NOT Work
Titan is not Node.js β it is a native Rust server running V8. The following will NOT work:
child_process(Titan handles processes via native extensions if needed)cluster(Titan multi-threaded via Rust, not JS clusters)- Native
.nodeaddons (Use Titan Rust Extensions instead) - Streams requiring real Node internals (libuv based)
- Async Node APIs (Use
drift()for async) - Libraries that depend heavily on the Node event loop
Timers & Microtasks
Because Titan executes in a strictly synchronous request-response cycle (only broken by drift), standard async timers are purposefully blocked to prevent hangs:
setTimeout,setInterval,setImmediateprocess.nextTick,queueMicrotask
Calling these will throw an error with the [Titan Node Libs Support] explanation.
Installation
npm install @titanpl/nodeRecommended Pattern
Always place the globals import at the very top of your action file:
import "@titanpl/node/globals";