From bafaf3b95ea23d049dc9e4cf19ebd0b95882a68a Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Mon, 3 Jun 2024 19:38:52 +0000 Subject: [PATCH] feat: register user instance --- .../(dashboard)/admin/site-settings/page.tsx | 9 ++-- .../webhooks/trigger-multiselect-combobox.tsx | 2 +- apps/web/src/instrumentation.ts | 14 +++---- .../lib/server-only/site-settings/schema.ts | 7 +++- .../site-settings/schemas/telemetry.ts | 20 +++++++++ .../site-settings/upsert-site-setting.ts | 2 +- .../telemetry/register-instance.ts | 42 +++++++++++++++++++ ...send-instance-info.ts => send-instance.ts} | 4 +- packages/trpc/server/admin-router/schema.ts | 4 +- packages/tsconfig/process-env.d.ts | 1 + turbo.json | 3 +- 11 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 packages/lib/server-only/site-settings/schemas/telemetry.ts create mode 100644 packages/lib/server-only/telemetry/register-instance.ts rename packages/lib/server-only/telemetry/{send-instance-info.ts => send-instance.ts} (86%) diff --git a/apps/web/src/app/(dashboard)/admin/site-settings/page.tsx b/apps/web/src/app/(dashboard)/admin/site-settings/page.tsx index bffb72ff0..52ab1431a 100644 --- a/apps/web/src/app/(dashboard)/admin/site-settings/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/site-settings/page.tsx @@ -1,12 +1,13 @@ import { getSiteSettings } from '@documenso/lib/server-only/site-settings/get-site-settings'; -import { SITE_SETTINGS_BANNER_ID } from '@documenso/lib/server-only/site-settings/schemas/banner'; +import { + SITE_SETTINGS_BANNER_ID, + ZSiteSettingsBannerSchema, +} from '@documenso/lib/server-only/site-settings/schemas/banner'; import { SettingsHeader } from '~/components/(dashboard)/settings/layout/header'; import { BannerForm } from './banner-form'; -// import { BannerForm } from './banner-form'; - export default async function AdminBannerPage() { const banner = await getSiteSettings().then((settings) => settings.find((setting) => setting.id === SITE_SETTINGS_BANNER_ID), @@ -17,7 +18,7 @@ export default async function AdminBannerPage() {
- +
); diff --git a/apps/web/src/components/(dashboard)/settings/webhooks/trigger-multiselect-combobox.tsx b/apps/web/src/components/(dashboard)/settings/webhooks/trigger-multiselect-combobox.tsx index 5636f1931..badbdc3bf 100644 --- a/apps/web/src/components/(dashboard)/settings/webhooks/trigger-multiselect-combobox.tsx +++ b/apps/web/src/components/(dashboard)/settings/webhooks/trigger-multiselect-combobox.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; -import { WebhookTriggerEvents } from '@prisma/client/'; +import { WebhookTriggerEvents } from '@prisma/client'; import { Check, ChevronsUpDown } from 'lucide-react'; import { toFriendlyWebhookEventName } from '@documenso/lib/universal/webhook/to-friendly-webhook-event-name'; diff --git a/apps/web/src/instrumentation.ts b/apps/web/src/instrumentation.ts index c52d2da15..f4ad8bbe2 100644 --- a/apps/web/src/instrumentation.ts +++ b/apps/web/src/instrumentation.ts @@ -1,9 +1,7 @@ -import { sendInstanceInfo } from '@documenso/lib/server-only/telemetry/send-instance-info'; +import { registerInstance } from '@documenso/lib/server-only/telemetry/register-instance'; -export async function register() { - await sendInstanceInfo({ - uniqueId: '1', - timestamp: new Date(), - version: '1.2.3', - }); -} +export const register = async () => { + if (process.env.NEXT_RUNTIME === 'nodejs') { + await registerInstance(); + } +}; diff --git a/packages/lib/server-only/site-settings/schema.ts b/packages/lib/server-only/site-settings/schema.ts index ff6194219..1a4f78f3b 100644 --- a/packages/lib/server-only/site-settings/schema.ts +++ b/packages/lib/server-only/site-settings/schema.ts @@ -1,9 +1,12 @@ import { z } from 'zod'; import { ZSiteSettingsBannerSchema } from './schemas/banner'; +import { ZSiteSettingsTelemetrySchema } from './schemas/telemetry'; -// TODO: Use `z.union([...])` once we have more than one setting -export const ZSiteSettingSchema = ZSiteSettingsBannerSchema; +export const ZSiteSettingSchema = z.union([ + ZSiteSettingsBannerSchema, + ZSiteSettingsTelemetrySchema, +]); export type TSiteSettingSchema = z.infer; diff --git a/packages/lib/server-only/site-settings/schemas/telemetry.ts b/packages/lib/server-only/site-settings/schemas/telemetry.ts new file mode 100644 index 000000000..2c783c243 --- /dev/null +++ b/packages/lib/server-only/site-settings/schemas/telemetry.ts @@ -0,0 +1,20 @@ +import { nanoid } from 'nanoid'; +import { z } from 'zod'; + +import { ZSiteSettingsBaseSchema } from './_base'; + +export const SITE_SETTINGS_TELEMETRY_ID = 'site.instance-id'; + +export const ZSiteSettingsTelemetrySchema = ZSiteSettingsBaseSchema.extend({ + id: z.literal(SITE_SETTINGS_TELEMETRY_ID), + data: z + .object({ + instanceId: z.string(), + }) + .optional() + .default({ + instanceId: nanoid(), + }), +}); + +export type TSiteSettingsTelemetrySchema = z.infer; diff --git a/packages/lib/server-only/site-settings/upsert-site-setting.ts b/packages/lib/server-only/site-settings/upsert-site-setting.ts index 6fc59b1d1..52c77b390 100644 --- a/packages/lib/server-only/site-settings/upsert-site-setting.ts +++ b/packages/lib/server-only/site-settings/upsert-site-setting.ts @@ -3,7 +3,7 @@ import { prisma } from '@documenso/prisma'; import type { TSiteSettingSchema } from './schema'; export type UpsertSiteSettingOptions = TSiteSettingSchema & { - userId: number; + userId: number | null; }; export const upsertSiteSetting = async ({ diff --git a/packages/lib/server-only/telemetry/register-instance.ts b/packages/lib/server-only/telemetry/register-instance.ts new file mode 100644 index 000000000..ffb082058 --- /dev/null +++ b/packages/lib/server-only/telemetry/register-instance.ts @@ -0,0 +1,42 @@ +import { nanoid } from 'nanoid'; + +import { getSiteSettings } from '../site-settings/get-site-settings'; +import { + SITE_SETTINGS_TELEMETRY_ID, + ZSiteSettingsTelemetrySchema, +} from '../site-settings/schemas/telemetry'; +import { upsertSiteSetting } from '../site-settings/upsert-site-setting'; +import { sendInstance } from './send-instance'; + +export const registerInstance = async () => { + const instanceResponse = await getSiteSettings().then((settings) => + settings.find((setting) => setting.id === SITE_SETTINGS_TELEMETRY_ID), + ); + + const instance = ZSiteSettingsTelemetrySchema.parse(instanceResponse); + + if (!instance) { + const upsert = await upsertSiteSetting({ + data: { + instanceId: nanoid(), + }, + enabled: true, + id: SITE_SETTINGS_TELEMETRY_ID, + userId: null, + }); + + const instance = ZSiteSettingsTelemetrySchema.parse(upsert); + + return await sendInstance({ + uniqueId: instance.data?.instanceId, + timestamp: new Date(), + version: '1.2.3', + }); + } + + return await sendInstance({ + uniqueId: instance.data.instanceId, + timestamp: new Date(), + version: '1.2.3', + }); +}; diff --git a/packages/lib/server-only/telemetry/send-instance-info.ts b/packages/lib/server-only/telemetry/send-instance.ts similarity index 86% rename from packages/lib/server-only/telemetry/send-instance-info.ts rename to packages/lib/server-only/telemetry/send-instance.ts index f9934bbcd..bc4fd9766 100644 --- a/packages/lib/server-only/telemetry/send-instance-info.ts +++ b/packages/lib/server-only/telemetry/send-instance.ts @@ -1,10 +1,10 @@ -export type SendInstanceInfo = { +export type SendInstance = { uniqueId: string; timestamp: Date; version: string; }; -export const sendInstanceInfo = async ({ uniqueId, timestamp, version }: SendInstanceInfo) => { +export const sendInstance = async ({ uniqueId, timestamp, version }: SendInstance) => { const isProduction = process.env.NODE_ENV === 'production'; const isTelemetryDisabled = process.env.DISABLE_TELEMETRY === 'true'; diff --git a/packages/trpc/server/admin-router/schema.ts b/packages/trpc/server/admin-router/schema.ts index 6bb567dbd..cf3c36060 100644 --- a/packages/trpc/server/admin-router/schema.ts +++ b/packages/trpc/server/admin-router/schema.ts @@ -1,7 +1,7 @@ import { Role } from '@prisma/client'; import z from 'zod'; -import { ZSiteSettingSchema } from '@documenso/lib/server-only/site-settings/schema'; +import { ZSiteSettingsBannerSchema } from '@documenso/lib/server-only/site-settings/schemas/banner'; export const ZAdminFindDocumentsQuerySchema = z.object({ term: z.string().optional(), @@ -30,7 +30,7 @@ export type TAdminUpdateRecipientMutationSchema = z.infer< typeof ZAdminUpdateRecipientMutationSchema >; -export const ZAdminUpdateSiteSettingMutationSchema = ZSiteSettingSchema; +export const ZAdminUpdateSiteSettingMutationSchema = ZSiteSettingsBannerSchema; export type TAdminUpdateSiteSettingMutationSchema = z.infer< typeof ZAdminUpdateSiteSettingMutationSchema diff --git a/packages/tsconfig/process-env.d.ts b/packages/tsconfig/process-env.d.ts index 80498f415..6c0761c72 100644 --- a/packages/tsconfig/process-env.d.ts +++ b/packages/tsconfig/process-env.d.ts @@ -70,6 +70,7 @@ declare namespace NodeJS { VERCEL?: string; VERCEL_ENV?: 'production' | 'development' | 'preview'; VERCEL_URL?: string; + NEXT_RUNTIME?: 'nodejs' | 'edge'; DEPLOYMENT_TARGET?: 'webapp' | 'marketing'; FONT_CAVEAT_URI: string; diff --git a/turbo.json b/turbo.json index 783e3ece9..ce5a3d525 100644 --- a/turbo.json +++ b/turbo.json @@ -111,6 +111,7 @@ "E2E_TEST_AUTHENTICATE_USERNAME", "E2E_TEST_AUTHENTICATE_USER_EMAIL", "E2E_TEST_AUTHENTICATE_USER_PASSWORD", - "DISABLE_TELEMETRY" + "DISABLE_TELEMETRY", + "NEXT_RUNTIME" ] }