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)],