dev #8
@@ -33,6 +33,7 @@ import { RedisModule } from "./redis/redis.module";
|
||||
import { ReferralsModule } from "./referrals/referrals.module";
|
||||
import { StorageModule } from "./storage/storage.module";
|
||||
import { SubscriptionsModule } from "./subscriptions/subscriptions.module";
|
||||
import { TelemetryModule } from "./telemetry/telemetry.module";
|
||||
import { TranslationsModule } from "./translations/translations.module";
|
||||
import { UsersModule } from "./users/users.module";
|
||||
import { VehiclesModule } from "./vehicles/vehicles.module";
|
||||
@@ -83,6 +84,7 @@ import { VehiclesModule } from "./vehicles/vehicles.module";
|
||||
CatalogModule,
|
||||
ChangelogModule,
|
||||
PostHogModule,
|
||||
TelemetryModule,
|
||||
],
|
||||
controllers: [HealthController],
|
||||
providers: [
|
||||
|
||||
@@ -16,7 +16,7 @@ async function bootstrap() {
|
||||
const port = configService.get<number>("port", 4000);
|
||||
const corsOrigins = configService.get<string[]>("cors.origin", ["http://localhost:3000"]);
|
||||
|
||||
app.setGlobalPrefix("api");
|
||||
app.setGlobalPrefix("api", { exclude: ["/collect/(.*)"] });
|
||||
|
||||
// Security headers
|
||||
app.use(
|
||||
@@ -24,11 +24,16 @@ async function bootstrap() {
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
defaultSrc: ["'self'"],
|
||||
scriptSrc: ["'self'"],
|
||||
scriptSrc: [
|
||||
"'self'",
|
||||
"https://t.sase.tr",
|
||||
"'sha256-T5FzBQBMINFjZ4WLy58SeZ+J7xXzjnQEGlg618CQnhA='",
|
||||
],
|
||||
styleSrc: ["'self'", "https:", "'unsafe-inline'"],
|
||||
imgSrc: ["'self'", "data:", "https://storage.sase.tr"],
|
||||
fontSrc: ["'self'", "https:", "data:"],
|
||||
connectSrc: ["'self'", "https://storage.sase.tr"],
|
||||
mediaSrc: ["'self'", "data:"],
|
||||
connectSrc: ["'self'", "https://storage.sase.tr", "https://t.sase.tr"],
|
||||
objectSrc: ["'none'"],
|
||||
frameSrc: ["'none'"],
|
||||
},
|
||||
|
||||
32
apps/api/src/telemetry/faro-collect.controller.ts
Normal file
32
apps/api/src/telemetry/faro-collect.controller.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Controller, Logger, Param, Post, Req, Res } from "@nestjs/common";
|
||||
import type { Request, Response } from "express";
|
||||
import { Public } from "../common/decorators/public.decorator";
|
||||
|
||||
const DEFAULT_FARO_UPSTREAM = "https://faro-collector-prod-eu-west-2.grafana.net";
|
||||
|
||||
@Controller("collect")
|
||||
export class FaroCollectController {
|
||||
private readonly logger = new Logger(FaroCollectController.name);
|
||||
private readonly upstream = process.env.FARO_UPSTREAM ?? DEFAULT_FARO_UPSTREAM;
|
||||
|
||||
@Public()
|
||||
@Post(":id")
|
||||
async forward(@Param("id") id: string, @Req() req: Request, @Res() res: Response): Promise<void> {
|
||||
const rawBody = (req as Request & { rawBody?: Buffer }).rawBody;
|
||||
const body = rawBody ?? Buffer.from(JSON.stringify(req.body ?? {}));
|
||||
try {
|
||||
const upstream = await fetch(`${this.upstream}/collect/${encodeURIComponent(id)}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": req.headers["content-type"] ?? "application/json",
|
||||
"user-agent": req.headers["user-agent"] ?? "sase-faro-proxy",
|
||||
},
|
||||
body,
|
||||
});
|
||||
res.status(upstream.status).end();
|
||||
} catch (err) {
|
||||
this.logger.warn(`Faro forward failed: ${(err as Error).message}`);
|
||||
res.status(502).end();
|
||||
}
|
||||
}
|
||||
}
|
||||
7
apps/api/src/telemetry/telemetry.module.ts
Normal file
7
apps/api/src/telemetry/telemetry.module.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { FaroCollectController } from "./faro-collect.controller";
|
||||
|
||||
@Module({
|
||||
controllers: [FaroCollectController],
|
||||
})
|
||||
export class TelemetryModule {}
|
||||
@@ -431,6 +431,9 @@ export function SubscriptionPage() {
|
||||
capture("plan_selected", { plan: planKey });
|
||||
setSelectedPlanKey(planKey);
|
||||
setSelectedBrandIds([]);
|
||||
if (planKey === "full") {
|
||||
capture("checkout_started", { plan: planKey, period: billingPeriod });
|
||||
}
|
||||
setStep(planKey === "full" ? "payment" : "brands");
|
||||
}
|
||||
|
||||
@@ -780,6 +783,7 @@ export function SubscriptionPage() {
|
||||
onAdvance={() => {
|
||||
if (step === "plan") {
|
||||
if (!selectedPlanKey) return;
|
||||
capture("checkout_started", { plan: selectedPlanKey, period: billingPeriod });
|
||||
setStep(isFullPlan ? "payment" : "brands");
|
||||
} else if (step === "brands") {
|
||||
handleAdvanceFromBrands();
|
||||
|
||||
Reference in New Issue
Block a user