{"_id":"@cloudsignal/ai-transport","_rev":"6-378909bf5250ee49119408b52c495d04","name":"@cloudsignal/ai-transport","dist-tags":{"latest":"0.1.4"},"versions":{"0.1.0":{"name":"@cloudsignal/ai-transport","version":"0.1.0","keywords":["mqtt","ai","vercel","ai-sdk","transport","streaming","cloudsignal","offline-recovery","real-time","multi-device"],"license":"MIT","_id":"@cloudsignal/ai-transport@0.1.0","maintainers":[{"name":"nocoderoi","email":"info@nocoderoi.com"}],"dist":{"shasum":"32d54887b3160b29cfe189d51efe3008d60251ed","tarball":"https://registry.npmjs.org/@cloudsignal/ai-transport/-/ai-transport-0.1.0.tgz","fileCount":17,"integrity":"sha512-BUdmUu6hZBlIQ3OMoI9iyYU37x9qeD4WARY3PL7JIdkMQYdlmSmm3fJW1wvuakSZy5S+ELje+JEA/Pje7qfCdA==","signatures":[{"sig":"MEQCIGGp5G88M+VmFydGxGWMul8cZBPIwNEPfUPUkiAwtUriAiBYLS67Pe6OP5rbLvhNK4mTYSD8dFFlNqhHI3MrH+LCWQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":73479},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js","require":"./dist/server.cjs"}},"gitHead":"83336685aa2c7010e5411a710ffb6047f9e8c924","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit"},"_npmUser":{"name":"nocoderoi","email":"info@nocoderoi.com"},"deprecated":"Deprecated due to internal-content disclosure. Install the latest version of this package.","_npmVersion":"10.8.2","description":"Vercel AI SDK transport using CloudSignal MQTT — drop-in replacement for HTTP streaming with offline recovery, multi-device sync, and ACL control","directories":{},"_nodeVersion":"20.20.1","_hasShrinkwrap":false,"devDependencies":{"ai":"^6.0.0","tsup":"^8.5.0","typescript":"^5.9.0","@types/node":"^22.0.0","@cloudsignal/mqtt-client":"^2.2.2"},"peerDependencies":{"ai":">=6.0.0","@cloudsignal/mqtt-client":">=2.2.0"},"_npmOperationalInternal":{"tmp":"tmp/ai-transport_0.1.0_1774036721447_0.8665808325666071","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@cloudsignal/ai-transport","version":"0.1.1","keywords":["mqtt","ai","vercel","ai-sdk","transport","streaming","cloudsignal","offline-recovery","real-time","multi-device"],"license":"MIT","_id":"@cloudsignal/ai-transport@0.1.1","maintainers":[{"name":"nocoderoi","email":"info@nocoderoi.com"}],"dist":{"shasum":"1c603881dfca76d3549ba42192f3ca2a6ec628ae","tarball":"https://registry.npmjs.org/@cloudsignal/ai-transport/-/ai-transport-0.1.1.tgz","fileCount":18,"integrity":"sha512-K3NQZqJN/9/Z/Q8rnoeSMVMuPlq4uzeal/0mYkjzGT+3VziW+fjziRfPAVqUq6xJWbK8azPebcLlK0nCPSisCw==","signatures":[{"sig":"MEYCIQC1jTwnOzYcegGpy9JSVuQQcg5jjBefdaKhqGkCJWUnQQIhAPSh0IHkBVj/rM5VvXSOgZ4KAg6X7uN7aYAUM2RnQeor","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83351},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js","require":"./dist/server.cjs"}},"gitHead":"845f8a0e343e76a6772a24366a7bc1ad32c2086b","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit"},"_npmUser":{"name":"nocoderoi","email":"info@nocoderoi.com"},"deprecated":"Deprecated due to internal-content disclosure. Install the latest version of this package.","_npmVersion":"10.8.2","description":"Vercel AI SDK transport using CloudSignal MQTT — drop-in replacement for HTTP streaming with offline recovery, multi-device sync, and ACL control","directories":{},"_nodeVersion":"20.20.1","_hasShrinkwrap":false,"devDependencies":{"ai":"^6.0.0","tsup":"^8.5.0","typescript":"^5.9.0","@types/node":"^22.0.0","@cloudsignal/mqtt-client":"^2.2.2"},"peerDependencies":{"ai":">=6.0.0","@cloudsignal/mqtt-client":">=2.2.0"},"_npmOperationalInternal":{"tmp":"tmp/ai-transport_0.1.1_1774057307504_0.11964752176751325","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@cloudsignal/ai-transport","version":"0.1.2","keywords":["mqtt","ai","vercel","ai-sdk","transport","streaming","cloudsignal","offline-recovery","real-time","multi-device"],"license":"MIT","_id":"@cloudsignal/ai-transport@0.1.2","maintainers":[{"name":"nocoderoi","email":"info@nocoderoi.com"}],"dist":{"shasum":"70bd0efc00416fb55fc24ecc0a2056110741489b","tarball":"https://registry.npmjs.org/@cloudsignal/ai-transport/-/ai-transport-0.1.2.tgz","fileCount":13,"integrity":"sha512-6MyRTsm0UtnY3+9DrjisJQOqz8WHxv3vtvvi5xkUFDjKBlChfuMALYPXHAmmHNj9klr3fdzqvoGm1UemPzkLUQ==","signatures":[{"sig":"MEQCICSBAo2MToqanGI4xadPC+RehbDPYv6eK/0H62b/ZER7AiBpp1gj5YMOgw0rwhnLOOIaNSiCMjsnMujq9kq8vo6oTQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":44469},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js","require":"./dist/server.cjs"}},"gitHead":"ee3834b6f0e57d3daf13edab4b8eb154a28e530f","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build && bash ../scripts/check-publish-safe.sh ."},"_npmUser":{"name":"nocoderoi","email":"info@nocoderoi.com"},"_npmVersion":"10.8.2","description":"Vercel AI SDK transport using CloudSignal MQTT — drop-in replacement for HTTP streaming with offline recovery, multi-device sync, and ACL control","directories":{},"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"ai":"^6.0.0","tsup":"^8.5.0","typescript":"^5.9.0","@types/node":"^22.0.0","@cloudsignal/mqtt-client":"^2.2.2"},"peerDependencies":{"ai":">=6.0.0","@cloudsignal/mqtt-client":">=2.2.0"},"_npmOperationalInternal":{"tmp":"tmp/ai-transport_0.1.2_1777532141687_0.3532536124148975","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@cloudsignal/ai-transport","version":"0.1.3","keywords":["mqtt","ai","vercel","ai-sdk","transport","streaming","cloudsignal","offline-recovery","real-time","multi-device"],"license":"MIT","_id":"@cloudsignal/ai-transport@0.1.3","maintainers":[{"name":"nocoderoi","email":"info@nocoderoi.com"}],"homepage":"https://cloudsignal.io","bugs":{"url":"https://github.com/cloudsignal/ai-transport/issues"},"dist":{"shasum":"789d1e1d5368ccd473a78d8f55235375b902f609","tarball":"https://registry.npmjs.org/@cloudsignal/ai-transport/-/ai-transport-0.1.3.tgz","fileCount":16,"integrity":"sha512-cRi4xLVGq8esIzffd/eFoguaX+CyNlJaR1vLzyMpaCSY09F+/BpSQ6VAk9YseGneYBP5WUNGljU9voG6H/2FnA==","signatures":[{"sig":"MEQCIAbFYinKBWeAqrUHFM/bYC3/AMTcxmX8GFufHplAIaRaAiBvZTlsy2nq8x2x8GLEx7EuNd38BKWdVl/Vm3beLOD/9w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":60756},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./server":{"types":"./dist/server.d.ts","import":"./dist/server.js","require":"./dist/server.cjs"}},"gitHead":"d6ecf15268c83c7ec061454a9edefb47c6399a2a","scripts":{"dev":"tsup --watch","build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build && bash ../scripts/check-publish-safe.sh ."},"_npmUser":{"name":"nocoderoi","email":"info@nocoderoi.com"},"repository":{"url":"git+https://github.com/cloudsignal/ai-transport.git","type":"git"},"_npmVersion":"10.8.2","description":"Vercel AI SDK transport using CloudSignal MQTT — drop-in replacement for HTTP streaming with offline recovery, multi-device sync, and ACL control","directories":{},"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"ai":"^6.0.0","tsup":"^8.5.0","typescript":"^5.9.0","@types/node":"^22.0.0","@cloudsignal/mqtt-client":"^2.2.2"},"peerDependencies":{"ai":">=6.0.0","@cloudsignal/mqtt-client":">=2.2.0"},"_npmOperationalInternal":{"tmp":"tmp/ai-transport_0.1.3_1782430619150_0.6356942301440587","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@cloudsignal/ai-transport","version":"0.1.4","description":"Vercel AI SDK transport using CloudSignal MQTT — drop-in replacement for HTTP streaming with offline recovery, multi-device sync, and ACL control","type":"module","exports":{".":{"import":"./dist/index.js","require":"./dist/index.cjs","types":"./dist/index.d.ts"},"./server":{"import":"./dist/server.js","require":"./dist/server.cjs","types":"./dist/server.d.ts"}},"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","prepublishOnly":"npm run build && bash ../scripts/check-publish-safe.sh ."},"peerDependencies":{"ai":">=6.0.0","@cloudsignal/mqtt-client":">=2.2.5"},"devDependencies":{"ai":"^6.0.0","@cloudsignal/mqtt-client":"^2.2.5","typescript":"^5.9.0","tsup":"^8.5.0","@types/node":"^22.0.0"},"keywords":["mqtt","ai","vercel","ai-sdk","transport","streaming","cloudsignal","offline-recovery","real-time","multi-device"],"license":"MIT","homepage":"https://cloudsignal.io","repository":{"type":"git","url":"git+https://github.com/cloudsignal/ai-transport.git"},"bugs":{"url":"https://github.com/cloudsignal/ai-transport/issues"},"_id":"@cloudsignal/ai-transport@0.1.4","gitHead":"3605d2e319ac90c5314e405a1f7bb99ca9922739","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-HhKOLUECKZDpr49g9ckTITvLAUrZOKlpP4LG/Ty7WvLcFN1xMsLmaEM3D8/B4rEYmrb3EPxAl6CbK3//kcvksQ==","shasum":"15620dc58e8c4f10be7725aaa38227e3d96a7c2e","tarball":"https://registry.npmjs.org/@cloudsignal/ai-transport/-/ai-transport-0.1.4.tgz","fileCount":16,"unpackedSize":60756,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIC6EXeexAQVF4JsOg/XLmpF0gyDRzuaP0kOxtId88eY3AiEAwnV8BBilPAIO0oJgvD6jROkSZPqzjqTIOvsnDgwn4pA="}]},"_npmUser":{"name":"nocoderoi","email":"info@nocoderoi.com"},"directories":{},"maintainers":[{"name":"nocoderoi","email":"info@nocoderoi.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ai-transport_0.1.4_1785543191172_0.6693148437859429"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-20T19:58:41.367Z","modified":"2026-08-01T00:13:11.579Z","0.1.0":"2026-03-20T19:58:41.590Z","0.1.1":"2026-03-21T01:41:47.634Z","0.1.2":"2026-04-30T06:55:41.825Z","0.1.3":"2026-06-25T23:36:59.276Z","0.1.4":"2026-08-01T00:13:11.392Z"},"bugs":{"url":"https://github.com/cloudsignal/ai-transport/issues"},"license":"MIT","homepage":"https://cloudsignal.io","keywords":["mqtt","ai","vercel","ai-sdk","transport","streaming","cloudsignal","offline-recovery","real-time","multi-device"],"repository":{"type":"git","url":"git+https://github.com/cloudsignal/ai-transport.git"},"description":"Vercel AI SDK transport using CloudSignal MQTT — drop-in replacement for HTTP streaming with offline recovery, multi-device sync, and ACL control","maintainers":[{"name":"nocoderoi","email":"info@nocoderoi.com"}],"readme":"# @cloudsignal/ai-transport\n\nDrop-in MQTT transport for the [Vercel AI SDK](https://sdk.vercel.ai/). Replace HTTP streaming with CloudSignal MQTT — get offline recovery, multi-device sync, and broker-level access control. Zero UI changes.\n\n```typescript\nimport { useChat } from '@ai-sdk/react';\nimport { CloudSignalChatTransport } from '@cloudsignal/ai-transport';\n\nconst { messages, sendMessage } = useChat({\n  transport: new CloudSignalChatTransport({\n    api: '/api/chat',\n    authEndpoint: '/api/auth/mqtt',\n    wssUrl: 'wss://connect.cloudsignal.app:18885/',\n  }),\n});\n```\n\nSame `messages`. Same `sendMessage`. Same UI code. Different infrastructure.\n\n## What changes\n\n| | HTTP streaming (default) | CloudSignal MQTT |\n|---|---|---|\n| **Disconnection** | Response lost, must re-request | Retained message delivers full response on reconnect |\n| **Multi-device** | Not possible (point-to-point) | Any number of clients subscribe to the same session |\n| **Access control** | App-level middleware | Broker-level ACL on every publish/subscribe |\n| **Tenant isolation** | App-level | Broker-enforced mountpoints |\n| **Delivery guarantee** | None | QoS 0 (tokens), QoS 1 (complete response) |\n| **Per-message cost** | N/A | N/A (vs Ably/Pusher per-message fees) |\n| **Protocol** | HTTP | MQTT (ISO/IEC 20922) — no vendor lock-in |\n\n## Install\n\n```bash\nnpm install @cloudsignal/ai-transport @cloudsignal/mqtt-client ai @ai-sdk/react\n```\n\n`@cloudsignal/mqtt-client` and `ai` are peer dependencies.\n\n## Quick Start\n\n### 1. Client — swap the transport\n\n```typescript\n// app/page.tsx\n'use client';\n\nimport { useChat } from '@ai-sdk/react';\nimport { CloudSignalChatTransport } from '@cloudsignal/ai-transport';\n\nconst transport = new CloudSignalChatTransport({\n  api: '/api/chat',\n  authEndpoint: '/api/auth/mqtt',\n  wssUrl: process.env.NEXT_PUBLIC_CLOUDSIGNAL_WSS_URL!,\n});\n\nexport default function Chat() {\n  const { messages, sendMessage } = useChat({ transport });\n\n  return (\n    <div>\n      {messages.map((m) => (\n        <div key={m.id}>\n          {m.role}: {m.parts.map((p) => p.type === 'text' ? p.text : null)}\n        </div>\n      ))}\n      <form onSubmit={(e) => { e.preventDefault(); sendMessage({ text: e.currentTarget.input.value }); }}>\n        <input name=\"input\" />\n      </form>\n    </div>\n  );\n}\n```\n\n### 2. Server — publish stream to MQTT\n\n```typescript\n// app/api/chat/route.ts\nimport { streamText } from 'ai';\nimport { anthropic } from '@ai-sdk/anthropic';\nimport { publishStreamToMqtt } from '@cloudsignal/ai-transport/server';\nimport { getServerMqttClient } from '@/lib/mqtt-server';\n\nexport async function POST(request: Request) {\n  const { chatId, messages, requestId } = await request.json();\n\n  const mqttClient = await getServerMqttClient();\n\n  const result = streamText({\n    model: anthropic('claude-sonnet-4-20250514'),\n    messages,\n  });\n\n  // Publish AI stream to MQTT — response arrives via subscription, not HTTP\n  publishStreamToMqtt(mqttClient, chatId, result, { requestId }).catch(console.error);\n\n  return Response.json({ status: 'streaming', chatId }, { status: 202 });\n}\n```\n\n### 3. Auth endpoint — issue temporary MQTT credentials\n\n```typescript\n// app/api/auth/mqtt/route.ts\nexport async function POST() {\n  const res = await fetch(`${process.env.CLOUDSIGNAL_TOKEN_SERVICE_URL}/v1/create`, {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({\n      organization_id: process.env.CLOUDSIGNAL_ORG_ID,\n      secret_key: process.env.CLOUDSIGNAL_SECRET_KEY,\n      user_email: `user-${crypto.randomUUID().slice(0, 8)}@chat.cloudsignal.app`,\n    }),\n  });\n\n  const data = await res.json();\n  // The token service returns credentials nested under `mqtt_credentials`.\n  return Response.json(data.mqtt_credentials); // { username, password }\n}\n```\n\n### 4. Server MQTT client — singleton connection\n\n```typescript\n// lib/mqtt-server.ts\nimport CloudSignalClient from '@cloudsignal/mqtt-client';\n\nlet client: CloudSignalClient | null = null;\n\nexport async function getServerMqttClient(): Promise<CloudSignalClient> {\n  if (client?.isConnected()) return client;\n\n  // tokenServiceUrl is a constructor option — required before connectWithToken.\n  client = new CloudSignalClient({ preset: 'server', tokenServiceUrl: 'https://auth.cloudsignal.app' });\n  await client.connectWithToken({\n    host: process.env.CLOUDSIGNAL_MQTTS_URL!,\n    organizationId: process.env.CLOUDSIGNAL_ORG_ID!,\n    secretKey: process.env.CLOUDSIGNAL_SECRET_KEY!,\n    userEmail: 'ai-server@internal.cloudsignal.app',\n  });\n\n  return client;\n}\n```\n\n## How It Works\n\n```\n1. useChat() calls transport.sendMessages()\n2. Transport subscribes to MQTT topics chat/{chatId}/stream and chat/{chatId}/complete\n3. Transport sends HTTP POST to /api/chat (returns 202 immediately)\n4. Server calls streamText(), publishes each UIMessageChunk to MQTT (QoS 0)\n5. Browser receives chunks via WebSocket subscription → ReadableStream → useChat renders\n6. Server publishes full response as retained message to chat/{chatId}/complete (QoS 1)\n7. If client disconnects and reconnects, broker delivers the retained complete message\n```\n\nThe HTTP POST only triggers the server. The actual response travels over MQTT. This is the key architectural difference from the default HTTP transport.\n\n## MQTT Topics\n\n| Topic | QoS | Retained | Purpose |\n|-------|-----|----------|---------|\n| `chat/{chatId}/stream` | 0 | No | UIMessageChunk stream (each token) |\n| `chat/{chatId}/complete` | 1 | Yes | Full response for offline recovery |\n\n## API\n\n### `CloudSignalChatTransport`\n\nImplements the Vercel AI SDK `ChatTransport` interface.\n\n```typescript\nnew CloudSignalChatTransport({\n  // Required (one of):\n  client: existingCloudSignalClient,      // Use a pre-connected client\n  // OR\n  authEndpoint: '/api/auth/mqtt',         // Endpoint returning { username, password }\n  wssUrl: 'wss://connect.cloudsignal.app:18885/',\n\n  // Optional:\n  api: '/api/chat',                       // Server endpoint (default: '/api/chat')\n  headers: { Authorization: 'Bearer ...' }, // Extra headers (or a function returning them)\n  body: { model: 'claude-sonnet-4-20250514' },   // Extra body fields\n  streamTimeout: 60_000,                  // Close stream if no chunk arrives (ms, default: 60000)\n  reconnectTimeout: 1_000,               // Wait for retained message on reconnect (ms, default: 1000)\n});\n```\n\n### `publishStreamToMqtt` (server)\n\n```typescript\nimport { publishStreamToMqtt } from '@cloudsignal/ai-transport/server';\n\nawait publishStreamToMqtt(mqttClient, chatId, streamTextResult, {\n  requestId: 'req_abc123',   // Matches client request for chunk filtering\n  streamQos: 0,              // QoS for stream chunks (default: 0)\n  completeQos: 1,            // QoS for retained complete message (default: 1)\n});\n```\n\n## Security Best Practices\n\n### Credential isolation\n\n```\nBrowser only sees:  temporary MQTT username/password (60-min TTL)\nServer only sees:   CLOUDSIGNAL_SECRET_KEY, ANTHROPIC_API_KEY\nBroker enforces:    per-message ACL, mountpoint isolation, message size limits\n```\n\nThe organization's secret key (`sk_...`) never reaches the browser. The browser receives temporary credentials that expire and cannot be used to create new tokens.\n\n### Recommended ACL policy\n\n```json\n{\n  \"schema\": \"cloudsignal://acl/v2\",\n  \"default\": \"deny\",\n  \"global\": [\n    { \"action\": \"sub\", \"topic\": \"chat/+/stream\", \"retain\": false },\n    { \"action\": \"sub\", \"topic\": \"chat/+/complete\" }\n  ],\n  \"rules\": [\n    {\n      \"action\": \"pub\",\n      \"topic\": \"chat/{user_id}/messages\",\n      \"binding\": \"user_id\"\n    }\n  ],\n  \"publishers\": [\n    {\n      \"action\": \"pub\",\n      \"topic\": \"chat/#\",\n      \"retain\": true,\n      \"qos\": [0, 1]\n    }\n  ]\n}\n```\n\nThis policy:\n- **Default deny** — nothing is allowed unless explicitly permitted\n- **Global subscribe** — any authenticated user can subscribe to chat streams (but not retain)\n- **Identity-bound publish** — users can only publish to `chat/{their_user_id}/messages`\n- **Server publish** — service accounts can publish to any chat topic with retain (for offline recovery)\n- **No client retain** — clients cannot poison retained messages\n\n### Transport encryption\n\n- **Server → Broker**: MQTTS (TLS on port 8883) — native MQTT, no WebSocket overhead\n- **Browser → Broker**: WSS (TLS on port 18885) — MQTT over WebSocket Secure\n\n### Tenant isolation\n\nEach organization operates in its own broker-enforced namespace. Clients in different organizations cannot see each other's topics — this is a broker-level boundary, so a bug in your application code cannot bypass it.\n\n## Edge Case Handling\n\n| Scenario | Mitigation |\n|----------|-----------|\n| Server crashes mid-stream | Stream timeout closes the ReadableStream after configurable idle period |\n| HTTP POST returns error | Stream cleaned up immediately, error propagated to AI SDK |\n| Two rapid messages interleave | Request ID filtering — each stream ignores chunks from other requests |\n| Stale retained message from previous session | Chat ID validation on reconnectToStream |\n| Client disconnects mid-stream | Server continues, publishes retained complete message; client recovers on reconnect |\n| Subscription accumulation | Cleanup unsubscribes from stream topic on completion or abort |\n| Abort signal fired | Cleanup runs, stream closed, subscriptions removed |\n| Retained message never arrives | Configurable reconnect timeout (default 1s), resolves null |\n\n## Environment Variables\n\n```bash\n# Server-side (never exposed to browser)\nANTHROPIC_API_KEY=sk-ant-...\nCLOUDSIGNAL_SECRET_KEY=sk_...\nCLOUDSIGNAL_ORG_ID=your-org-uuid\nCLOUDSIGNAL_TOKEN_SERVICE_URL=https://auth.cloudsignal.app\nCLOUDSIGNAL_MQTTS_URL=mqtts://connect.cloudsignal.app:8883\n\n# Client-side (safe to expose)\nNEXT_PUBLIC_CLOUDSIGNAL_WSS_URL=wss://connect.cloudsignal.app:18885/\n```\n\n## Demo\n\nSee [cloudsignal/ai-chat](https://github.com/cloudsignal/ai-chat) — a complete Next.js 16 chat app using this transport.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}