diff --git a/packages/app/src/cli/models/extensions/schemas.test.ts b/packages/app/src/cli/models/extensions/schemas.test.ts index e4244c98a03..dc65bd10ce5 100644 --- a/packages/app/src/cli/models/extensions/schemas.test.ts +++ b/packages/app/src/cli/models/extensions/schemas.test.ts @@ -1,4 +1,4 @@ -import {BaseSchema, MAX_UID_LENGTH} from './schemas.js' +import {BaseSchema, MAX_UID_LENGTH, NewExtensionPointsSchema} from './schemas.js' import {describe, expect, test} from 'vitest' const validUIDTestCases = [ @@ -29,6 +29,49 @@ const invalidUIDTestCases = [ ['-----', "UID can't start or end with a hyphen"], ] +describe('NewExtensionPointsSchema', () => { + const extensionPoint = { + target: 'pos.app.ready.data', + module: './src/index.ts', + } + + test('accepts free-form intercept event names for Core to validate', () => { + const result = NewExtensionPointsSchema.safeParse([ + { + ...extensionPoint, + capabilities: {intercepts: ['beforecheckout', 'future:event']}, + }, + ]) + + expect(result.success).toBe(true) + }) + + test('rejects non-string intercept event names', () => { + const result = NewExtensionPointsSchema.safeParse([ + { + ...extensionPoint, + capabilities: {intercepts: ['beforecheckout', 1]}, + }, + ]) + + expect(result.success).toBe(false) + }) + + test('rejects duplicate intercept event names', () => { + const result = NewExtensionPointsSchema.safeParse([ + { + ...extensionPoint, + capabilities: {intercepts: ['beforecheckout', 'beforecheckout']}, + }, + ]) + + expect(result.success).toBe(false) + if (!result.success) { + expect(result.error.issues[0]?.message).toBe('Intercept events must be unique: beforecheckout') + } + }) +}) + describe('UIDSchema', () => { describe('valid UIDs', () => { test.each(validUIDTestCases)('accepts %s (%s)', (uid) => { diff --git a/packages/app/src/cli/models/extensions/schemas.ts b/packages/app/src/cli/models/extensions/schemas.ts index 04978437b76..1a0feabd55c 100644 --- a/packages/app/src/cli/models/extensions/schemas.ts +++ b/packages/app/src/cli/models/extensions/schemas.ts @@ -37,8 +37,19 @@ export const ExtensionsArraySchema = zod.object({ extensions: zod.array(zod.any()).optional(), }) +const InterceptEventsSchema = zod.array(zod.string()).superRefine((events, context) => { + const duplicates = [...new Set(events.filter((event, index) => events.indexOf(event) !== index))] + if (duplicates.length > 0) { + context.addIssue({ + code: zod.ZodIssueCode.custom, + message: `Intercept events must be unique: ${duplicates.join(', ')}`, + }) + } +}) + const TargetCapabilitiesSchema = zod.object({ allow_direct_linking: zod.boolean().optional(), + intercepts: InterceptEventsSchema.optional(), }) const ShouldRenderSchema = zod.object({