From 112c69bb929a34fb2cedc88c60f3684f173dd276 Mon Sep 17 00:00:00 2001 From: Mike Conrad Date: Wed, 28 May 2025 15:51:05 -0400 Subject: [PATCH] Add faker endpoint for local dev --- app/controllers/replays_controller.ts | 80 ++++++++++++++++++++++++++- package-lock.json | 1 + package.json | 1 + start/routes.ts | 1 + 4 files changed, 80 insertions(+), 3 deletions(-) diff --git a/app/controllers/replays_controller.ts b/app/controllers/replays_controller.ts index d06e0c4..7d07f83 100644 --- a/app/controllers/replays_controller.ts +++ b/app/controllers/replays_controller.ts @@ -5,8 +5,19 @@ const SENTRY_ORG = env.get('SENTRY_ORG') import redis from '@adonisjs/redis/services/main' import { fetchBatch } from '../Helpers/Replays.js' import { sendDataToWebhook } from '../Helpers/Webhook.js' +import { faker } from '@faker-js/faker' export default class ReplaysController { + public async faker({ request, response }: HttpContext) { + const { page } = await request.qs() + const sessions = Array.from({ length: 100 }, generateFakeSession) + const nextPage = +page + 1 + await response.safeHeader( + 'link', + `; rel="previous"; results="true"; cursor="0:1100:1", ; rel="next"; results="${page == 10 ? 'false' : 'true'}"; cursor="0:${page * 100}:0"` + ) + return { data: sessions, count: sessions.length, page: page } + } public async stats({ request, response }: HttpContext) { const { sendToWebhook } = request.qs() const latestVersion = await redis.get(`replays:stats:latest_version`) @@ -77,9 +88,12 @@ export default class ReplaysController { queryString = `?start=${start}&end=${end}` } const queryFilter = env.get('QUERY_FILTER') - await fetchBatch( - `https://sentry.io/api/0/organizations/${SENTRY_ORG}/replays/${queryString}&field=id&field=user&field=duration&field=started_at&field=finished_at&query=${encodeURIComponent(queryFilter)}` - ) + const baseUrl = + env.get('NODE_ENV') == 'production' + ? `https://sentry.io/api/0/organizations/${SENTRY_ORG}/replays/${queryString}&field=id&field=user&field=duration&field=started_at&field=finished_at&query=${encodeURIComponent(queryFilter)}` + : 'http://localhost:3333/faker?page=1' + console.log('base', baseUrl) + await fetchBatch(baseUrl) let queryResults = await Replay.updateReplayStats() @@ -119,3 +133,63 @@ function buildPaginationLinks(meta: { return links } + +function generateFakeSession() { + const uuid = faker.string.uuid() + const browserName = faker.helpers.arrayElement(['Chrome', 'Firefox', 'Safari', 'Edge', 'Brave']) + const deviceBrand = faker.helpers.arrayElement(['Apple', 'Samsung', 'Google']) + const osName = faker.helpers.arrayElement(['iOS', 'Android', 'Windows', 'macOS']) + const platform = faker.helpers.arrayElement(['Sentry', 'Datadog', 'New Relic', 'Rollbar']) + const finishedAt = new Date(Date.now() - faker.number.int({ min: 0, max: 60 * 60 * 1000 })) + const displayName = faker.internet.email() + return { + activity: faker.number.int({ min: 1, max: 10 }), + browser: { + name: browserName, + version: faker.system.semver(), + }, + count_dead_clicks: faker.number.int({ min: 0, max: 10 }), + count_rage_clicks: faker.number.int({ min: 0, max: 5 }), + count_errors: faker.number.int({ min: 0, max: 5 }), + count_segments: faker.number.int({ min: 0, max: 3 }), + count_urls: faker.number.int({ min: 1, max: 3 }), + device: { + brand: deviceBrand, + family: deviceBrand === 'Apple' ? 'iPhone' : deviceBrand, + model: faker.string.numeric({ length: 2 }), + name: `${deviceBrand} ${faker.string.alphanumeric({ length: 3 })}`, + }, + dist: null, + duration: faker.number.int({ min: 100, max: 1000 }), + environment: faker.helpers.arrayElement(['production', 'staging', 'development']), + error_ids: [uuid], + finished_at: faker.date.between({ from: finishedAt, to: new Date() }).toISOString(), + has_viewed: faker.datatype.boolean(), + id: uuid, + is_archived: faker.datatype.boolean() ? null : false, + os: { + name: osName, + version: `${faker.number.int({ min: 10, max: 17 })}.${faker.number.int({ min: 0, max: 5 })}`, + }, + platform: platform, + project_id: faker.string.numeric({ length: 6 }), + releases: [`version@${faker.system.semver()}`], + sdk: { + name: faker.hacker.noun(), + version: faker.system.semver(), + }, + started_at: faker.date.recent().toISOString(), + tags: { + hello: ['world', faker.person.fullName()], + }, + trace_ids: [uuid], + urls: [faker.internet.url()], + user: { + display_name: displayName, + email: displayName, + id: faker.string.numeric({ length: 8 }), + ip: faker.internet.ip(), + username: faker.internet.username(), + }, + } +} diff --git a/package-lock.json b/package-lock.json index 6d9db39..0ef9cda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,7 @@ "@adonisjs/eslint-config": "^2.0.0", "@adonisjs/prettier-config": "^1.4.4", "@adonisjs/tsconfig": "^1.4.0", + "@faker-js/faker": "^9.8.0", "@japa/assert": "^4.0.1", "@japa/plugin-adonisjs": "^4.0.0", "@japa/runner": "^4.2.0", diff --git a/package.json b/package.json index 88afd5b..97b6246 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "@adonisjs/eslint-config": "^2.0.0", "@adonisjs/prettier-config": "^1.4.4", "@adonisjs/tsconfig": "^1.4.0", + "@faker-js/faker": "^9.8.0", "@japa/assert": "^4.0.1", "@japa/plugin-adonisjs": "^4.0.0", "@japa/runner": "^4.2.0", diff --git a/start/routes.ts b/start/routes.ts index 2f625b1..924e552 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -12,3 +12,4 @@ import router from '@adonisjs/core/services/router' router.get('/', [ReplaysController, 'home']) router.get('/replays', [ReplaysController, 'index']) router.get('/stats', [ReplaysController, 'stats']) +router.get('/faker', [ReplaysController, 'faker'])