devfortress-sdk 4.2.0

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/dist/client.js ADDED
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /**
3
+ * DevFortress API Client
4
+ * Core client for sending events to DevFortress surveillance API
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.DevFortressClient = void 0;
11
+ const axios_1 = __importDefault(require("axios"));
12
+ const DEFAULT_ENDPOINT = 'https://www.devfortress.net/api/events/ingest';
13
+ const DEFAULT_TIMEOUT = 5000;
14
+ const DEFAULT_RETRIES = 3;
15
+ class DevFortressClient {
16
+ constructor(options) {
17
+ if (!options.apiKey) {
18
+ throw new Error('DevFortressClient: apiKey is required');
19
+ }
20
+ this.apiKey = options.apiKey;
21
+ this.endpoint = options.endpoint || DEFAULT_ENDPOINT;
22
+ this.timeout = options.timeout || DEFAULT_TIMEOUT;
23
+ this.retries = options.retries || DEFAULT_RETRIES;
24
+ this.debug = options.debug || false;
25
+ // Warn if endpoint is not HTTPS
26
+ if (this.endpoint.startsWith('http://') &&
27
+ !this.endpoint.includes('localhost') &&
28
+ !this.endpoint.includes('127.0.0.1')) {
29
+ // eslint-disable-next-line no-console
30
+ console.warn('[DevFortress] WARNING: Using non-HTTPS endpoint. API key will be transmitted in cleartext.');
31
+ }
32
+ this.axios = axios_1.default.create({
33
+ baseURL: this.endpoint,
34
+ timeout: this.timeout,
35
+ headers: {
36
+ 'Content-Type': 'application/json',
37
+ 'X-DevFortress-Key': this.apiKey,
38
+ },
39
+ });
40
+ }
41
+ /**
42
+ * Track a security event
43
+ */
44
+ async trackEvent(event) {
45
+ try {
46
+ // Add timestamp if not provided
47
+ const payload = {
48
+ ...event,
49
+ timestamp: event.timestamp || new Date().toISOString(),
50
+ };
51
+ const response = await this.sendWithRetry(payload);
52
+ return response.data;
53
+ }
54
+ catch (error) {
55
+ throw new Error(`Failed to track event: ${error instanceof Error ? error.message : 'Unknown error'}`);
56
+ }
57
+ }
58
+ /**
59
+ * Send event with automatic retry logic
60
+ */
61
+ async sendWithRetry(payload, attempt = 1) {
62
+ try {
63
+ const response = await this.axios.post('', payload);
64
+ return response;
65
+ }
66
+ catch (error) {
67
+ const axiosError = error;
68
+ // Don't retry on client errors (4xx)
69
+ if (axiosError.response?.status && axiosError.response.status < 500) {
70
+ throw error;
71
+ }
72
+ // Retry on server errors (5xx) or network errors
73
+ if (attempt < this.retries) {
74
+ const backoff = Math.pow(2, attempt) * 1000; // Exponential backoff
75
+ await new Promise(resolve => setTimeout(resolve, backoff));
76
+ return this.sendWithRetry(payload, attempt + 1);
77
+ }
78
+ throw error;
79
+ }
80
+ }
81
+ /**
82
+ * Test connection to surveillance API
83
+ */
84
+ async testConnection() {
85
+ try {
86
+ await this.trackEvent({
87
+ eventType: 'custom',
88
+ ip: '127.0.0.1',
89
+ metadata: { test: true },
90
+ });
91
+ return true;
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ }
97
+ }
98
+ exports.DevFortressClient = DevFortressClient;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * DevFortress SDK v4.0.0 — Main Entry Point (Node.js)
3
+ *
4
+ * For browser usage, import from 'devfortress-sdk/browser' instead.
5
+ * For zero-config quick start, import from 'devfortress-sdk/quick'.
6
+ * For Express middleware, use devfortressMiddleware from this package.
7
+ * For FastAPI/Flask, see the Python middleware in src/middleware/
8
+ *
9
+ * NEW in v4.0 — Closed-Loop Mode Architecture:
10
+ * - Three protection modes: external, internal, hybrid
11
+ * - Circuit breaker with automatic failover (hybrid mode)
12
+ * - Unified audit trail (internal + external merged timeline)
13
+ * - Tier-gated feature access (Starter/Pro/Enterprise)
14
+ * - Backward compatible — existing external-mode code works unchanged
15
+ *
16
+ * v3.3:
17
+ * - Internal Closed-Loop Engine (3-tier deterministic + ML + async relay)
18
+ * - Air-gap mode support (no external dependencies in Tier 1 + 2)
19
+ *
20
+ * v3.2:
21
+ * - Agent security (AgentAdapter, credential management, anomaly detection)
22
+ *
23
+ * v3.1:
24
+ * - Zero-config quick start (df.init({ apiKey }))
25
+ * - Privacy-strict mode, Debug mode
26
+ *
27
+ * v3.0:
28
+ * - DevFortress class with observe(), isBlocked(), onThreatDetected()
29
+ * - AbuseIPDB integration, Token alias security, Webhook handler
30
+ *
31
+ * @packageDocumentation
32
+ */
33
+ export { init, getInstance, getDataSnapshot } from './quick';
34
+ export type { QuickConfig } from './quick';
35
+ export { DevFortress } from './devfortress';
36
+ export { PlatformCircuitBreaker } from './circuit-breaker';
37
+ export type { CircuitState, CircuitBreakerConfig } from './circuit-breaker';
38
+ export { UnifiedAuditTrail } from './unified-audit';
39
+ export type { AuditSource, UnifiedAuditEntry, UnifiedAuditConfig, } from './unified-audit';
40
+ export { TierGate } from './tier-gate';
41
+ export type { SubscriptionTier, TierCapabilities } from './tier-gate';
42
+ export { checkIP, reportIP, syncBlacklist, scoreThreat, getCachedScore, } from './abuseipdb';
43
+ export { TokenAliasManager, EmergencyBlocklist } from './token-alias';
44
+ export type { CacheAdapter, TokenAliasManagerConfig, RevocationReason, } from './token-alias';
45
+ export { AgentAdapter, validateAgentId } from './agent';
46
+ export type { AgentToolCall, AgentAdapterConfig } from './agent';
47
+ export { AgentCredentialManager, AgentBaselineEngine, AgentAnomalyDetector, AgentScopeEnforcer, } from './agent-security';
48
+ export type { AgentCredentialType, AgentCredentialAliasData, AgentBaselineMetrics, AgentSessionRecord, AgentAnomalyType, AgentAnomalySignal, AgentScopeDefinition, } from './agent-security';
49
+ export { InternalClosedLoopEngine } from './internal-closed-loop-engine';
50
+ export type { InternalCLConfig, InternalCLRequest, InternalCLResult, InternalCLDecision, InternalCLAction, InternalCLAuditEntry, InternalCLRule, } from './internal-closed-loop-engine';
51
+ export { DevFortressClient } from './client';
52
+ export { devfortressMiddleware } from './middleware/express';
53
+ export type { CLMode, DevFortressConfig, EnrichmentConfig, ObserveResult, ObserveOptions, ThreatEvent, ThreatSeverity, ThreatHandler, ActionReport, WebhookPayload, AbuseIPDBScore, AbuseIPDBCheckResult, CompositeScoreResult, TokenAliasData, DevFortressClientOptions, LiveThreatEvent, EventType, SeverityLevel, DevFortressMiddlewareOptions, ApiResponse, } from './types';
package/dist/index.js ADDED
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * DevFortress SDK v4.0.0 — Main Entry Point (Node.js)
4
+ *
5
+ * For browser usage, import from 'devfortress-sdk/browser' instead.
6
+ * For zero-config quick start, import from 'devfortress-sdk/quick'.
7
+ * For Express middleware, use devfortressMiddleware from this package.
8
+ * For FastAPI/Flask, see the Python middleware in src/middleware/
9
+ *
10
+ * NEW in v4.0 — Closed-Loop Mode Architecture:
11
+ * - Three protection modes: external, internal, hybrid
12
+ * - Circuit breaker with automatic failover (hybrid mode)
13
+ * - Unified audit trail (internal + external merged timeline)
14
+ * - Tier-gated feature access (Starter/Pro/Enterprise)
15
+ * - Backward compatible — existing external-mode code works unchanged
16
+ *
17
+ * v3.3:
18
+ * - Internal Closed-Loop Engine (3-tier deterministic + ML + async relay)
19
+ * - Air-gap mode support (no external dependencies in Tier 1 + 2)
20
+ *
21
+ * v3.2:
22
+ * - Agent security (AgentAdapter, credential management, anomaly detection)
23
+ *
24
+ * v3.1:
25
+ * - Zero-config quick start (df.init({ apiKey }))
26
+ * - Privacy-strict mode, Debug mode
27
+ *
28
+ * v3.0:
29
+ * - DevFortress class with observe(), isBlocked(), onThreatDetected()
30
+ * - AbuseIPDB integration, Token alias security, Webhook handler
31
+ *
32
+ * @packageDocumentation
33
+ */
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.devfortressMiddleware = exports.DevFortressClient = exports.InternalClosedLoopEngine = exports.AgentScopeEnforcer = exports.AgentAnomalyDetector = exports.AgentBaselineEngine = exports.AgentCredentialManager = exports.validateAgentId = exports.AgentAdapter = exports.EmergencyBlocklist = exports.TokenAliasManager = exports.getCachedScore = exports.scoreThreat = exports.syncBlacklist = exports.reportIP = exports.checkIP = exports.TierGate = exports.UnifiedAuditTrail = exports.PlatformCircuitBreaker = exports.DevFortress = exports.getDataSnapshot = exports.getInstance = exports.init = void 0;
36
+ // v3.1 — Zero-config quick start
37
+ var quick_1 = require("./quick");
38
+ Object.defineProperty(exports, "init", { enumerable: true, get: function () { return quick_1.init; } });
39
+ Object.defineProperty(exports, "getInstance", { enumerable: true, get: function () { return quick_1.getInstance; } });
40
+ Object.defineProperty(exports, "getDataSnapshot", { enumerable: true, get: function () { return quick_1.getDataSnapshot; } });
41
+ // v3.0 — Primary export
42
+ var devfortress_1 = require("./devfortress");
43
+ Object.defineProperty(exports, "DevFortress", { enumerable: true, get: function () { return devfortress_1.DevFortress; } });
44
+ // v4.0 — Closed-Loop Mode Architecture
45
+ var circuit_breaker_1 = require("./circuit-breaker");
46
+ Object.defineProperty(exports, "PlatformCircuitBreaker", { enumerable: true, get: function () { return circuit_breaker_1.PlatformCircuitBreaker; } });
47
+ var unified_audit_1 = require("./unified-audit");
48
+ Object.defineProperty(exports, "UnifiedAuditTrail", { enumerable: true, get: function () { return unified_audit_1.UnifiedAuditTrail; } });
49
+ var tier_gate_1 = require("./tier-gate");
50
+ Object.defineProperty(exports, "TierGate", { enumerable: true, get: function () { return tier_gate_1.TierGate; } });
51
+ // v3.0 — AbuseIPDB integration
52
+ var abuseipdb_1 = require("./abuseipdb");
53
+ Object.defineProperty(exports, "checkIP", { enumerable: true, get: function () { return abuseipdb_1.checkIP; } });
54
+ Object.defineProperty(exports, "reportIP", { enumerable: true, get: function () { return abuseipdb_1.reportIP; } });
55
+ Object.defineProperty(exports, "syncBlacklist", { enumerable: true, get: function () { return abuseipdb_1.syncBlacklist; } });
56
+ Object.defineProperty(exports, "scoreThreat", { enumerable: true, get: function () { return abuseipdb_1.scoreThreat; } });
57
+ Object.defineProperty(exports, "getCachedScore", { enumerable: true, get: function () { return abuseipdb_1.getCachedScore; } });
58
+ // v3.0 — Token alias security
59
+ var token_alias_1 = require("./token-alias");
60
+ Object.defineProperty(exports, "TokenAliasManager", { enumerable: true, get: function () { return token_alias_1.TokenAliasManager; } });
61
+ Object.defineProperty(exports, "EmergencyBlocklist", { enumerable: true, get: function () { return token_alias_1.EmergencyBlocklist; } });
62
+ // v3.2 — Agent Security (IP-C1 through IP-C5)
63
+ var agent_1 = require("./agent");
64
+ Object.defineProperty(exports, "AgentAdapter", { enumerable: true, get: function () { return agent_1.AgentAdapter; } });
65
+ Object.defineProperty(exports, "validateAgentId", { enumerable: true, get: function () { return agent_1.validateAgentId; } });
66
+ var agent_security_1 = require("./agent-security");
67
+ Object.defineProperty(exports, "AgentCredentialManager", { enumerable: true, get: function () { return agent_security_1.AgentCredentialManager; } });
68
+ Object.defineProperty(exports, "AgentBaselineEngine", { enumerable: true, get: function () { return agent_security_1.AgentBaselineEngine; } });
69
+ Object.defineProperty(exports, "AgentAnomalyDetector", { enumerable: true, get: function () { return agent_security_1.AgentAnomalyDetector; } });
70
+ Object.defineProperty(exports, "AgentScopeEnforcer", { enumerable: true, get: function () { return agent_security_1.AgentScopeEnforcer; } });
71
+ // v3.3 — Internal Closed-Loop Engine
72
+ var internal_closed_loop_engine_1 = require("./internal-closed-loop-engine");
73
+ Object.defineProperty(exports, "InternalClosedLoopEngine", { enumerable: true, get: function () { return internal_closed_loop_engine_1.InternalClosedLoopEngine; } });
74
+ // v1.x — Backward compatible exports
75
+ var client_1 = require("./client");
76
+ Object.defineProperty(exports, "DevFortressClient", { enumerable: true, get: function () { return client_1.DevFortressClient; } });
77
+ var express_1 = require("./middleware/express");
78
+ Object.defineProperty(exports, "devfortressMiddleware", { enumerable: true, get: function () { return express_1.devfortressMiddleware; } });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Express.js Middleware for DevFortress Surveillance
3
+ */
4
+ import { Request, Response, NextFunction } from 'express';
5
+ import type { DevFortressMiddlewareOptions } from '../types';
6
+ /**
7
+ * Create Express middleware for automatic threat monitoring
8
+ */
9
+ export declare function devfortressMiddleware(options: DevFortressMiddlewareOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
@@ -0,0 +1,236 @@
1
+ "use strict";
2
+ /**
3
+ * Express.js Middleware for DevFortress Surveillance
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.devfortressMiddleware = devfortressMiddleware;
7
+ const client_1 = require("../client");
8
+ /**
9
+ * Create Express middleware for automatic threat monitoring
10
+ */
11
+ function devfortressMiddleware(options) {
12
+ const client = new client_1.DevFortressClient(options);
13
+ const { captureBody = false, captureHeaders = false, excludePaths = [], sanitize, onRequest, onError, mode = 'external', } = options;
14
+ return async function devfortressMiddlewareHandler(req, res, next) {
15
+ // Skip excluded paths
16
+ if (excludePaths.some(path => req.path.startsWith(path))) {
17
+ return next();
18
+ }
19
+ const startTime = Date.now();
20
+ // Capture response
21
+ const originalSend = res.send;
22
+ res.send = function (body) {
23
+ return originalSend.call(this, body);
24
+ };
25
+ // Wait for response to finish
26
+ res.on('finish', async () => {
27
+ try {
28
+ const responseTime = Date.now() - startTime;
29
+ const statusCode = res.statusCode;
30
+ // Determine if this is a security event
31
+ let eventType = null;
32
+ let severity = 'LOW';
33
+ let reason;
34
+ // Check for authentication failures
35
+ if (statusCode === 401 || statusCode === 403) {
36
+ eventType = 'auth_failure';
37
+ severity = 'MEDIUM';
38
+ reason = 'Authentication or authorization failed';
39
+ }
40
+ // Check for validation errors
41
+ else if (statusCode === 400 || statusCode === 422) {
42
+ eventType = 'validation_error';
43
+ severity = 'LOW';
44
+ reason = 'Request validation failed';
45
+ }
46
+ // Check for rate limiting
47
+ else if (statusCode === 429) {
48
+ eventType = 'rate_limit_exceeded';
49
+ severity = 'MEDIUM';
50
+ reason = 'Rate limit exceeded';
51
+ }
52
+ // Check for server errors
53
+ else if (statusCode >= 500) {
54
+ eventType = '5xx_error';
55
+ severity = 'HIGH';
56
+ reason = `Server error: ${statusCode}`;
57
+ }
58
+ // Check for client errors
59
+ else if (statusCode >= 400) {
60
+ eventType = '4xx_error';
61
+ severity = 'LOW';
62
+ reason = `Client error: ${statusCode}`;
63
+ }
64
+ // Check for suspicious patterns
65
+ const suspiciousPatterns = detectSuspiciousPatterns(req);
66
+ if (suspiciousPatterns.length > 0) {
67
+ eventType = 'suspicious_pattern';
68
+ severity = 'HIGH';
69
+ reason = `Suspicious patterns detected: ${suspiciousPatterns.join(', ')}`;
70
+ }
71
+ // Allow custom event detection
72
+ if (onRequest) {
73
+ const customEvent = onRequest(req);
74
+ if (customEvent) {
75
+ eventType = customEvent.eventType || eventType;
76
+ severity = customEvent.severity || severity;
77
+ reason = customEvent.reason || reason;
78
+ }
79
+ }
80
+ // Only track if we detected an event
81
+ if (eventType) {
82
+ let metadata = {
83
+ method: req.method,
84
+ path: req.path,
85
+ query: req.query,
86
+ responseTime,
87
+ };
88
+ if (captureHeaders) {
89
+ metadata.headers = req.headers;
90
+ }
91
+ if (captureBody && req.body) {
92
+ metadata.body = req.body;
93
+ }
94
+ // Sanitize metadata if function provided
95
+ if (sanitize) {
96
+ metadata = sanitize(metadata);
97
+ }
98
+ // Determine auth phase: if a userId is present, this is post-auth
99
+ const reqAny = req;
100
+ const userObj = reqAny.user;
101
+ const userId = (typeof reqAny.userId === 'string' ? reqAny.userId : null) ||
102
+ (typeof userObj?.id === 'string' ? userObj.id : null);
103
+ const sessionId = (typeof reqAny.sessionId === 'string' ? reqAny.sessionId : null) ||
104
+ (typeof req.headers['x-session-id'] === 'string' ? req.headers['x-session-id'] : null);
105
+ const authPhase = userId ? 'post_auth' : 'pre_auth';
106
+ // Determine action taken based on status code and event type
107
+ let actionTaken = 'monitored';
108
+ if (statusCode === 429) {
109
+ actionTaken = 'rate_limited';
110
+ }
111
+ else if (statusCode === 403) {
112
+ actionTaken = 'blocked';
113
+ }
114
+ else if (statusCode === 401 && userId) {
115
+ actionTaken = 'session_revoked';
116
+ }
117
+ else if (statusCode === 401) {
118
+ actionTaken = 'blocked';
119
+ }
120
+ else if (statusCode >= 400 && statusCode < 500) {
121
+ actionTaken = 'flagged';
122
+ }
123
+ else if (statusCode >= 200 && statusCode < 300 && suspiciousPatterns.length > 0) {
124
+ actionTaken = 'flagged';
125
+ }
126
+ else if (statusCode >= 200 && statusCode < 300) {
127
+ actionTaken = 'allowed';
128
+ }
129
+ // Session remains active if action is not blocking/revoking
130
+ const sessionActiveAfterAction = !['blocked', 'session_revoked'].includes(actionTaken);
131
+ const event = {
132
+ eventType,
133
+ ip: getClientIp(req),
134
+ method: req.method,
135
+ path: req.path,
136
+ userAgent: req.get('user-agent') || null,
137
+ statusCode,
138
+ responseTime,
139
+ metadata: { ...metadata },
140
+ severity,
141
+ reason,
142
+ // v3.1 observability fields
143
+ clMode: mode,
144
+ authPhase,
145
+ actionTaken,
146
+ responseLatencyMs: responseTime,
147
+ userId: userId || null,
148
+ sessionId: sessionId || null,
149
+ sessionActiveAfterAction,
150
+ };
151
+ // Track event asynchronously (non-blocking)
152
+ client.trackEvent(event).catch(error => {
153
+ if (onError) {
154
+ onError(error);
155
+ }
156
+ });
157
+ }
158
+ }
159
+ catch (error) {
160
+ if (onError) {
161
+ onError(error);
162
+ }
163
+ }
164
+ });
165
+ next();
166
+ };
167
+ }
168
+ /**
169
+ * Get client IP address from request
170
+ */
171
+ function getClientIp(req) {
172
+ return (req.headers['x-forwarded-for']?.split(',')[0]?.trim() ||
173
+ req.headers['x-real-ip'] ||
174
+ req.socket.remoteAddress ||
175
+ '0.0.0.0');
176
+ }
177
+ /**
178
+ * Detect suspicious patterns in request
179
+ */
180
+ function detectSuspiciousPatterns(req) {
181
+ const patterns = [];
182
+ // SQL Injection patterns
183
+ const sqlPatterns = [
184
+ /('\s*\bor\b\s+'[^']*'\s*=\s*')/i,
185
+ /(\bunion\b\s+\bselect\b)/i,
186
+ /(\bdrop\b\s+\btable\b)/i,
187
+ /(\binsert\b\s+\binto\b)/i,
188
+ /('\s*or\s*'1'\s*=\s*'1)/i,
189
+ /(;\s*--)/,
190
+ ];
191
+ // XSS patterns
192
+ const xssPatterns = [
193
+ /<script[^>]*>[\s\S]*?<\/script>/i,
194
+ /<iframe[^>]*>[\s\S]*?<\/iframe>/i,
195
+ /javascript:/i,
196
+ /onerror\s*=\s*/i,
197
+ /onload\s*=\s*/i,
198
+ ];
199
+ // Path traversal patterns
200
+ const traversalPatterns = [
201
+ /\.\.[\/\\]/,
202
+ /\/etc\/passwd/i,
203
+ /\/windows\/system32/i,
204
+ ];
205
+ let requestString;
206
+ try {
207
+ requestString = JSON.stringify({
208
+ url: req.url,
209
+ query: req.query,
210
+ body: req.body,
211
+ }).slice(0, 10000); // Limit size to prevent performance issues
212
+ }
213
+ catch {
214
+ requestString = req.url || '';
215
+ }
216
+ // Check SQL injection
217
+ if (sqlPatterns.some(pattern => pattern.test(requestString))) {
218
+ patterns.push('sql_injection');
219
+ }
220
+ // Check XSS
221
+ if (xssPatterns.some(pattern => pattern.test(requestString))) {
222
+ patterns.push('xss');
223
+ }
224
+ // Check path traversal
225
+ if (traversalPatterns.some(pattern => pattern.test(requestString))) {
226
+ patterns.push('path_traversal');
227
+ }
228
+ // Check for excessive failed auth attempts
229
+ if (req.headers['x-devfortress-failed-attempts']) {
230
+ const attempts = parseInt(req.headers['x-devfortress-failed-attempts'], 10);
231
+ if (attempts > 5) {
232
+ patterns.push('brute_force');
233
+ }
234
+ }
235
+ return patterns;
236
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * DevFortress SDK — Zero-Config Quick Start
3
+ *
4
+ * One-line initialization for fastest time-to-first-event:
5
+ * import df from 'devfortress-sdk/quick';
6
+ * df.init({ apiKey: 'df_...' });
7
+ *
8
+ * Auto-detects framework (Express, Fastify, Next.js, Hono)
9
+ * and applies appropriate middleware configuration.
10
+ */
11
+ import { DevFortress } from './devfortress';
12
+ export interface QuickConfig {
13
+ apiKey: string;
14
+ /** App identifier (auto-generated from package.json name if omitted) */
15
+ appId?: string;
16
+ /** Privacy mode: 'standard' | 'strict'. Strict never sends user agents, IPs are hashed */
17
+ privacy?: 'standard' | 'strict';
18
+ /** Enable console debug logs: [DF →] / [DF ✗] */
19
+ debug?: boolean;
20
+ /** Override ingest endpoint */
21
+ endpoint?: string;
22
+ /** Environment tag */
23
+ environment?: string;
24
+ }
25
+ export declare function init(config: QuickConfig): DevFortress;
26
+ export declare function getInstance(): DevFortress | null;
27
+ /** Data snapshot for privacy transparency — shows what would be sent */
28
+ export declare function getDataSnapshot(req: unknown): {
29
+ collected: Record<string, string>;
30
+ neverCollected: string[];
31
+ };
32
+ declare const _default: {
33
+ init: typeof init;
34
+ getInstance: typeof getInstance;
35
+ getDataSnapshot: typeof getDataSnapshot;
36
+ };
37
+ export default _default;
package/dist/quick.js ADDED
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ /**
3
+ * DevFortress SDK — Zero-Config Quick Start
4
+ *
5
+ * One-line initialization for fastest time-to-first-event:
6
+ * import df from 'devfortress-sdk/quick';
7
+ * df.init({ apiKey: 'df_...' });
8
+ *
9
+ * Auto-detects framework (Express, Fastify, Next.js, Hono)
10
+ * and applies appropriate middleware configuration.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.init = init;
14
+ exports.getInstance = getInstance;
15
+ exports.getDataSnapshot = getDataSnapshot;
16
+ const devfortress_1 = require("./devfortress");
17
+ function detectFramework() {
18
+ try {
19
+ // Check for Next.js
20
+ if (typeof process !== 'undefined') {
21
+ if (process.env.NEXT_RUNTIME || process.env.__NEXT_PRIVATE_ORIGIN) {
22
+ return 'nextjs';
23
+ }
24
+ }
25
+ // Check for Express (most common)
26
+ try {
27
+ require.resolve('express');
28
+ return 'express';
29
+ }
30
+ catch {
31
+ /* not available */
32
+ }
33
+ // Check for Fastify
34
+ try {
35
+ require.resolve('fastify');
36
+ return 'fastify';
37
+ }
38
+ catch {
39
+ /* not available */
40
+ }
41
+ // Check for Hono
42
+ try {
43
+ require.resolve('hono');
44
+ return 'hono';
45
+ }
46
+ catch {
47
+ /* not available */
48
+ }
49
+ }
50
+ catch {
51
+ /* detection failed */
52
+ }
53
+ return 'unknown';
54
+ }
55
+ /* ─── Auto-detect app ID ─── */
56
+ function autoAppId() {
57
+ try {
58
+ // Try to read from nearest package.json
59
+ const pkg = require(process.cwd() + '/package.json');
60
+ if (pkg.name)
61
+ return pkg.name;
62
+ }
63
+ catch {
64
+ /* no package.json */
65
+ }
66
+ return `app-${Date.now().toString(36)}`;
67
+ }
68
+ /* ─── Quick start factory ─── */
69
+ let _instance = null;
70
+ function init(config) {
71
+ const framework = detectFramework();
72
+ const appId = config.appId ?? autoAppId();
73
+ const isStrict = config.privacy === 'strict';
74
+ const fullConfig = {
75
+ apiKey: config.apiKey,
76
+ appId,
77
+ environment: config.environment ?? process.env.NODE_ENV ?? 'production',
78
+ debug: config.debug ?? false,
79
+ endpoint: config.endpoint,
80
+ // In strict privacy mode, hash IPs before sending
81
+ enrichment: isStrict
82
+ ? {
83
+ getIP: (req) => {
84
+ const r = req;
85
+ const raw = r.ip ?? r.socket?.remoteAddress ?? 'unknown';
86
+ // SHA-256 hash for privacy
87
+ const crypto = require('crypto');
88
+ return crypto
89
+ .createHash('sha256')
90
+ .update(raw)
91
+ .digest('hex')
92
+ .slice(0, 16);
93
+ },
94
+ }
95
+ : undefined,
96
+ };
97
+ _instance = new devfortress_1.DevFortress(fullConfig);
98
+ if (config.debug) {
99
+ console.log(`[DF →] DevFortress initialized (framework: ${framework}, privacy: ${config.privacy ?? 'standard'}, appId: ${appId})`);
100
+ }
101
+ return _instance;
102
+ }
103
+ function getInstance() {
104
+ return _instance;
105
+ }
106
+ /** Data snapshot for privacy transparency — shows what would be sent */
107
+ function getDataSnapshot(req) {
108
+ const r = req;
109
+ return {
110
+ collected: {
111
+ ip: typeof r.ip === 'string' ? r.ip : 'from socket',
112
+ method: String(r.method ?? 'unknown'),
113
+ path: String(r.url ?? r.path ?? 'unknown'),
114
+ statusCode: 'after response',
115
+ responseTime: 'measured automatically',
116
+ timestamp: new Date().toISOString(),
117
+ userAgent: 'first 200 chars only',
118
+ },
119
+ neverCollected: [
120
+ 'Request body content',
121
+ 'Response body content',
122
+ 'Cookies or session data',
123
+ 'Authorization headers',
124
+ 'Real session tokens (anonymised via proprietary mechanism)',
125
+ 'Query string values',
126
+ 'Form data',
127
+ 'File uploads',
128
+ 'Database queries',
129
+ 'Environment variables',
130
+ 'Source code',
131
+ 'User PII (names, emails, phone numbers)',
132
+ ],
133
+ };
134
+ }
135
+ exports.default = { init, getInstance, getDataSnapshot };