@dropout-ai/runtime 0.3.11 → 0.4.1

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 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
- * **🔋 Auto-Discovery:** Automatically detects framework (Next.js, NestJS) and configures itself.
11
+ * **🔋 Robust:** Explicit initialization ensures you always know when it's running.
11
12
 
12
13
  ---
13
14
 
14
- ## 🚀 Quick Start (Recommended)
15
+ ## 🚀 Quick Start (Wizard)
15
16
 
16
- Run our initialization wizard in your project root. It will detect your framework and automatically create the necessary configuration files.
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/runtime init
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
- If you prefer to configure it yourself, install the package and follow the guide for your specific framework.
30
+ ### 1. Install the Package
30
31
 
31
32
  ```bash
32
33
  npm install @dropout-ai/runtime
33
34
  # or
34
- yarn add @dropout-ai/runtime
35
+ pnpm add @dropout-ai/runtime
35
36
 
36
37
  ```
37
38
 
38
- ### 1. Next.js (App Router)
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
- Next.js uses lazy-loading, so we use `instrumentation.ts` to ensure Dropout loads immediately on server boot.
45
+ #### For Next.js (App Router)
41
46
 
42
- **Create/Edit:** `src/instrumentation.ts` (or `instrumentation.ts` in root)
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
- console.log('✅ Dropout AI Monitoring Active');
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
- ### 2. Node.js / Express / Fastify
64
+ #### For Node.js / Express / Fastify
56
65
 
57
- Initialize Dropout at the **very top** of your entry file (`index.js` or `server.js`), before importing other libraries.
66
+ **File:** `index.js` or `server.js` (Top of file)
58
67
 
59
68
  ```javascript
60
- // MUST be the first line
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
- // ... rest of your code
80
+ // ...
66
81
 
67
82
  ```
68
83
 
69
- ### 3. NestJS
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 first - Sends "Boot Ping" immediately
82
- new Dropout({
83
- projectId: process.env.DROPOUT_PROJECT_ID,
84
- apiKey: process.env.DROPOUT_API_KEY
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
- ### 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_..."
108
+ ---
102
109
 
103
- # 2. Run your app with the runtime injected
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
- ## ⚙️ Configuration
121
+ ## Troubleshooting
111
122
 
112
- You can configure Dropout via **Environment Variables** (Recommended) or by passing options to the constructor.
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
- | 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 |
126
+ > `[Dropout] 🟢 Online | Project: <Your-Project-ID>`
120
127
 
121
- **Example `.env` file:**
128
+ **Q: I don't see any logs.**
122
129
 
123
- ```bash
124
- DROPOUT_PROJECT_ID="HomeOS"
125
- DROPOUT_API_KEY="dp_live_xyz123..."
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, Java, or Go, you can manually send interaction logs to our ingestion endpoint.
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
- **Headers:**
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", // or "user"
149
+ "turn_role": "assistant",
158
150
  "content": "AI response text...",
159
- "model": "gpt-4", // optional
160
- "provider": "openai", // optional
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.3.11",
4
- "description": "Invisible Node.js runtime for understanding behavoiral impact of AI interactions.",
3
+ "version": "0.4.1",
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
- "behavoiral analysis",
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.js CHANGED
@@ -17,7 +17,27 @@ const KNOWN_AI_DOMAINS = [
17
17
  ];
18
18
 
19
19
  class Dropout {
20
+ // Singleton Instance Storage
21
+ static instance = null;
22
+
23
+ /**
24
+ * Universal Initialization Method (Idempotent)
25
+ * Users call this explicitly in their code.
26
+ */
27
+ static init(config) {
28
+ if (!Dropout.instance) {
29
+ new Dropout(config);
30
+ }
31
+ return Dropout.instance;
32
+ }
33
+
20
34
  constructor(config = {}) {
35
+ // 🛡️ SINGLETON GUARD (Prevent multiple initializations)
36
+ if (Dropout.instance) {
37
+ if (config.debug) console.log("[Dropout] ℹ️ Already initialized. Returning existing instance.");
38
+ return Dropout.instance;
39
+ }
40
+
21
41
  // 🛡️ 1. BROWSER GUARD (Client-Side Protection)
22
42
  if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {
23
43
  if (config.debug) console.warn("[Dropout] ⚠️ Skipped: Browser detected. SDK is Server-Only.");
@@ -26,7 +46,9 @@ class Dropout {
26
46
 
27
47
  // 🛡️ 2. CREDENTIAL GUARD
28
48
  if (!config.apiKey || !config.projectId) {
29
- if (config.debug) console.warn("[Dropout] ⚠️ Skipped: Missing API Key or Project ID.");
49
+ if (config.debug) {
50
+ console.warn("\x1b[31m%s\x1b[0m", "[Dropout] 🔴 Initialization Failed: Missing API Key or Project ID.");
51
+ }
30
52
  return;
31
53
  }
32
54
 
@@ -56,9 +78,10 @@ class Dropout {
56
78
  this.lastPromptHash = null;
57
79
  this.lastResponseHash = null;
58
80
 
59
- // Singleton Guard
81
+ // Global Guard (Extra safety for HMR environments like Next.js)
60
82
  if (global.__dropout_initialized__) {
61
- if (this.debug) console.log("[Dropout] ℹ️ Already initialized.");
83
+ if (this.debug) console.log("[Dropout] ℹ️ Global flag found. Skipping re-initialization.");
84
+ Dropout.instance = this; // Re-bind if lost
62
85
  return;
63
86
  }
64
87
  global.__dropout_initialized__ = true;
@@ -68,7 +91,10 @@ class Dropout {
68
91
  global.__dropout_session_id__ = this.generateSessionId();
69
92
  }
70
93
 
71
- if (this.debug) console.log(`[Dropout] 🟢 Online: ${this.projectId}`);
94
+ // VISUAL SUCCESS INDICATOR
95
+ if (this.debug) {
96
+ console.log('\x1b[32m%s\x1b[0m', `[Dropout] 🟢 Online | Project: ${this.projectId}`);
97
+ }
72
98
 
73
99
  // Bindings
74
100
  this.log = this.log.bind(this);
@@ -77,10 +103,12 @@ class Dropout {
77
103
  // 4. Start Network Interceptor
78
104
  this.patchNetwork();
79
105
 
80
- // 5. SEND STARTUP PING (Always run this, silent by default)
81
- // This turns the dashboard status GREEN immediately on app boot.
106
+ // 5. SEND STARTUP PING
82
107
  this.sendStartupSignal();
83
108
 
109
+ // Lock the instance
110
+ Dropout.instance = this;
111
+
84
112
  } catch (err) {
85
113
  // THE ULTIMATE CATCH-ALL: Ensure app NEVER crashes
86
114
  if (config.debug) console.error("[Dropout] ❌ Initialization Error:", err);
@@ -108,7 +136,6 @@ class Dropout {
108
136
  turn_role: 'system',
109
137
  turn_index: 0,
110
138
  content: 'Dropout SDK Initialized',
111
- // content_blob: 'Dropout SDK Initialized',
112
139
  metadata_flags: {
113
140
  type: 'system_boot',
114
141
  environment: process.env.NODE_ENV || 'development',
@@ -185,7 +212,6 @@ class Dropout {
185
212
  model: payload.model,
186
213
  latency_ms: payload.latency_ms || null,
187
214
  content: payload.content,
188
- // content_blob: payload.content,
189
215
  content_hash: payload.content_hash,
190
216
  metadata_flags: payload.metadata_flags,
191
217
  received_at: new Date().toISOString()
@@ -409,9 +435,9 @@ class Dropout {
409
435
  }
410
436
  }
411
437
 
412
- // Auto-Start (Server-Side Only)
438
+ // Auto-Start (Backwards Compatibility & Environment Variable Support)
413
439
  if (typeof process !== 'undefined' && process.env.DROPOUT_PROJECT_ID && process.env.DROPOUT_API_KEY) {
414
- new Dropout({
440
+ Dropout.init({
415
441
  projectId: process.env.DROPOUT_PROJECT_ID,
416
442
  apiKey: process.env.DROPOUT_API_KEY,
417
443
  debug: process.env.DROPOUT_DEBUG === 'true'
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
- }
package/src/index.d.ts DELETED
@@ -1,33 +0,0 @@
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
- }