Files
zeekay 26a9531f7b merge: upstream/main (sync, brand preserved)
# Conflicts:
#	.github/workflows/check-insights-major-version.yml
#	.github/workflows/check-posthog-major-version.yml
#	.github/workflows/ci-security.yaml
#	.github/workflows/validate-versioning.yml
#	AGENTS.md
#	AGENTS.md~upstream_main
#	packages/ai/src/otel/capture.ts
#	packages/ai/src/otel/mappers/aiSdk.ts
#	packages/ai/src/otel/mappers/index.ts
#	packages/ai/src/otel/types.ts
#	packages/core/src/__tests__/posthog.init.spec.ts
#	packages/react-native/src/PostHogProvider.tsx
#	packages/react/src/context/PostHogContext.ts
#	packages/react/src/context/PostHogProvider.tsx
#	tooling/eslint-plugin-insights/no-unsafe-web-global.js
2026-06-02 10:52:56 -07:00

207 lines
5.6 KiB
JavaScript

/**
* Insights Node SDK Compliance Adapter
*
* Wraps the insights-node SDK for compliance testing.
*/
const express = require('express')
const { Insights } = require('../../packages/node/dist/entrypoints/index.node')
const app = express()
app.use(express.json())
const state = {
client: null,
totalEventsCaptured: 0,
totalEventsSent: 0,
totalRetries: 0,
lastError: null,
requestsMade: [],
pendingEvents: 0,
}
app.get('/health', (req, res) => {
res.json({
sdk_name: 'insights-node',
sdk_version: require('../../packages/node/package.json').version,
adapter_version: '1.0.0',
capabilities: ['capture_v0', 'encoding_gzip'],
})
})
app.post('/init', (req, res) => {
const { api_key, host, flush_at, flush_interval_ms, max_retries, enable_compression } = req.body
// Shutdown existing client
if (state.client) {
state.client.shutdown()
}
// Reset state
state.totalEventsCaptured = 0
state.totalEventsSent = 0
state.totalRetries = 0
state.lastError = null
state.requestsMade = []
state.pendingEvents = 0
// Create new client
state.client = new Insights(api_key, {
host,
flushAt: flush_at ?? 1,
flushInterval: flush_interval_ms ?? 100,
// Use before_send to track events being sent
before_send: (event) => {
// Track that event is being sent
// Note: This runs before the HTTP request
return event
},
// Override fetch to track HTTP requests
fetch: async (url, options) => {
const response = await fetch(url, options)
// Track the request
try {
const body = options?.body ? JSON.parse(options.body) : null
const events = body?.batch || (body ? [body] : [])
state.requestsMade.push({
timestamp_ms: Date.now(),
status_code: response.status,
retry_attempt: 0,
event_count: events.length,
uuid_list: events.map(e => e.uuid).filter(Boolean),
})
if (response.status === 200) {
state.totalEventsSent += events.length
state.pendingEvents -= events.length
if (state.pendingEvents < 0) state.pendingEvents = 0
}
} catch (e) {
// Ignore parsing errors
}
return response
},
})
res.json({ success: true })
})
app.post('/capture', (req, res) => {
if (!state.client) {
return res.status(400).json({ error: 'SDK not initialized' })
}
const { distinct_id, event, properties, timestamp } = req.body
if (!distinct_id || !event) {
return res.status(400).json({ error: 'distinct_id and event are required' })
}
try {
// Capture event
state.client.capture({
distinctId: distinct_id,
event,
properties,
timestamp: timestamp ? new Date(timestamp) : undefined,
})
state.totalEventsCaptured++
state.pendingEvents++
// TODO: Get actual UUID from SDK
res.json({ success: true, uuid: 'generated-uuid' })
} catch (error) {
state.lastError = error.message
res.status(500).json({ error: error.message })
}
})
app.post('/flush', async (req, res) => {
if (!state.client) {
return res.status(400).json({ error: 'SDK not initialized' })
}
try {
await state.client.flush()
res.json({ success: true, events_flushed: state.totalEventsSent })
} catch (error) {
state.lastError = error.message
res.status(500).json({ error: error.message })
}
})
app.get('/state', (req, res) => {
res.json({
pending_events: state.pendingEvents,
total_events_captured: state.totalEventsCaptured,
total_events_sent: state.totalEventsSent,
total_retries: state.totalRetries,
last_error: state.lastError,
requests_made: state.requestsMade,
})
})
app.post('/get_feature_flag', async (req, res) => {
if (!state.client) {
return res.status(400).json({ error: 'SDK not initialized' })
}
const {
key,
distinct_id,
person_properties,
groups,
group_properties,
disable_geoip,
force_remote = true,
} = req.body || {}
if (!key) {
return res.status(400).json({ error: 'key is required' })
}
if (!distinct_id) {
return res.status(400).json({ error: 'distinct_id is required' })
}
try {
const value = await state.client.getFeatureFlag(key, distinct_id, {
groups,
personProperties: person_properties,
groupProperties: group_properties,
disableGeoip: disable_geoip,
onlyEvaluateLocally: !force_remote,
sendFeatureFlagEvents: false,
})
res.json({ success: true, value })
} catch (error) {
state.lastError = error.message
res.status(500).json({ error: error.message })
}
})
app.post('/reset', (req, res) => {
if (state.client) {
state.client.shutdown()
state.client = null
}
state.totalEventsCaptured = 0
state.totalEventsSent = 0
state.totalRetries = 0
state.lastError = null
state.requestsMade = []
state.pendingEvents = 0
res.json({ success: true })
})
const port = process.env.PORT || 8080
app.listen(port, () => {
console.log(`Insights Node SDK adapter listening on port ${port}`)
})