No description
Find a file
Dirk Hoyer 3aeaaf4439 chore: Release v0.17.5
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:18:35 +01:00
examples Initial commit 2025-10-15 08:57:01 +02:00
ixt-public@eaf4205d72 chore: Update ixt-public submodule to include BlobStore schemas 2026-02-23 19:45:16 +01:00
.gitignore Initial commit 2025-10-15 08:57:01 +02:00
.gitmodules feat: Source IPC schemas from ixt-public submodule 2026-02-17 14:56:53 +01:00
BIDIRECTIONAL_IPC_GUIDE.md Initial commit 2025-10-15 08:57:01 +02:00
CHANGELOG.md Initial commit 2025-10-15 08:57:01 +02:00
IMPLEMENTATION_SUMMARY.md Initial commit 2025-10-15 08:57:01 +02:00
ipc.capnp.js fix(nodejs): Fix Cap'n Proto IPC serialization for process runtime 2026-01-08 09:31:53 +01:00
ixt-process-module.js chore: Update SDK for v0.13.0 2026-02-25 20:00:10 +01:00
LICENSE feat(sdk-nodejs): Add MIT license for SDK distribution 2025-10-23 08:38:54 +02:00
package-lock.json feat: Add length-prefixed JSON framing (Mission I140) 2025-12-24 19:39:53 +01:00
package.json chore: Release v0.17.5 2026-03-24 21:18:35 +01:00
PYTHON_TO_NODEJS.md Initial commit 2025-10-15 08:57:01 +02:00
QUICKREF.md Initial commit 2025-10-15 08:57:01 +02:00
README.md docs: Update documentation for multi-method service patterns (I151) 2026-02-27 13:13:21 +01:00
RELEASE_NOTES.md feat: Source IPC schemas from ixt-public submodule 2026-02-17 14:56:53 +01:00
serialization.js chore: Update SDK for v0.13.0 2026-02-25 20:00:10 +01:00
service-payloads.js chore: Update SDK for v0.13.0 2026-02-25 20:00:10 +01:00
test-serialization.js feat: Add length-prefixed JSON framing (Mission I140) 2025-12-24 19:39:53 +01:00
test-services.js Initial commit 2025-10-15 08:57:01 +02:00

IXT Node.js SDK

Node.js SDK for building IXT modules that run as separate processes and communicate with the IXT runtime via IPC.

Features

  • Simple base class for module development
  • Automatic IPC connection handling
  • JSON message parsing and framing
  • Lifecycle management (init, handle, shutdown, health_check)
  • Base64 payload encoding/decoding helpers
  • Error handling and logging
  • Zero external dependencies (Node.js 14+)
  • Full async/await support
  • NEW: Bidirectional IPC Services
    • MessageBus: Send messages to other modules
    • KV Store: Persist and retrieve data (get, set, delete, exists)
    • Logging: Send structured logs to runtime

Installation

# From source
cd sdk/ixt-sdk-nodejs
npm install

# Or copy ixt-process-module.js to your project
cp sdk/ixt-sdk-nodejs/ixt-process-module.js my-module/

Quick Start

1. Create Your Module

#!/usr/bin/env node
const { IxtProcessModule } = require('./ixt-process-module');

class MyModule extends IxtProcessModule {
  async onInit(config) {
    // Initialize module with configuration
    this.dbUrl = config.database_url || 'sqlite://data.db';
    this.log(`Connecting to database: ${this.dbUrl}`);
    // Initialize your resources here
  }

  async onHandle(message, context) {
    // Handle incoming messages
    // Tip: Use `ixt codegen schema.toml` to generate typed service proxies.
    // See examples/codegen/ for multi-method service patterns.
    const topic = message.topic;
    const payloadData = this.decodePayload(message.payload);

    if (topic === 'my.service.process') {
      const result = await this.processData(payloadData);
      return this.success({
        result: this.encodePayload(result)
      });
    } else if (topic === 'my.service.query') {
      const data = await this.queryData(payloadData);
      return this.success({
        data: this.encodePayload(data)
      });
    } else {
      return this.error('UNKNOWN_TOPIC', `Unknown topic: ${topic}`);
    }
  }

  async onShutdown() {
    // Clean up resources
    this.log('Shutting down module');
    // Close connections, save state, etc.
  }

  async onHealthCheck() {
    // Report health status (optional)
    return {
      healthy: true,
      database_connected: await this.checkDbConnection(),
      requests_processed: this.requestCount
    };
  }
}

if (require.main === module) {
  new MyModule().run();
}

2. Create Manifest

# manifest.toml
schema_version = "3.0"

[module]
name = "my-module"
version = "1.0.0"
description = "My IXT module"
author = "Your Name"
license = "MIT"
runtime_targets = ["Process"]

[provides]
services = ["my.service"]

[services."my.service"]
timeout_ms = 5000

[services."my.service".methods.process]
input = "ProcessRequest"
output = "ProcessResponse"

[services."my.service".methods.query]
input = "QueryRequest"
output = "QueryResponse"

[config]
database_url = { type = "string", default = "sqlite://data.db" }

3. Run Your Module

The IXT runtime will spawn your module automatically. For development testing:

# Runtime sets these environment variables:
export IXT_IPC_SOCKET=/tmp/ixt-module-abc123.sock
export IXT_MODULE_ID=my-module:1.0.0/instance-001

# Run your module
node my-module.js

API Reference

IxtProcessModule Base Class

Abstract base class for IXT modules. Implement these methods:

onInit(config)

Initialize your module with configuration from the manifest.

async onInit(config) {
  this.setting = config.my_setting || 'default';
  // Initialize resources, connect to services, etc.
}

onHandle(message, context)

Handle incoming messages. This is where your business logic goes.

async onHandle(message, context) {
  const topic = message.topic;
  const payload = this.decodePayload(message.payload);
  
  // Process the message
  const result = await this.process(payload);
  
  // Return success or error
  return this.success({ result: this.encodePayload(result) });
}

Message structure:

{
  topic: 'service.name',           // Service topic
  payload: 'base64-encoded-data',  // Base64-encoded payload
  priority: 1,                     // Priority level
  ttl_ms: 5000                     // Time-to-live in milliseconds
}

Context structure:

{
  trace_id: 'unique-trace-id',     // Distributed tracing ID
  source_module: 'caller:1.0.0',   // Calling module
  timestamp: 1234567890            // Unix timestamp
}

onShutdown()

Gracefully shutdown your module.

async onShutdown() {
  await this.db.close();
  await this.saveState();
}

onHealthCheck() (optional)

Report health status. Default returns {healthy: true}.

async onHealthCheck() {
  return {
    healthy: await this.isHealthy(),
    uptime_seconds: process.uptime()
  };
}

Helper Methods

success(data)

Create a success response.

return this.success({ result: 42 });

error(code, message, details)

Create an error response.

return this.error('INVALID_INPUT', 'Missing required field: name');

encodePayload(data)

Encode binary data as base64 string.

const encoded = this.encodePayload(Buffer.from("hello world"));

decodePayload(payload)

Decode base64 payload to Buffer.

const data = this.decodePayload(message.payload);
const text = data.toString('utf8');

log(message)

Log informational message (to stderr, captured by runtime).

this.log(`Processing request ${requestId}`);

logError(message)

Log error message.

this.logError(`Failed to connect: ${error}`);

Bidirectional IPC Services

The SDK provides methods to interact with runtime services from within your module.

MessageBus Service

Send messages to other modules via the MessageBus.

sendMessage(topic, payload, priority, ttlMs)

Send a message to another module.

const response = await this.sendMessage(
  'notifications.send',                    // Topic
  Buffer.from(JSON.stringify({             // Payload (binary)
    user_id: 123,
    message: 'Hello!'
  })),
  2,                                       // Priority: 1=low, 2=normal, 3=high, 4=critical
  5000                                     // TTL in milliseconds (optional)
);

if (response.success) {
  this.log('Message sent successfully');
}

Parameters:

  • topic (string): Message topic (e.g., "user.created", "order.process")
  • payload (Buffer): Binary message payload
  • priority (number): Message priority (1=low, 2=normal, 3=high, 4=critical), default: 1
  • ttlMs (number, optional): Time-to-live in milliseconds

Returns: Promise