From a16d768577b88e58b145aac34e5bb96f85566fec Mon Sep 17 00:00:00 2001 From: Yury Saukou Date: Thu, 22 Oct 2026 11:23:47 +0300 Subject: [PATCH] feat(core): support optional project name updates --- packages/core/src/hosted-projects.test.ts | 8 ++++++++ packages/core/src/hosted-projects.ts | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/packages/core/src/hosted-projects.test.ts b/packages/core/src/hosted-projects.test.ts index ca66343..e54cba9 100644 --- a/packages/core/src/hosted-projects.test.ts +++ b/packages/core/src/hosted-projects.test.ts @@ -396,6 +396,14 @@ describe('hosted project contract', () => { }); describe('createLingvaHostedProjectUpdatePayload', () => { + it('normalizes optional names and rejects blank or oversized names', () => { + const project = { projectId: 'demo', defaultLocale: 'en', locales: ['en'] }; + expect(createLingvaHostedProjectUpdatePayload({ ...project, name: ' Mobile app ' }).name).toBe('Mobile app'); + expect(createLingvaHostedProjectUpdatePayload(project)).not.toHaveProperty('name'); + expect(() => createLingvaHostedProjectUpdatePayload({ ...project, name: ' ' })).toThrow(); + expect(() => createLingvaHostedProjectUpdatePayload({ ...project, name: 'x'.repeat(121) })).toThrow(); + }); + it('normalizes a valid locale list and pins the default first', () => { expect( createLingvaHostedProjectUpdatePayload({ diff --git a/packages/core/src/hosted-projects.ts b/packages/core/src/hosted-projects.ts index 2c6f75e..3f020c3 100644 --- a/packages/core/src/hosted-projects.ts +++ b/packages/core/src/hosted-projects.ts @@ -283,6 +283,8 @@ export interface LingvaHostedProjectDeleteInput { } export interface LingvaHostedProjectUpdateInput { + /** Omit to preserve the current display name. Project ID never changes. */ + name?: string; defaultLocale: string; locales: readonly string[]; projectId: string; @@ -999,6 +1001,10 @@ export function normalizeLingvaHostedProjectUpdateInput( ): LingvaHostedProjectUpdateInput { const projectId = normalizeIdentifier(input.projectId, 'projectId', LINGVA_HOSTED_PROJECT_ID_PATTERN); const defaultLocale = normalizeLocaleCode(input.defaultLocale, 'defaultLocale'); + const name = input.name === undefined ? undefined : normalizeRequiredString(input.name, 'name'); + if (name !== undefined && name.length > LINGVA_HOSTED_PROJECT_NAME_MAX_LENGTH) { + throw new Error('Lingva hosted project name is too long.'); + } if (!Array.isArray(input.locales) || input.locales.length === 0) { throw new Error('Lingva hosted project locales must include at least one entry.'); @@ -1020,6 +1026,7 @@ export function normalizeLingvaHostedProjectUpdateInput( } return { + ...(name === undefined ? {} : { name }), projectId, defaultLocale, locales: [defaultLocale, ...locales.filter((locale) => locale !== defaultLocale)],