@dropout-ai/runtime 0.4.0 → 0.4.2
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 +68 -96
- package/package.json +6 -13
- package/src/index.d.ts +20 -15
- package/bin/init.js +0 -71
- package/src/autoload.js +0 -35
package/README.md
CHANGED
|
@@ -1,74 +1,87 @@
|
|
|
1
|
+
|
|
1
2
|
# 🕵️ Dropout AI Runtime (`@dropout-ai/runtime`)
|
|
2
3
|
|
|
3
4
|
**Universal AI Behavior Analysis & Capture for Node.js**
|
|
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
|
+
Dropout is a lightweight, "install-and-forget" runtime that automatically captures AI interactions (prompts & responses) from your application without requiring code changes to your API calls. It acts as a passive observer, patching the network layer to ensure you never miss a conversation.
|
|
6
7
|
|
|
7
8
|
* **🔌 Universal:** Works with OpenAI, Anthropic, Genkit, LangChain, Axios, and `fetch`.
|
|
8
9
|
* **🛡️ Safe:** Designed for production with silent failure modes and browser guards.
|
|
9
10
|
* **⚡ Zero-Latency:** Uses fire-and-forget logging to ensure your app stays fast.
|
|
10
|
-
* **🔋
|
|
11
|
+
* **🔋 Robust:** Explicit initialization ensures you always know when it's running.
|
|
11
12
|
|
|
12
13
|
---
|
|
13
14
|
|
|
14
|
-
## 🚀 Quick Start (
|
|
15
|
+
## 🚀 Quick Start (Wizard)
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
The easiest way to get started is to run our installer. It will install the package and give you the exact code snippet to copy.
|
|
17
18
|
|
|
18
19
|
```bash
|
|
19
|
-
npx @dropout-ai/
|
|
20
|
+
npx @dropout-ai/wizard@latest
|
|
20
21
|
|
|
21
22
|
```
|
|
22
23
|
|
|
23
|
-
*Supports: **Next.js** (App Router), **NestJS**, **Express**, and standard **Node.js** apps.*
|
|
24
|
-
|
|
25
24
|
---
|
|
26
25
|
|
|
27
|
-
## 🛠️ Manual Installation
|
|
26
|
+
## 🛠️ Manual Installation & Usage
|
|
27
|
+
|
|
28
|
+
If you prefer to install manually, follow these two steps.
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
### 1. Install the Package
|
|
30
31
|
|
|
31
32
|
```bash
|
|
32
33
|
npm install @dropout-ai/runtime
|
|
33
34
|
# or
|
|
34
|
-
|
|
35
|
+
pnpm add @dropout-ai/runtime
|
|
35
36
|
|
|
36
37
|
```
|
|
37
38
|
|
|
38
|
-
###
|
|
39
|
+
### 2. Initialize (The "Universal" Method)
|
|
40
|
+
|
|
41
|
+
To start capturing, you must explicitly initialize Dropout. Place this code snippet **as early as possible** in your application lifecycle (before you make any AI calls).
|
|
42
|
+
|
|
43
|
+
It is safe to call `init()` multiple times; it will only run once.
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
#### ➤ For Next.js (App Router)
|
|
41
46
|
|
|
42
|
-
**
|
|
47
|
+
**File:** `src/instrumentation.ts` (or `instrumentation.ts` in root)
|
|
43
48
|
|
|
44
49
|
```typescript
|
|
45
50
|
export async function register() {
|
|
46
|
-
// Ensure we only run on the Node.js server runtime
|
|
47
51
|
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
48
|
-
await import('@dropout-ai/runtime');
|
|
49
|
-
|
|
52
|
+
const { default: Dropout } = await import('@dropout-ai/runtime');
|
|
53
|
+
|
|
54
|
+
Dropout.init({
|
|
55
|
+
apiKey: process.env.DROPOUT_API_KEY,
|
|
56
|
+
projectId: process.env.DROPOUT_PROJECT_ID,
|
|
57
|
+
debug: true // Set to false in production
|
|
58
|
+
});
|
|
50
59
|
}
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
```
|
|
54
63
|
|
|
55
|
-
|
|
64
|
+
#### ➤ For Node.js / Express / Fastify
|
|
56
65
|
|
|
57
|
-
|
|
66
|
+
**File:** `index.js` or `server.js` (Top of file)
|
|
58
67
|
|
|
59
68
|
```javascript
|
|
60
|
-
//
|
|
61
|
-
require('@dropout-ai/runtime');
|
|
69
|
+
require('dotenv').config(); // Ensure env vars are loaded first
|
|
70
|
+
const Dropout = require('@dropout-ai/runtime');
|
|
71
|
+
|
|
72
|
+
Dropout.init({
|
|
73
|
+
apiKey: process.env.DROPOUT_API_KEY,
|
|
74
|
+
projectId: process.env.DROPOUT_PROJECT_ID,
|
|
75
|
+
debug: process.env.NODE_ENV !== 'production'
|
|
76
|
+
});
|
|
62
77
|
|
|
63
78
|
const express = require('express');
|
|
64
79
|
const app = express();
|
|
65
|
-
// ...
|
|
80
|
+
// ...
|
|
66
81
|
|
|
67
82
|
```
|
|
68
83
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Initialize Dropout inside your `bootstrap()` function before creating the Nest app.
|
|
84
|
+
#### ➤ For NestJS
|
|
72
85
|
|
|
73
86
|
**File:** `src/main.ts`
|
|
74
87
|
|
|
@@ -78,10 +91,11 @@ import { AppModule } from './app.module';
|
|
|
78
91
|
import Dropout from '@dropout-ai/runtime';
|
|
79
92
|
|
|
80
93
|
async function bootstrap() {
|
|
81
|
-
// ✅ Initialize
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
94
|
+
// ✅ Initialize before the app starts
|
|
95
|
+
Dropout.init({
|
|
96
|
+
apiKey: process.env.DROPOUT_API_KEY,
|
|
97
|
+
projectId: process.env.DROPOUT_PROJECT_ID,
|
|
98
|
+
debug: true
|
|
85
99
|
});
|
|
86
100
|
|
|
87
101
|
const app = await NestFactory.create(AppModule);
|
|
@@ -91,96 +105,54 @@ bootstrap();
|
|
|
91
105
|
|
|
92
106
|
```
|
|
93
107
|
|
|
94
|
-
|
|
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_..."
|
|
108
|
+
---
|
|
102
109
|
|
|
103
|
-
|
|
104
|
-
node -r @dropout-ai/runtime dist/index.js
|
|
110
|
+
## ⚙️ Configuration
|
|
105
111
|
|
|
106
|
-
|
|
112
|
+
| Option | Type | Description | Required |
|
|
113
|
+
| --- | --- | --- | --- |
|
|
114
|
+
| `projectId` | `string` | Your Project ID from the dashboard. | ✅ |
|
|
115
|
+
| `apiKey` | `string` | Your Secret Key (`dp_live_...`). | ✅ |
|
|
116
|
+
| `debug` | `boolean` | Set `true` to see "🟢 Online" logs and errors in console. | No |
|
|
117
|
+
| `privacy` | `string` | `full` (capture text) or `mask` (metadata only). Default: `full`. | No |
|
|
107
118
|
|
|
108
119
|
---
|
|
109
120
|
|
|
110
|
-
##
|
|
121
|
+
## ❓ Troubleshooting
|
|
111
122
|
|
|
112
|
-
|
|
123
|
+
**Q: How do I know if it's working?**
|
|
124
|
+
Set `debug: true` in your config. When your app starts, you should see this message immediately:
|
|
113
125
|
|
|
114
|
-
|
|
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 |
|
|
126
|
+
> `[Dropout] 🟢 Online | Project: <Your-Project-ID>`
|
|
120
127
|
|
|
121
|
-
**
|
|
128
|
+
**Q: I don't see any logs.**
|
|
122
129
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
DROPOUT_DEBUG="true"
|
|
130
|
+
1. Check that you called `Dropout.init()`.
|
|
131
|
+
2. Ensure your `apiKey` and `projectId` are not undefined (log them to check).
|
|
132
|
+
3. If using Next.js, ensure `instrumentation.ts` is in the correct folder (`src/` if you use it).
|
|
127
133
|
|
|
128
|
-
|
|
134
|
+
**Q: Does this work with Edge Functions?**
|
|
135
|
+
No. This runtime relies on Node.js core modules (`http`, `https`). It does not support Vercel Edge Runtime or Cloudflare Workers.
|
|
129
136
|
|
|
130
137
|
---
|
|
131
138
|
|
|
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
139
|
### Non-Node.js Usage (REST API)
|
|
142
140
|
|
|
143
|
-
If you are using Python,
|
|
141
|
+
If you are using Python, Go, or other languages, you can manually send interaction logs to our ingestion endpoint.
|
|
144
142
|
|
|
145
143
|
**Endpoint:** `POST https://hipughmjlwmwjxzyxfzs.supabase.co/functions/v1/capture-sealed`
|
|
144
|
+
**Headers:** `x-dropout-key: <YOUR_API_KEY>`
|
|
146
145
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
* `Content-Type: application/json`
|
|
150
|
-
* `x-dropout-key: YOUR_API_KEY`
|
|
151
|
-
|
|
152
|
-
**Payload:**
|
|
153
|
-
|
|
154
|
-
```json
|
|
146
|
+
json
|
|
155
147
|
{
|
|
156
148
|
"project_id": "your_project_id",
|
|
157
|
-
"turn_role": "assistant",
|
|
149
|
+
"turn_role": "assistant",
|
|
158
150
|
"content": "AI response text...",
|
|
159
|
-
"model": "gpt-4",
|
|
160
|
-
"provider": "openai"
|
|
161
|
-
"latency_ms": 1250 // optional
|
|
151
|
+
"model": "gpt-4",
|
|
152
|
+
"provider": "openai"
|
|
162
153
|
}
|
|
163
154
|
|
|
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
|
-
---
|
|
183
|
-
|
|
184
155
|
### License
|
|
185
156
|
|
|
186
|
-
MIT
|
|
157
|
+
MIT
|
|
158
|
+
|
package/package.json
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dropout-ai/runtime",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"description": "Invisible Node.js runtime for understanding
|
|
3
|
+
"version": "0.4.2",
|
|
4
|
+
"description": "Invisible Node.js runtime for understanding behavioral impact of AI interactions.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
7
|
-
"bin": {
|
|
8
|
-
"init": "./bin/init.js"
|
|
9
|
-
},
|
|
10
7
|
"scripts": {
|
|
11
8
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
9
|
},
|
|
@@ -17,7 +14,7 @@
|
|
|
17
14
|
"invisible",
|
|
18
15
|
"observability",
|
|
19
16
|
"ai",
|
|
20
|
-
"
|
|
17
|
+
"behavioral analysis",
|
|
21
18
|
"ai forensic",
|
|
22
19
|
"llm",
|
|
23
20
|
"monitoring",
|
|
@@ -30,16 +27,12 @@
|
|
|
30
27
|
"url": "git+https://github.com/vaibhavv4re/dropout.git",
|
|
31
28
|
"directory": "packages/runtime"
|
|
32
29
|
},
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"dotenv": "^16.4.5"
|
|
35
|
-
},
|
|
30
|
+
"dependencies": {},
|
|
36
31
|
"exports": {
|
|
37
|
-
".": "./src/index.js"
|
|
38
|
-
"./register": "./src/autoload.js"
|
|
32
|
+
".": "./src/index.js"
|
|
39
33
|
},
|
|
40
34
|
"files": [
|
|
41
|
-
"src"
|
|
42
|
-
"bin"
|
|
35
|
+
"src"
|
|
43
36
|
],
|
|
44
37
|
"publishConfig": {
|
|
45
38
|
"access": "public"
|
package/src/index.d.ts
CHANGED
|
@@ -1,33 +1,38 @@
|
|
|
1
|
+
// packages/runtime/src/index.d.ts
|
|
2
|
+
|
|
1
3
|
export interface DropoutConfig {
|
|
4
|
+
projectId: string;
|
|
5
|
+
apiKey: string;
|
|
6
|
+
debug?: boolean;
|
|
7
|
+
privacy?: 'full' | 'mask';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default class Dropout {
|
|
2
11
|
/**
|
|
3
|
-
*
|
|
12
|
+
* The project ID associated with this instance.
|
|
4
13
|
*/
|
|
5
14
|
projectId: string;
|
|
6
15
|
|
|
7
16
|
/**
|
|
8
|
-
*
|
|
17
|
+
* The API Key used for authentication.
|
|
9
18
|
*/
|
|
10
19
|
apiKey: string;
|
|
11
20
|
|
|
12
21
|
/**
|
|
13
|
-
*
|
|
14
|
-
* 'full' - Captures prompts and responses (Default).
|
|
15
|
-
* 'mask' - Captures metadata only, redacts text.
|
|
22
|
+
* Enable debug mode for verbose logging.
|
|
16
23
|
*/
|
|
17
|
-
|
|
24
|
+
debug: boolean;
|
|
18
25
|
|
|
19
26
|
/**
|
|
20
|
-
*
|
|
21
|
-
* Default: false
|
|
27
|
+
* Privacy setting ('full' captures text, 'mask' captures metadata only).
|
|
22
28
|
*/
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default class Dropout {
|
|
27
|
-
constructor(config: DropoutConfig);
|
|
29
|
+
privacy: 'full' | 'mask';
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
|
-
*
|
|
32
|
+
* Universal Initialization Method (Idempotent).
|
|
33
|
+
* Safe to call multiple times; will only initialize once.
|
|
31
34
|
*/
|
|
32
|
-
|
|
35
|
+
static init(config: DropoutConfig): Dropout;
|
|
36
|
+
|
|
37
|
+
constructor(config: DropoutConfig);
|
|
33
38
|
}
|
package/bin/init.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
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/src/autoload.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// packages/runtime/src/autoload.js
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const Dropout = require('./index');
|
|
5
|
-
|
|
6
|
-
// 1. Force Load Environment Variables (Fixes the "undefined" error)
|
|
7
|
-
try {
|
|
8
|
-
const dotenv = require('dotenv');
|
|
9
|
-
const cwd = process.cwd();
|
|
10
|
-
|
|
11
|
-
// We explicitly look for .env.local first (Next.js standard), then .env
|
|
12
|
-
const envFiles = ['.env.local', '.env'];
|
|
13
|
-
|
|
14
|
-
envFiles.forEach(file => {
|
|
15
|
-
const envPath = path.resolve(cwd, file);
|
|
16
|
-
if (fs.existsSync(envPath)) {
|
|
17
|
-
dotenv.config({ path: envPath, override: true });
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
} catch (e) {
|
|
21
|
-
// dotenv might not be installed, ignore if using system env vars
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// 2. Initialize Immediately
|
|
25
|
-
if (process.env.DROPOUT_PROJECT_ID && process.env.DROPOUT_API_KEY) {
|
|
26
|
-
new Dropout({
|
|
27
|
-
projectId: process.env.DROPOUT_PROJECT_ID,
|
|
28
|
-
apiKey: process.env.DROPOUT_API_KEY,
|
|
29
|
-
debug: process.env.DROPOUT_DEBUG === 'true'
|
|
30
|
-
});
|
|
31
|
-
// Log strictly for debug verification
|
|
32
|
-
if (process.env.DROPOUT_DEBUG === 'true') {
|
|
33
|
-
console.log(`[Dropout] 🚀 Global Autoload Active: ${process.env.DROPOUT_PROJECT_ID}`);
|
|
34
|
-
}
|
|
35
|
-
}
|