{"_id":"exospherehost","name":"exospherehost","dist-tags":{"beta":"0.0.1-b1","latest":"0.0.1-b1"},"versions":{"0.0.1-b1":{"name":"exospherehost","version":"0.0.1-b1","description":"Official TypeScript SDK for ExosphereHost","type":"module","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","test":"vitest","test:run":"vitest run","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build && npm run test:run","prepack":"npm run build","clean":"rm -rf dist","lint":"echo 'No linting configured'","lint:fix":"echo 'No linting configured'","version:beta":"node scripts/version.js beta","version:patch":"node scripts/version.js patch","version:minor":"node scripts/version.js minor","version:major":"node scripts/version.js major"},"dependencies":{"zod-to-json-schema":"^3.23.3"},"devDependencies":{"@types/node":"^20.14.11","@vitest/coverage-v8":"^1.6.0","typescript":"^5.6.3","vitest":"^1.6.0","zod":"^3.23.8"},"peerDependencies":{"@types/node":">=20.0.0","zod":"^3.23.8"},"keywords":["exosphere","exospherehost","typescript","sdk","workflow","ai","agents","distributed","state-management"],"repository":{"type":"git","url":"git+https://github.com/exospherehost/exospherehost.git","directory":"typescript-sdk"},"bugs":{"url":"https://github.com/exospherehost/exospherehost/issues"},"homepage":"https://exosphere.host","license":"MIT","engines":{"node":">=18.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_id":"exospherehost@0.0.1-b1","gitHead":"af1ec83407e8871ba06618a5f3594b5466f2ebe2","_nodeVersion":"22.14.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-LcD7BEmFA0MHbnhCLdageJ0dRmarkZozZyqX7Lrwke/KYq4bAW54jWwn3Z7eTZD+K0rAFCqMEwl8WpVlilGeZA==","shasum":"0e55f9f4c52526bb057a4498df094329e24e7005","tarball":"https://registry.npmjs.org/exospherehost/-/exospherehost-0.0.1-b1.tgz","fileCount":22,"unpackedSize":67538,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDqRcn+5AHm9JkJSXect8E4mpjVJ/1JCS64WXY7YVI+qQIgd5wT3+e17NJIxW8mBhUP63N9zTimdPkJQSu5dG2TcZo="}]},"_npmUser":{"name":"niveditjain","email":"nivedit@exosphere.host"},"directories":{},"maintainers":[{"name":"niveditjain","email":"nivedit@exosphere.host"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/exospherehost_0.0.1-b1_1758512281265_0.32681263603045907"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-22T03:38:01.171Z","0.0.1-b1":"2025-09-22T03:38:01.436Z","modified":"2025-09-22T03:38:01.722Z"},"maintainers":[{"name":"niveditjain","email":"nivedit@exosphere.host"}],"description":"Official TypeScript SDK for ExosphereHost","homepage":"https://exosphere.host","keywords":["exosphere","exospherehost","typescript","sdk","workflow","ai","agents","distributed","state-management"],"repository":{"type":"git","url":"git+https://github.com/exospherehost/exospherehost.git","directory":"typescript-sdk"},"bugs":{"url":"https://github.com/exospherehost/exospherehost/issues"},"license":"MIT","readme":"# ExosphereHost TypeScript SDK\r\n\r\n[![npm version](https://badge.fury.io/js/exospherehost.svg)](https://badge.fury.io/js/exospherehost)\r\n[![Node.js 18+](https://img.shields.io/badge/node.js-18+-green.svg)](https://nodejs.org/)\r\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\r\n\r\nThe official TypeScript SDK for [ExosphereHost](https://exosphere.host) - an open-source infrastructure layer for background AI workflows and agents. This SDK enables you to create distributed, stateful applications using a node-based architecture.\r\n\r\n## Overview\r\n\r\nExosphereHost provides a robust, affordable, and effortless infrastructure for building scalable AI workflows and agents. The TypeScript SDK allows you to:\r\n\r\n- Create distributed workflows using a simple node-based architecture.\r\n- Build stateful applications that can scale across multiple compute resources.\r\n- Execute complex AI workflows with automatic state management.\r\n- Integrate with the ExosphereHost platform for optimized performance.\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install exospherehost\r\n```\r\n\r\n## Quick Start\r\n\r\n> Important: In v1, all fields in `Inputs`, `Outputs`, and `Secrets` must be strings. If you need to pass complex data (e.g., JSON), serialize the data to a string first, then parse that string within your node.\r\n\r\n### Basic Node Creation\r\n\r\nCreate a simple node that processes data:\r\n\r\n```typescript\r\nimport { Runtime, BaseNode } from 'exospherehost';\r\nimport { z } from 'zod';\r\n\r\nclass SampleNode extends BaseNode {\r\n  static name = 'sample-node';\r\n  \r\n  static Inputs = z.object({\r\n    name: z.string(),\r\n    data: z.string() // v1: strings only\r\n  });\r\n  \r\n  static Outputs = z.object({\r\n    message: z.string(),\r\n    processed_data: z.string() // v1: strings only\r\n  });\r\n  \r\n  static Secrets = z.object({});\r\n\r\n  async execute() {\r\n    console.log(`Processing data for: ${this.inputs.name}`);\r\n    // Your processing logic here; serialize complex data to strings (e.g., JSON)\r\n    const processed_data = `completed:${this.inputs.data}`;\r\n    return {\r\n      message: \"success\",\r\n      processed_data: processed_data\r\n    };\r\n  }\r\n}\r\n\r\n// Initialize the runtime\r\nconst runtime = new Runtime(\r\n  \"MyProject\",\r\n  \"DataProcessor\",\r\n  [SampleNode],\r\n  {\r\n    stateManagerUri: process.env.EXOSPHERE_STATE_MANAGER_URI || 'http://localhost:8000',\r\n    key: process.env.EXOSPHERE_API_KEY || '',\r\n    stateManagerVersion: 'v0'\r\n  }\r\n);\r\n\r\nawait runtime.start();\r\n```\r\n\r\n## Environment Configuration\r\n\r\nThe SDK requires the following environment variables for authentication with ExosphereHost:\r\n\r\n```bash\r\nexport EXOSPHERE_STATE_MANAGER_URI=\"your-state-manager-uri\"\r\nexport EXOSPHERE_API_KEY=\"your-api-key\"\r\n```\r\n\r\n## Key Features\r\n\r\n- **Distributed Execution**: Run nodes across multiple compute resources\r\n- **State Management**: Automatic state persistence and recovery\r\n- **Type Safety**: Full TypeScript and Zod integration for input/output validation\r\n- **String-only data model (v1)**: All `Inputs`, `Outputs`, and `Secrets` fields are strings. Serialize non-string data (e.g., JSON) as needed.\r\n- **Async Support**: Native async/await support for high-performance operations\r\n- **Error Handling**: Built-in retry mechanisms and error recovery\r\n- **Scalability**: Designed for high-volume batch processing and workflows\r\n- **Graph Store**: Strings-only key-value store with per-run scope for sharing data across nodes (not durable across separate runs or clusters)\r\n\r\n## Architecture\r\n\r\nThe SDK is built around two core concepts:\r\n\r\n### Runtime\r\n\r\nThe `Runtime` class manages the execution environment and coordinates with the ExosphereHost state manager. It handles:\r\n\r\n- Node lifecycle management\r\n- State coordination\r\n- Error handling and recovery\r\n- Resource allocation\r\n\r\n### Nodes\r\n\r\nNodes are the building blocks of your workflows. Each node:\r\n\r\n- Defines input/output schemas using Zod schemas\r\n- Implements an `execute` method for processing logic\r\n- Can be connected to other nodes to form workflows\r\n- Automatically handles state persistence\r\n\r\n## Advanced Usage\r\n\r\n### Custom Node Configuration\r\n\r\n```typescript\r\nimport { BaseNode } from 'exospherehost';\r\nimport { z } from 'zod';\r\n\r\nclass ConfigurableNode extends BaseNode {\r\n  static name = 'configurable-node';\r\n  \r\n  static Inputs = z.object({\r\n    text: z.string(),\r\n    max_length: z.string().default(\"100\") // v1: strings only\r\n  });\r\n  \r\n  static Outputs = z.object({\r\n    result: z.string(),\r\n    length: z.string() // v1: strings only\r\n  });\r\n  \r\n  static Secrets = z.object({});\r\n\r\n  async execute() {\r\n    const max_length = parseInt(this.inputs.max_length);\r\n    const result = this.inputs.text.substring(0, max_length);\r\n    return {\r\n      result: result,\r\n      length: result.length.toString()\r\n    };\r\n  }\r\n}\r\n```\r\n\r\n### Error Handling\r\n\r\n```typescript\r\nimport { BaseNode } from 'exospherehost';\r\nimport { z } from 'zod';\r\n\r\nclass RobustNode extends BaseNode {\r\n  static name = 'robust-node';\r\n  \r\n  static Inputs = z.object({\r\n    data: z.string()\r\n  });\r\n  \r\n  static Outputs = z.object({\r\n    success: z.string(),\r\n    result: z.string()\r\n  });\r\n  \r\n  static Secrets = z.object({});\r\n\r\n  async execute() {\r\n    throw new Error(\"This is a test error\");\r\n  }\r\n}\r\n```\r\n\r\nError handling is automatically handled by the runtime and the state manager.\r\n\r\n### Working with Secrets\r\n\r\nSecrets allow you to securely manage sensitive configuration data like API keys, database credentials, and authentication tokens. Here's how to use secrets in your nodes:\r\n\r\n```typescript\r\nimport { BaseNode } from 'exospherehost';\r\nimport { z } from 'zod';\r\n\r\nclass APINode extends BaseNode {\r\n  static name = 'api-node';\r\n  \r\n  static Inputs = z.object({\r\n    user_id: z.string(),\r\n    query: z.string()\r\n  });\r\n  \r\n  static Outputs = z.object({\r\n    response: z.string(), // v1: strings only\r\n    status: z.string()\r\n  });\r\n  \r\n  static Secrets = z.object({\r\n    api_key: z.string(),\r\n    api_endpoint: z.string(),\r\n    database_url: z.string()\r\n  });\r\n\r\n  async execute() {\r\n    // Access secrets via this.secrets\r\n    const headers = { \"Authorization\": `Bearer ${this.secrets.api_key}` };\r\n    \r\n    // Use secrets for API calls\r\n    const response = await fetch(\r\n      `${this.secrets.api_endpoint}/process`,\r\n      {\r\n        method: 'POST',\r\n        headers: {\r\n          ...headers,\r\n          'Content-Type': 'application/json'\r\n        },\r\n        body: JSON.stringify({\r\n          user_id: this.inputs.user_id,\r\n          query: this.inputs.query\r\n        })\r\n      }\r\n    );\r\n    \r\n    // Serialize body: prefer JSON if valid; fallback to text or empty string\r\n    let response_str = \"\";\r\n    try {\r\n      const responseData = await response.json();\r\n      response_str = JSON.stringify(responseData);\r\n    } catch {\r\n      try {\r\n        response_str = await response.text() || \"\";\r\n      } catch {\r\n        response_str = \"\";\r\n      }\r\n    }\r\n\r\n    return {\r\n      response: response_str,\r\n      status: \"success\"\r\n    };\r\n  }\r\n}\r\n```\r\n\r\n**Key points about secrets:**\r\n\r\n- **Security**: Secrets are stored securely by the ExosphereHost Runtime and are never exposed in logs or error messages\r\n- **Validation**: The `Secrets` schema uses Zod for automatic validation of secret values\r\n- **String-only (v1)**: All `Secrets` fields must be strings.\r\n- **Access**: Secrets are available via `this.secrets` during node execution\r\n- **Types**: Common secret types include API keys, database credentials, encryption keys, and authentication tokens\r\n- **Injection**: Secrets are injected by the Runtime at execution time, so you don't need to handle them manually\r\n\r\n### Advanced Control Flow with Signals\r\n\r\nThe SDK provides signals for advanced control flow:\r\n\r\n```typescript\r\nimport { BaseNode, PruneSignal, ReQueueAfterSignal } from 'exospherehost';\r\nimport { z } from 'zod';\r\n\r\nclass ConditionalNode extends BaseNode {\r\n  static name = 'conditional-node';\r\n  \r\n  static Inputs = z.object({\r\n    data: z.string(),\r\n    should_retry: z.string()\r\n  });\r\n  \r\n  static Outputs = z.object({\r\n    result: z.string()\r\n  });\r\n  \r\n  static Secrets = z.object({});\r\n\r\n  async execute() {\r\n    const shouldRetry = this.inputs.should_retry === 'true';\r\n    \r\n    if (shouldRetry) {\r\n      // Requeue this state after 5 seconds\r\n      throw new ReQueueAfterSignal(5000);\r\n    }\r\n    \r\n    if (this.inputs.data === 'invalid') {\r\n      // Drop this state completely\r\n      throw new PruneSignal();\r\n    }\r\n    \r\n    return {\r\n      result: `Processed: ${this.inputs.data}`\r\n    };\r\n  }\r\n}\r\n```\r\n\r\n## State Management\r\n\r\nThe SDK provides a `StateManager` class for programmatically triggering graph executions and managing workflow states. This is useful for integrating ExosphereHost workflows into existing applications or for building custom orchestration logic.\r\n\r\n### StateManager Class\r\n\r\nThe `StateManager` class allows you to trigger graph executions with custom trigger states and create/update graph definitions using model-based parameters. It handles authentication and communication with the ExosphereHost state manager service.\r\n\r\n#### Initialization\r\n\r\n```typescript\r\nimport { StateManager } from 'exospherehost';\r\n\r\n// Initialize with explicit configuration\r\nconst stateManager = new StateManager(\r\n  \"MyProject\",\r\n  {\r\n    stateManagerUri: \"https://your-state-manager.exosphere.host\",\r\n    key: \"your-api-key\",\r\n    stateManagerVersion: \"v0\"\r\n  }\r\n);\r\n\r\n// Or initialize with environment variables\r\nconst stateManager = new StateManager(\"MyProject\", {\r\n  stateManagerUri: process.env.EXOSPHERE_STATE_MANAGER_URI || 'http://localhost:8000',\r\n  key: process.env.EXOSPHERE_API_KEY || ''\r\n});\r\n```\r\n\r\n**Parameters:**\r\n\r\n- `namespace` (string): The namespace for your project\r\n- `config.stateManagerUri` (string, optional): The URI of the state manager service. If not provided, reads from `EXOSPHERE_STATE_MANAGER_URI` environment variable\r\n- `config.key` (string, optional): Your API key. If not provided, reads from `EXOSPHERE_API_KEY` environment variable\r\n- `config.stateManagerVersion` (string): The API version to use (default: \"v0\")\r\n\r\n#### Creating/Updating Graph Definitions\r\n\r\n```typescript\r\nimport { StateManager, GraphNodeModel } from 'exospherehost';\r\n\r\nasync function createGraph() {\r\n  const stateManager = new StateManager(\"MyProject\", {\r\n    stateManagerUri: process.env.EXOSPHERE_STATE_MANAGER_URI || 'http://localhost:8000',\r\n    key: process.env.EXOSPHERE_API_KEY || ''\r\n  });\r\n  \r\n  // Define graph nodes using models\r\n  const graphNodes: GraphNodeModel[] = [\r\n    {\r\n      node_name: \"DataProcessorNode\",\r\n      namespace: \"MyProject\",\r\n      identifier: \"data_processor\",\r\n      inputs: {\r\n        \"source\": \"initial\",\r\n        \"format\": \"json\"\r\n      },\r\n      next_nodes: [\"data_validator\"]\r\n    },\r\n    {\r\n      node_name: \"DataValidatorNode\", \r\n      namespace: \"MyProject\",\r\n      identifier: \"data_validator\",\r\n      inputs: {\r\n        \"data\": \"${{ data_processor.outputs.processed_data }}\",\r\n        \"validation_rules\": \"initial\"\r\n      },\r\n      next_nodes: []\r\n    }\r\n  ];\r\n  \r\n  // Create or update the graph \r\n  const result = await stateManager.upsertGraph(\r\n    \"my-workflow\",\r\n    graphNodes,\r\n    {\r\n      \"api_key\": \"your-api-key\",\r\n      \"database_url\": \"your-database-url\"\r\n    }\r\n  );\r\n  \r\n  console.log(`Graph created/updated: ${result.validation_status}`);\r\n  return result;\r\n}\r\n```\r\n\r\n**Parameters:**\r\n\r\n- `graphName` (string): Name of the graph to create/update\r\n- `graphNodes` (GraphNodeModel[]): List of graph node models defining the workflow \r\n- `secrets` (Record<string, string>): Key/value secrets available to all nodes\r\n\r\n**Returns:**\r\n\r\n- `Promise<any>`: Validated graph object returned by the API\r\n\r\n**Raises:**\r\n\r\n- `Error`: If validation fails or times out\r\n\r\n#### Triggering Graph Execution\r\n\r\n```typescript\r\nimport { StateManager } from 'exospherehost';\r\n\r\n// Create a single trigger state\r\nconst triggerState = {\r\n  identifier: \"user-login\",\r\n  inputs: {\r\n    \"user_id\": \"12345\",\r\n    \"session_token\": \"abc123def456\",\r\n    \"timestamp\": \"2024-01-15T10:30:00Z\"\r\n  }\r\n};\r\n\r\n// Trigger the graph \r\nconst result = await stateManager.trigger(\r\n  \"my-graph\",\r\n  {\r\n    \"user_id\": \"12345\",\r\n    \"session_token\": \"abc123def456\"\r\n  },\r\n  {\r\n    \"cursor\": \"0\" // persisted across nodes\r\n  }\r\n);\r\n```\r\n\r\n**Parameters:**\r\n\r\n- `graphName` (string): Name of the graph to execute\r\n- `inputs` (Record<string, string> | undefined): Key/value inputs for the first node (strings only)\r\n- `store` (Record<string, string> | undefined): Graph-level key/value store persisted across nodes\r\n\r\n**Returns:**\r\n\r\n- `Promise<any>`: JSON payload from the state manager\r\n\r\n**Raises:**\r\n\r\n- `Error`: If the HTTP request fails\r\n\r\n## Complete Minimal Example\r\n\r\nHere's a complete example that demonstrates the full workflow:\r\n\r\n```typescript\r\nimport { StateManager, BaseNode, Runtime, GraphNodeModel } from 'exospherehost';\r\nimport { z } from 'zod';\r\n\r\n// 1. Define a custom node\r\nclass GreetingNode extends BaseNode {\r\n  static name = 'greeting';\r\n  \r\n  static Inputs = z.object({\r\n    name: z.string()\r\n  });\r\n  \r\n  static Outputs = z.object({\r\n    greeting: z.string()\r\n  });\r\n  \r\n  static Secrets = z.object({});\r\n\r\n  async execute() {\r\n    return {\r\n      greeting: `Hello, ${this.inputs.name}!`\r\n    };\r\n  }\r\n}\r\n\r\n// 2. Set up the state manager\r\nconst sm = new StateManager('example-namespace', {\r\n  stateManagerUri: 'http://localhost:8000',\r\n  key: 'your-api-key'\r\n});\r\n\r\n// 3. Define the workflow graph\r\nconst nodes: GraphNodeModel[] = [\r\n  {\r\n    node_name: 'greeting',\r\n    namespace: 'example-namespace',\r\n    identifier: 'greeter',\r\n    inputs: {\r\n      name: \"store.name\"\r\n    }\r\n  }\r\n];\r\n\r\n// 4. Create the graph\r\nawait sm.upsertGraph('greeting-workflow', nodes, {});\r\n\r\n// 5. Start the runtime to process nodes\r\nconst runtime = new Runtime('example-namespace', 'greeting-runtime', [GreetingNode], {\r\n  stateManagerUri: 'http://localhost:8000',\r\n  key: 'your-api-key'\r\n});\r\n\r\nawait runtime.start();\r\n\r\n// 6. Trigger the workflow\r\nconst store = { name: 'World' };\r\nawait sm.trigger('greeting-workflow', { name: 'World' }, store);\r\n```\r\n\r\n## License\r\n\r\nMIT","readmeFilename":"README.md","_rev":"1-eb051a5a27725244749cecae31a49a5d"}