@dropout-ai/runtime 0.3.8 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +170 -20
- package/bin/init.js +71 -0
- package/package.json +19 -5
- package/src/index.d.ts +33 -0
- package/src/index.js +27 -31
package/README.md
CHANGED
|
@@ -1,36 +1,186 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 🕵️ Dropout AI Runtime (`@dropout-ai/runtime`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Universal AI Behavior Analysis & Capture for Node.js**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Dropout is a lightweight, "install-and-forget" runtime that automatically captures AI interactions (prompts & responses) from your application without requiring code changes. It acts as a passive observer, patching the network layer to ensure you never miss a conversation.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
* **🔌 Universal:** Works with OpenAI, Anthropic, Genkit, LangChain, Axios, and `fetch`.
|
|
8
|
+
* **🛡️ Safe:** Designed for production with silent failure modes and browser guards.
|
|
9
|
+
* **⚡ Zero-Latency:** Uses fire-and-forget logging to ensure your app stays fast.
|
|
10
|
+
* **🔋 Auto-Discovery:** Automatically detects framework (Next.js, NestJS) and configures itself.
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 🚀 Quick Start (Recommended)
|
|
15
|
+
|
|
16
|
+
Run our initialization wizard in your project root. It will detect your framework and automatically create the necessary configuration files.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx @dropout-ai/runtime init
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
*Supports: **Next.js** (App Router), **NestJS**, **Express**, and standard **Node.js** apps.*
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🛠️ Manual Installation
|
|
28
|
+
|
|
29
|
+
If you prefer to configure it yourself, install the package and follow the guide for your specific framework.
|
|
10
30
|
|
|
11
31
|
```bash
|
|
12
32
|
npm install @dropout-ai/runtime
|
|
33
|
+
# or
|
|
34
|
+
yarn add @dropout-ai/runtime
|
|
35
|
+
|
|
13
36
|
```
|
|
14
37
|
|
|
15
|
-
|
|
38
|
+
### 1. Next.js (App Router)
|
|
39
|
+
|
|
40
|
+
Next.js uses lazy-loading, so we use `instrumentation.ts` to ensure Dropout loads immediately on server boot.
|
|
41
|
+
|
|
42
|
+
**Create/Edit:** `src/instrumentation.ts` (or `instrumentation.ts` in root)
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
export async function register() {
|
|
46
|
+
// Ensure we only run on the Node.js server runtime
|
|
47
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
48
|
+
await import('@dropout-ai/runtime');
|
|
49
|
+
console.log('✅ Dropout AI Monitoring Active');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
```
|
|
16
54
|
|
|
17
|
-
|
|
55
|
+
### 2. Node.js / Express / Fastify
|
|
56
|
+
|
|
57
|
+
Initialize Dropout at the **very top** of your entry file (`index.js` or `server.js`), before importing other libraries.
|
|
18
58
|
|
|
19
59
|
```javascript
|
|
20
|
-
|
|
60
|
+
// MUST be the first line
|
|
61
|
+
require('@dropout-ai/runtime');
|
|
62
|
+
|
|
63
|
+
const express = require('express');
|
|
64
|
+
const app = express();
|
|
65
|
+
// ... rest of your code
|
|
66
|
+
|
|
21
67
|
```
|
|
22
68
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
69
|
+
### 3. NestJS
|
|
70
|
+
|
|
71
|
+
Initialize Dropout inside your `bootstrap()` function before creating the Nest app.
|
|
72
|
+
|
|
73
|
+
**File:** `src/main.ts`
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { NestFactory } from '@nestjs/core';
|
|
77
|
+
import { AppModule } from './app.module';
|
|
78
|
+
import Dropout from '@dropout-ai/runtime';
|
|
79
|
+
|
|
80
|
+
async function bootstrap() {
|
|
81
|
+
// ✅ Initialize first - Sends "Boot Ping" immediately
|
|
82
|
+
new Dropout({
|
|
83
|
+
projectId: process.env.DROPOUT_PROJECT_ID,
|
|
84
|
+
apiKey: process.env.DROPOUT_API_KEY
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const app = await NestFactory.create(AppModule);
|
|
88
|
+
await app.listen(3000);
|
|
89
|
+
}
|
|
90
|
+
bootstrap();
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 4. Docker / Zero-Code Injection
|
|
95
|
+
|
|
96
|
+
You can inject Dropout into any Node.js application without editing a single file by using the Node `--require` flag. This is perfect for Docker containers or PaaS deployments.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# 1. Set credentials
|
|
100
|
+
export DROPOUT_PROJECT_ID="your_project_id"
|
|
101
|
+
export DROPOUT_API_KEY="dp_live_..."
|
|
102
|
+
|
|
103
|
+
# 2. Run your app with the runtime injected
|
|
104
|
+
node -r @dropout-ai/runtime dist/index.js
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## ⚙️ Configuration
|
|
111
|
+
|
|
112
|
+
You can configure Dropout via **Environment Variables** (Recommended) or by passing options to the constructor.
|
|
113
|
+
|
|
114
|
+
| Environment Variable | Config Option | Description | Required |
|
|
115
|
+
| --- | --- | --- | --- |
|
|
116
|
+
| `DROPOUT_PROJECT_ID` | `projectId` | Your Project ID from dashboard. | ✅ |
|
|
117
|
+
| `DROPOUT_API_KEY` | `apiKey` | Your Secret Key (`dp_live_...`). | ✅ |
|
|
118
|
+
| `DROPOUT_DEBUG` | `debug` | Set `true` to see logs in console and enable connectivity checks. | No |
|
|
119
|
+
| `DROPOUT_PRIVACY` | `privacy` | `full` (capture text) or `mask` (metadata only). | No |
|
|
120
|
+
|
|
121
|
+
**Example `.env` file:**
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
DROPOUT_PROJECT_ID="HomeOS"
|
|
125
|
+
DROPOUT_API_KEY="dp_live_xyz123..."
|
|
126
|
+
DROPOUT_DEBUG="true"
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 🌐 Supported Environments
|
|
133
|
+
|
|
134
|
+
| Language/Framework | Status | Integration Method |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| **Node.js** (v18+) | ✅ Ready | `require('@dropout-ai/runtime')` |
|
|
137
|
+
| **Next.js** | ✅ Ready | `instrumentation.ts` |
|
|
138
|
+
| **NestJS** | ✅ Ready | `main.ts` import |
|
|
139
|
+
| **Python / Java / Go** | 🚧 Beta | Use REST API (see below) |
|
|
140
|
+
|
|
141
|
+
### Non-Node.js Usage (REST API)
|
|
142
|
+
|
|
143
|
+
If you are using Python, Java, or Go, you can manually send interaction logs to our ingestion endpoint.
|
|
144
|
+
|
|
145
|
+
**Endpoint:** `POST https://hipughmjlwmwjxzyxfzs.supabase.co/functions/v1/capture-sealed`
|
|
146
|
+
|
|
147
|
+
**Headers:**
|
|
148
|
+
|
|
149
|
+
* `Content-Type: application/json`
|
|
150
|
+
* `x-dropout-key: YOUR_API_KEY`
|
|
151
|
+
|
|
152
|
+
**Payload:**
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"project_id": "your_project_id",
|
|
157
|
+
"turn_role": "assistant", // or "user"
|
|
158
|
+
"content": "AI response text...",
|
|
159
|
+
"model": "gpt-4", // optional
|
|
160
|
+
"provider": "openai", // optional
|
|
161
|
+
"latency_ms": 1250 // optional
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## ❓ Troubleshooting
|
|
169
|
+
|
|
170
|
+
**Q: I don't see any logs in the dashboard.**
|
|
171
|
+
|
|
172
|
+
1. Ensure `DROPOUT_DEBUG="true"` is set.
|
|
173
|
+
2. Check your console for `[Dropout] 🟢 Online: <ProjectID>`.
|
|
174
|
+
3. If using Next.js, ensure you created `instrumentation.ts` in the correct folder (root or `src`).
|
|
175
|
+
|
|
176
|
+
**Q: Does this work with Edge Functions (Vercel Edge / Cloudflare)?**
|
|
177
|
+
No. This runtime relies on Node.js core modules (`http`, `https`) to capture traffic. It does not currently support Vercel Edge Runtime or Cloudflare Workers. Please ensure your API routes use the Node.js runtime.
|
|
178
|
+
|
|
179
|
+
**Q: Will this crash my app if the API is down?**
|
|
180
|
+
No. The SDK is built with a "Safety Fuse." If it cannot connect or encounters an error, it fails silently and your application continues running without interruption.
|
|
181
|
+
|
|
182
|
+
---
|
|
28
183
|
|
|
29
|
-
|
|
30
|
-
- **Zero Configuration**: Just import and it works.
|
|
31
|
-
- **Invisible capture**: No code changes to your AI logic.
|
|
32
|
-
- **Non-blocking**: Uses fire-and-forget network calls.
|
|
33
|
-
- **Remote Config**: Supports dynamic output capping and provider filtering.
|
|
184
|
+
### License
|
|
34
185
|
|
|
35
|
-
|
|
36
|
-
MIT
|
|
186
|
+
MIT
|
package/bin/init.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const colors = {
|
|
6
|
+
reset: "\x1b[0m",
|
|
7
|
+
green: "\x1b[32m",
|
|
8
|
+
yellow: "\x1b[33m",
|
|
9
|
+
cyan: "\x1b[36m"
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const log = (color, msg) => console.log(`${color}${msg}${colors.reset}`);
|
|
13
|
+
|
|
14
|
+
function detectFramework() {
|
|
15
|
+
const cwd = process.cwd();
|
|
16
|
+
if (fs.existsSync(path.resolve(cwd, 'package.json'))) {
|
|
17
|
+
const pkg = JSON.parse(fs.readFileSync(path.resolve(cwd, 'package.json'), 'utf-8'));
|
|
18
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
19
|
+
if (deps.next) return 'nextjs';
|
|
20
|
+
if (deps['@nestjs/core']) return 'nestjs';
|
|
21
|
+
return 'node';
|
|
22
|
+
}
|
|
23
|
+
return 'unknown';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function setupNextJs() {
|
|
27
|
+
log(colors.cyan, '🔍 Next.js project detected.');
|
|
28
|
+
const hasSrc = fs.existsSync(path.resolve(process.cwd(), 'src'));
|
|
29
|
+
const targetDir = hasSrc ? 'src' : '.';
|
|
30
|
+
const isTs = fs.existsSync(path.resolve(process.cwd(), 'tsconfig.json'));
|
|
31
|
+
const ext = isTs ? 'ts' : 'js';
|
|
32
|
+
const filePath = path.resolve(process.cwd(), targetDir, `instrumentation.${ext}`);
|
|
33
|
+
|
|
34
|
+
const content = `export async function register() {
|
|
35
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
36
|
+
await import('@dropout-ai/runtime');
|
|
37
|
+
console.log('[Dropout] 🟢 Initialized via instrumentation hook');
|
|
38
|
+
}
|
|
39
|
+
}`;
|
|
40
|
+
|
|
41
|
+
if (fs.existsSync(filePath)) {
|
|
42
|
+
log(colors.yellow, `⚠️ File exists: ${filePath}`);
|
|
43
|
+
log(colors.yellow, `👉 Please add the register() hook manually.`);
|
|
44
|
+
} else {
|
|
45
|
+
fs.writeFileSync(filePath, content);
|
|
46
|
+
log(colors.green, `✅ Created: ${targetDir}/instrumentation.${ext}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
log(colors.cyan, '\nNEXT STEP: Add .env keys (DROPOUT_PROJECT_ID, DROPOUT_API_KEY).');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function run() {
|
|
53
|
+
console.log(colors.cyan + "\nDropout AI - Init Wizard 🧙♂️" + colors.reset);
|
|
54
|
+
const framework = detectFramework();
|
|
55
|
+
|
|
56
|
+
switch (framework) {
|
|
57
|
+
case 'nextjs': setupNextJs(); break;
|
|
58
|
+
case 'nestjs':
|
|
59
|
+
log(colors.cyan, '🔍 NestJS detected.');
|
|
60
|
+
log(colors.green, '👉 Initialize in src/main.ts before bootstrap().');
|
|
61
|
+
break;
|
|
62
|
+
case 'node':
|
|
63
|
+
log(colors.cyan, '🔍 Node/Express detected.');
|
|
64
|
+
log(colors.green, '👉 Add require("@dropout-ai/runtime") at the top of index.js.');
|
|
65
|
+
break;
|
|
66
|
+
default:
|
|
67
|
+
log(colors.yellow, '⚠️ Unknown framework. Check docs for manual setup.');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
run();
|
package/package.json
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dropout-ai/runtime",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Invisible Node.js runtime for
|
|
3
|
+
"version": "0.3.10",
|
|
4
|
+
"description": "Invisible Node.js runtime for understanding behavoiral impact of AI interactions.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"init": "./bin/init.js"
|
|
9
|
+
},
|
|
6
10
|
"scripts": {
|
|
7
|
-
"test": "
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
12
|
},
|
|
9
13
|
"keywords": [
|
|
10
14
|
"openai",
|
|
11
15
|
"telemetry",
|
|
12
16
|
"runtime",
|
|
13
|
-
"invisible"
|
|
17
|
+
"invisible",
|
|
18
|
+
"observability",
|
|
19
|
+
"ai",
|
|
20
|
+
"behavoiral analysis",
|
|
21
|
+
"ai forensic",
|
|
22
|
+
"llm",
|
|
23
|
+
"monitoring",
|
|
24
|
+
"genkit",
|
|
25
|
+
"nestjs",
|
|
26
|
+
"nextjs"
|
|
14
27
|
],
|
|
15
28
|
"repository": {
|
|
16
29
|
"type": "git",
|
|
@@ -18,7 +31,8 @@
|
|
|
18
31
|
"directory": "packages/runtime"
|
|
19
32
|
},
|
|
20
33
|
"files": [
|
|
21
|
-
"src"
|
|
34
|
+
"src",
|
|
35
|
+
"bin"
|
|
22
36
|
],
|
|
23
37
|
"publishConfig": {
|
|
24
38
|
"access": "public"
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface DropoutConfig {
|
|
2
|
+
/**
|
|
3
|
+
* Your project ID from the Dropout Dashboard.
|
|
4
|
+
*/
|
|
5
|
+
projectId: string;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Your secret API Key (starts with dp_live_...).
|
|
9
|
+
*/
|
|
10
|
+
apiKey: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Data Privacy Level.
|
|
14
|
+
* 'full' - Captures prompts and responses (Default).
|
|
15
|
+
* 'mask' - Captures metadata only, redacts text.
|
|
16
|
+
*/
|
|
17
|
+
privacy?: 'full' | 'mask';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Enable verbose logging for connection debugging.
|
|
21
|
+
* Default: false
|
|
22
|
+
*/
|
|
23
|
+
debug?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default class Dropout {
|
|
27
|
+
constructor(config: DropoutConfig);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Manually log a message to the debug stream.
|
|
31
|
+
*/
|
|
32
|
+
log(msg: string, ...args: any[]): void;
|
|
33
|
+
}
|
package/src/index.js
CHANGED
|
@@ -19,13 +19,12 @@ const KNOWN_AI_DOMAINS = [
|
|
|
19
19
|
class Dropout {
|
|
20
20
|
constructor(config = {}) {
|
|
21
21
|
// 🛡️ 1. BROWSER GUARD (Client-Side Protection)
|
|
22
|
-
// If this accidentally runs in a browser/Client Component, we abort silently.
|
|
23
22
|
if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {
|
|
24
23
|
if (config.debug) console.warn("[Dropout] ⚠️ Skipped: Browser detected. SDK is Server-Only.");
|
|
25
24
|
return;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
// 🛡️ 2. CREDENTIAL
|
|
27
|
+
// 🛡️ 2. CREDENTIAL GUARD
|
|
29
28
|
if (!config.apiKey || !config.projectId) {
|
|
30
29
|
if (config.debug) console.warn("[Dropout] ⚠️ Skipped: Missing API Key or Project ID.");
|
|
31
30
|
return;
|
|
@@ -69,18 +68,18 @@ class Dropout {
|
|
|
69
68
|
global.__dropout_session_id__ = this.generateSessionId();
|
|
70
69
|
}
|
|
71
70
|
|
|
71
|
+
if (this.debug) console.log(`[Dropout] 🟢 Online: ${this.projectId}`);
|
|
72
|
+
|
|
72
73
|
// Bindings
|
|
73
74
|
this.log = this.log.bind(this);
|
|
74
75
|
this.emit = this.emit.bind(this);
|
|
75
76
|
|
|
76
|
-
//
|
|
77
|
+
// 4. Start Network Interceptor
|
|
77
78
|
this.patchNetwork();
|
|
78
79
|
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
this.validateConnection();
|
|
83
|
-
}
|
|
80
|
+
// 5. SEND STARTUP PING (Always run this, silent by default)
|
|
81
|
+
// This turns the dashboard status GREEN immediately on app boot.
|
|
82
|
+
this.sendStartupSignal();
|
|
84
83
|
|
|
85
84
|
} catch (err) {
|
|
86
85
|
// THE ULTIMATE CATCH-ALL: Ensure app NEVER crashes
|
|
@@ -101,9 +100,22 @@ class Dropout {
|
|
|
101
100
|
}
|
|
102
101
|
}
|
|
103
102
|
|
|
104
|
-
// ---
|
|
105
|
-
|
|
106
|
-
|
|
103
|
+
// --- HEARTBEAT ---
|
|
104
|
+
sendStartupSignal() {
|
|
105
|
+
const payload = JSON.stringify({
|
|
106
|
+
project_id: this.projectId,
|
|
107
|
+
session_id: 'system_boot_' + Date.now(),
|
|
108
|
+
turn_role: 'system',
|
|
109
|
+
turn_index: 0,
|
|
110
|
+
content: 'Dropout SDK Initialized',
|
|
111
|
+
// content_blob: 'Dropout SDK Initialized',
|
|
112
|
+
metadata_flags: {
|
|
113
|
+
type: 'system_boot',
|
|
114
|
+
environment: process.env.NODE_ENV || 'development',
|
|
115
|
+
runtime: 'node'
|
|
116
|
+
},
|
|
117
|
+
received_at: new Date().toISOString()
|
|
118
|
+
});
|
|
107
119
|
|
|
108
120
|
const req = https.request(this.captureEndpoint, {
|
|
109
121
|
method: 'POST',
|
|
@@ -111,26 +123,10 @@ class Dropout {
|
|
|
111
123
|
'Content-Type': 'application/json',
|
|
112
124
|
'x-dropout-key': this.apiKey
|
|
113
125
|
}
|
|
114
|
-
}, (res) => {
|
|
115
|
-
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
116
|
-
console.log(`[Dropout] ✅ Connected to Project: ${this.projectId}`);
|
|
117
|
-
} else {
|
|
118
|
-
console.warn(`[Dropout] ⚠️ Connection Failed (Status: ${res.statusCode}). Check your API Key.`);
|
|
119
|
-
}
|
|
120
126
|
});
|
|
121
127
|
|
|
122
|
-
req.on('error', (e) =>
|
|
123
|
-
|
|
124
|
-
// Send lightweight Ping payload
|
|
125
|
-
req.write(JSON.stringify({
|
|
126
|
-
project_id: this.projectId,
|
|
127
|
-
session_id: 'system_ping',
|
|
128
|
-
turn_role: 'system',
|
|
129
|
-
turn_index: 0,
|
|
130
|
-
content: 'ping',
|
|
131
|
-
//content_blob: 'ping',
|
|
132
|
-
metadata_flags: { type: 'connectivity_check' }
|
|
133
|
-
}));
|
|
128
|
+
req.on('error', (e) => this.log("❌ Startup Signal Failed", e.message));
|
|
129
|
+
req.write(payload);
|
|
134
130
|
req.end();
|
|
135
131
|
}
|
|
136
132
|
|
|
@@ -160,7 +156,7 @@ class Dropout {
|
|
|
160
156
|
if (parsed.model) model = parsed.model;
|
|
161
157
|
if (provider === 'custom' && (parsed.messages || parsed.prompt)) provider = 'heuristic';
|
|
162
158
|
}
|
|
163
|
-
} catch (e) {
|
|
159
|
+
} catch (e) { }
|
|
164
160
|
return { provider, model };
|
|
165
161
|
}
|
|
166
162
|
|
|
@@ -189,7 +185,7 @@ class Dropout {
|
|
|
189
185
|
model: payload.model,
|
|
190
186
|
latency_ms: payload.latency_ms || null,
|
|
191
187
|
content: payload.content,
|
|
192
|
-
//content_blob: payload.content,
|
|
188
|
+
// content_blob: payload.content,
|
|
193
189
|
content_hash: payload.content_hash,
|
|
194
190
|
metadata_flags: payload.metadata_flags,
|
|
195
191
|
received_at: new Date().toISOString()
|