From 32edb9b501b30ef35e0708d3ec99d7f727dc5655 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 00:05:04 +0000 Subject: [PATCH] Add name truncation for growth server endpoints Co-authored-by: stnguyen90 <1477010+stnguyen90@users.noreply.github.com> --- src/lib/helpers/string.test.ts | 29 ++++++++++++++++++++++- src/lib/helpers/string.ts | 18 ++++++++++++++ src/lib/stores/feedback.ts | 3 ++- src/routes/(console)/supportWizard.svelte | 3 ++- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/lib/helpers/string.test.ts b/src/lib/helpers/string.test.ts index d4c907b1e..8d37f47f9 100644 --- a/src/lib/helpers/string.test.ts +++ b/src/lib/helpers/string.test.ts @@ -1,4 +1,4 @@ -import { singular, camelize, capitalize } from '$lib/helpers/string'; +import { singular, camelize, capitalize, truncateNameForGrowthServer } from '$lib/helpers/string'; import { expect, test } from 'vitest'; /* @@ -97,3 +97,30 @@ test('capitalize should handle strings with no lowercase letters', () => { test('capitalize should handle strings with only one character', () => { expect(capitalize('a')).toBe('A'); }); + +/* +TRUNCATE NAME FOR GROWTH SERVER +*/ + +test('truncateNameForGrowthServer should return the name as-is if it is 40 characters or less', () => { + expect(truncateNameForGrowthServer('John Doe')).toBe('John Doe'); + expect(truncateNameForGrowthServer('A'.repeat(40))).toBe('A'.repeat(40)); + expect(truncateNameForGrowthServer('A'.repeat(39))).toBe('A'.repeat(39)); +}); + +test('truncateNameForGrowthServer should truncate to 37 chars and add ... if name exceeds 40 chars', () => { + const longName = 'A'.repeat(41); + expect(truncateNameForGrowthServer(longName)).toBe('A'.repeat(37) + '...'); + expect(truncateNameForGrowthServer(longName).length).toBe(40); + + const veryLongName = 'John Jacob Jingleheimer Schmidt is a very long name'; + const result = truncateNameForGrowthServer(veryLongName); + expect(result).toBe('John Jacob Jingleheimer Schmidt is a ...'); + expect(result.length).toBe(40); +}); + +test('truncateNameForGrowthServer should return "Unknown" for empty or falsy input', () => { + expect(truncateNameForGrowthServer('')).toBe('Unknown'); + expect(truncateNameForGrowthServer(null)).toBe('Unknown'); + expect(truncateNameForGrowthServer(undefined)).toBe('Unknown'); +}); diff --git a/src/lib/helpers/string.ts b/src/lib/helpers/string.ts index 6f867f86c..7abf2ace2 100644 --- a/src/lib/helpers/string.ts +++ b/src/lib/helpers/string.ts @@ -76,6 +76,24 @@ export const hostnameRegex = String.raw`(\*)|(\*\.)?(?!-)[A-Za-z0-9\-]+([\-\.]{1 */ export const extendedHostnameRegex = String.raw`(\*)|(\*\.)?((?!-)[A-Za-z0-9\-]+([\-\.]{1}[a-z0-9]+)*\.[A-Za-z]{2,18}|localhost|(\d{1,3}\.){3}\d{1,3}|[a-z0-9]{32})`; +/** + * Truncates a name to fit within the 40-character limit required by the growth server. + * If the name exceeds 40 characters, it truncates to 37 characters and appends '...'. + * + * @export + * @param {string} name - The name to truncate. + * @returns {string} The truncated name (max 40 chars). + */ +export function truncateNameForGrowthServer(name: string): string { + if (!name) { + return 'Unknown'; + } + if (name.length > 40) { + return name.slice(0, 37) + '...'; + } + return name; +} + export function hash(input: string | string[], delimiter: string = ','): string { const str = Array.isArray(input) ? input.join(delimiter) : input; let hash = 0; diff --git a/src/lib/stores/feedback.ts b/src/lib/stores/feedback.ts index 8b140c0ca..8159736e4 100644 --- a/src/lib/stores/feedback.ts +++ b/src/lib/stores/feedback.ts @@ -5,6 +5,7 @@ import type { Component } from 'svelte'; import FeedbackGeneral from '$lib/components/feedback/feedbackGeneral.svelte'; import FeedbackNps from '$lib/components/feedback/feedbackNPS.svelte'; import { Submit, trackEvent } from '$lib/actions/analytics'; +import { truncateNameForGrowthServer } from '$lib/helpers/string'; export type Feedback = { elapsed: number; @@ -144,7 +145,7 @@ function createFeedbackStore() { message, email, customFields, - firstname: (name || 'Unknown').slice(0, 40), + firstname: truncateNameForGrowthServer(name || ''), metaFields: { source: get(feedback).source, orgId, diff --git a/src/routes/(console)/supportWizard.svelte b/src/routes/(console)/supportWizard.svelte index 5c7731121..79431b92e 100644 --- a/src/routes/(console)/supportWizard.svelte +++ b/src/routes/(console)/supportWizard.svelte @@ -25,6 +25,7 @@ import { wizard } from '$lib/stores/wizard'; import { VARS } from '$lib/system'; import { IconCheckCircle, IconXCircle, IconInfo } from '@appwrite.io/pink-icons-svelte'; + import { truncateNameForGrowthServer } from '$lib/helpers/string'; let projectOptions = $state>([]); @@ -109,7 +110,7 @@ body: JSON.stringify({ email: $user.email, subject: $supportData.subject, - firstName: ($user?.name || 'Unknown').slice(0, 40), + firstName: truncateNameForGrowthServer($user?.name || ''), message: $supportData.message, tags: [categoryTopicTag], customFields: [