@shiftlabsas/iman-agent
v0.1.2
Published
SDK for making your app manageable by IMAN (Instance Manager)
Readme
@shiftlabsas/iman-agent
SDK for making your app manageable by IMAN (Instance Manager). Install it in any Express-compatible app to expose health, manifest, and heartbeat endpoints that IMAN reads and displays in its control panel.
Demo: See polarities for a full working example of an Express app managed by IMAN.
How it works
Once installed, the agent:
- Mounts
/.iman/*routes protected by HMAC signature validation — IMAN uses these to fetch health and the manifest. - Pushes periodic heartbeats to your IMAN server (signed, never sending the raw token) so the instance stays marked as online.
- Declares a manifest — a capability contract that tells IMAN what actions (metrics, backups, deployments…) are available for this instance.
Installing the agent in your app
npm install @shiftlabsas/iman-agent
# or
pnpm add @shiftlabsas/iman-agentMinimal setup (Express)
import express from 'express';
import { ImanAgent, ManifestBuilder, Duration } from '@shiftlabsas/iman-agent';
const app = express();
const manifestBuilder = new ManifestBuilder()
.setName('my-app')
.setVersion('1.0.0')
.setEnv(process.env.NODE_ENV ?? 'production')
.setCapabilities({ metrics: true })
.setApp(app);
const agent = new ImanAgent({
instanceId: process.env.IMAN_INSTANCE_ID!,
token: process.env.IMAN_TOKEN!,
manifest: manifestBuilder, // agent uses builder.app automatically
app,
heartbeatPort: 3000,
imanUrl: process.env.IMAN_URL,
heartbeatInterval: Duration.minutes(1),
logLevel: 'info',
});Environment variables
| Variable | Required | Description |
| ------------------ | ------------- | -------------------------------------------------------------- |
| IMAN_INSTANCE_ID | Yes | Instance ID issued when the instance was registered in IMAN |
| IMAN_TOKEN | Yes | Shared secret used to sign requests — never sent over the wire |
| IMAN_URL | For heartbeat | Base URL of the IMAN server (e.g. https://iman.example.com) |
API reference
ImanAgent
new ImanAgent(options: ImanAgentOptions)| Option | Type | Required | Default | Description |
| ------------------- | --------------------------------- | ------------- | ---------------------- | -------------------------------------------------------- |
| instanceId | string | Yes | — | Instance ID issued by IMAN — sent in plaintext |
| token | string | Yes | — | Shared secret used to sign requests — never transmitted |
| manifest | ImanManifest \| ManifestBuilder | Yes | — | Built manifest or builder |
| app | ExpressLikeApp | No | — | App used to mount middleware and optionally start server |
| heartbeatPort | number | No | — | When set with app, agent calls app.listen(port, cb) |
| imanUrl | string | For heartbeat | — | Base URL of your IMAN server |
| heartbeatInterval | Duration | No | Duration.seconds(30) | How often to push heartbeats |
| logLevel | 'debug' \| 'info' \| 'silent' | No | 'info' | Console verbosity |
Methods
expressMiddleware()— Returns Express middleware that handles all/.iman/*routes. Mount it before your app routes.startHeartbeat()— Begins sending signed heartbeats toimanUrl. RequiresimanUrlto be set.attach(app)— Mounts middleware on the app.
When app and heartbeatPort are provided, the agent uses:
app.listen(PORT, () => {
console.log(`Salesforce API running on http://localhost:${PORT}`);
this.startHeartbeat();
console.log(`Heartbeat -> ${IMAN_URL} every 15s`);
});Routes exposed
| Route | Description |
| --------------------- | ----------------------------------- |
| GET /.iman/manifest | Returns the full manifest JSON |
| GET /.iman/health | Returns { status: "ok", version } |
All routes require a valid X-IMAN-Token header.
ManifestBuilder
Fluent builder for ImanManifest. All fields are set via chainable methods; .build() validates and returns the manifest.
import { ManifestBuilder, DatabaseType, CacheType } from '@shiftlabsas/iman-agent';
const manifest = new ManifestBuilder()
.setName('my-app')
.setVersion('2.3.1')
.setEnv('production')
.setCapabilities({
metrics: true,
settings: { read: true, write: ['theme', 'notifications'] },
backup: true,
deployments: { githubRepo: 'ShiftLabSAS/my-app', trigger: true },
})
.setDependencies({
databases: [{ type: DatabaseType.PSQL, label: 'primary', host: 'db.internal' }],
caches: [{ type: CacheType.REDIS, host: 'redis.internal' }],
})
.setEndpoints(['/api', '/webhooks'])
.build();You can also populate endpoints directly from an Express app:
const manifest = new ManifestBuilder()
.setName('my-app')
.setVersion('2.3.1')
.setEnv('production')
.setCapabilities({ metrics: true })
.setApp(app)
.build();Capabilities
| Field | Type | Description |
| ------------------------ | ---------- | ----------------------------- |
| metrics | boolean | Expose metrics to IMAN |
| settings.read | boolean | Allow IMAN to read settings |
| settings.write | string[] | Setting keys IMAN may write |
| backup | boolean | Support backup trigger |
| deployments.githubRepo | string | Source repo (org/name) |
| deployments.trigger | boolean | Allow IMAN to trigger deploys |
Dependency types
| Enum | Values |
| -------------- | ------------------------------------------------ |
| DatabaseType | SQLITE, MYSQL, PSQL, MONGODB, DYNAMODB |
| CacheType | REDIS, MEMCACHED |
| QueueType | SQS, RABBITMQ, KAFKA |
| StorageType | S3, GCS, AZURE |
Duration
Convenience wrapper for heartbeat intervals.
Duration.seconds(30);
Duration.minutes(5);
Duration.hours(1);
Duration.from({ minutes: 2, seconds: 30 }); // 150sSecurity
Heartbeats are signed with HMAC-SHA256 — the raw token never travels over the wire. Each request includes:
X-IMAN-Instance-ID— identifies the instance (not sensitive)X-IMAN-Timestamp— Unix timestamp in secondsX-IMAN-Signature—sha256=HMAC(token, "{timestamp}.{instanceId}")
IMAN rejects requests with a timestamp older than 5 minutes, preventing replay attacks.
Publishing a new version
- Bump
versioninpackage.json - Commit and push to
dev - Tag and push — CI will lint, test, build, then publish to npm after
prodenvironment approval:
git tag agent/v<version> && git push gh agent/v<version>
# e.g.
git tag agent/v0.2.0 && git push gh agent/v0.2.0