n8n/packages/cli/src/controllers/posthog.controller.ts
2025-11-26 14:31:12 +01:00

104 lines
3.3 KiB
TypeScript

import { GlobalConfig } from '@n8n/config';
import { AuthenticatedRequest } from '@n8n/db';
import { Get, Post, RestController } from '@n8n/decorators';
import { NextFunction, Response } from 'express';
import { createProxyMiddleware, fixRequestBody } from 'http-proxy-middleware';
@RestController('/posthog')
export class PostHogController {
proxy;
constructor(private readonly globalConfig: GlobalConfig) {
const targetUrl = this.globalConfig.diagnostics.posthogConfig.apiHost;
this.proxy = createProxyMiddleware({
target: targetUrl,
changeOrigin: true,
pathRewrite: {
'^/posthog/': '/',
},
on: {
proxyReq: (proxyReq, req) => {
proxyReq.removeHeader('cookie');
if (req.method === 'POST') {
fixRequestBody(proxyReq, req);
}
},
},
});
}
// Main event capture endpoint
@Post('/capture/', { skipAuth: true, rateLimit: { limit: 200, windowMs: 60_000 } })
async capture(req: AuthenticatedRequest, res: Response, next: NextFunction) {
return await this.proxy(req, res, next);
}
// Feature flags and configuration
@Post('/decide/', { skipAuth: true, rateLimit: { limit: 100, windowMs: 60_000 } })
async decide(req: AuthenticatedRequest, res: Response, next: NextFunction) {
return await this.proxy(req, res, next);
}
// Session recording events
@Post('/s/', { skipAuth: true, rateLimit: { limit: 50, windowMs: 60_000 } })
async sessionRecording(req: AuthenticatedRequest, res: Response, next: NextFunction) {
return await this.proxy(req, res, next);
}
// Session recording events (alternative endpoint)
@Post('/e/', { skipAuth: true, rateLimit: { limit: 50, windowMs: 60_000 } })
async sessionEvents(req: AuthenticatedRequest, res: Response, next: NextFunction) {
return await this.proxy(req, res, next);
}
// Person/profile updates
@Post('/engage/', { skipAuth: true, rateLimit: { limit: 50, windowMs: 60_000 } })
async engage(req: AuthenticatedRequest, res: Response, next: NextFunction) {
return await this.proxy(req, res, next);
}
// Batch endpoint (for multiple events)
@Post('/batch/', { skipAuth: true, rateLimit: { limit: 100, windowMs: 60_000 } })
async batch(req: AuthenticatedRequest, res: Response, next: NextFunction) {
return await this.proxy(req, res, next);
}
// Feature flags endpoint - /flags/
@Post('/flags/', { skipAuth: true, rateLimit: { limit: 100, windowMs: 60_000 } })
async flags(req: AuthenticatedRequest, res: Response, next: NextFunction) {
return await this.proxy(req, res, next);
}
// Static files - specific endpoint for array.js and lazy-recorder.js
@Get('/static/array.js', {
skipAuth: true,
usesTemplates: true,
rateLimit: { limit: 50, windowMs: 60_000 },
})
staticArrayJs(req: AuthenticatedRequest, res: Response, next: NextFunction) {
void this.proxy(req, res, next);
}
@Get('/static/lazy-recorder.js', {
skipAuth: true,
usesTemplates: true,
rateLimit: { limit: 50, windowMs: 60_000 },
})
staticLazyRecorderJs(req: AuthenticatedRequest, res: Response, next: NextFunction) {
void this.proxy(req, res, next);
}
// Configuration endpoints for array.js
@Get('/array/:apiKey/config.js', {
skipAuth: true,
rateLimit: { limit: 20, windowMs: 60_000 },
usesTemplates: true,
})
arrayConfig(req: AuthenticatedRequest, res: Response, next: NextFunction) {
void this.proxy(req, res, next);
}
}