diff --git a/.changeset/perfect-needles-walk.md b/.changeset/perfect-needles-walk.md new file mode 100644 index 00000000..3369c87f --- /dev/null +++ b/.changeset/perfect-needles-walk.md @@ -0,0 +1,7 @@ +--- +'@elbwalker/walker.js': minor +'@elbwalker/client-node': minor +'@elbwalker/types': minor +--- + +Push events via elb (#372)[https://github.com/elbwalker/walkerOS/issues/372] diff --git a/packages/clients/node/src/push.ts b/packages/clients/node/src/push.ts index 1d5bf898..8bba78f6 100644 --- a/packages/clients/node/src/push.ts +++ b/packages/clients/node/src/push.ts @@ -33,12 +33,13 @@ function createEventOrCommand( nameOrEvent: string | WalkerOS.PartialEvent, pushData: unknown, ): { event?: WalkerOS.Event; command?: string } { - let partialEvent: WalkerOS.PartialEvent; - if (isSameType(nameOrEvent, '' as string)) - partialEvent = { event: nameOrEvent }; - else { - partialEvent = nameOrEvent || {}; - } + // Determine the partial event + const partialEvent: WalkerOS.PartialEvent = isSameType( + nameOrEvent, + '' as string, + ) + ? { event: nameOrEvent } + : ((nameOrEvent || {}) as WalkerOS.PartialEvent); if (!partialEvent.event) throw new Error('Event name is required'); @@ -54,16 +55,23 @@ function createEventOrCommand( // Increase event counter ++instance.count; - const timestamp = partialEvent.timestamp || Date.now(); - const group = partialEvent.group || instance.group; - const count = partialEvent.count || instance.count; - const source = partialEvent.source || { - type: 'node', - id: '', - previous_id: '', - }; - - const data = + // Extract properties with default fallbacks + const { + timestamp = Date.now(), + group = instance.group, + count = instance.count, + source = { type: 'node', id: '', previous_id: '' }, + context = {}, + custom = {}, + globals = instance.globals, + user = instance.user, + nested = [], + consent = instance.consent, + trigger = '', + version = { tagging: instance.config.tagging }, + } = partialEvent; + + const data: WalkerOS.Properties = partialEvent.data || (isSameType(pushData, {} as WalkerOS.Properties) ? pushData : {}); @@ -74,13 +82,13 @@ function createEventOrCommand( const event: WalkerOS.Event = { event: `${entity} ${action}`, data, - context: partialEvent.context || {}, - custom: partialEvent.custom || {}, - globals: partialEvent.globals || instance.globals, - user: partialEvent.user || instance.user, - nested: partialEvent.nested || [], - consent: partialEvent.consent || instance.consent, - trigger: partialEvent.trigger || '', + context, + custom, + globals, + user, + nested, + consent, + trigger, entity, action, timestamp, @@ -90,7 +98,7 @@ function createEventOrCommand( id: `${timestamp}-${group}-${count}`, version: { client: instance.client, - tagging: partialEvent.version?.tagging || instance.config.tagging, + tagging: version.tagging, }, source, }; diff --git a/packages/clients/walkerjs/src/__tests__/web-client.test.ts b/packages/clients/walkerjs/src/__tests__/web-client.test.ts index 335f02d8..c797257d 100644 --- a/packages/clients/walkerjs/src/__tests__/web-client.test.ts +++ b/packages/clients/walkerjs/src/__tests__/web-client.test.ts @@ -43,14 +43,14 @@ describe('Walkerjs', () => { expect(w.bar).toBe(instance); }); - test('empty push', () => { + test('push empty', () => { (walkerjs as unknown as string[]).push(); elb(''); elb('entity'); expect(mockDataLayer).toHaveBeenCalledTimes(0); }); - test('regular push', () => { + test('push regular', () => { elb('walker run'); elb('entity action'); @@ -109,6 +109,14 @@ describe('Walkerjs', () => { }); }); + test('push event', () => { + (walkerjs as unknown as string[]).push(); + elb({ event: 'e a', timing: 42 }); + expect(mockDataLayer).toHaveBeenCalledWith( + expect.objectContaining({ event: 'e a', timing: 42, data: {} }), + ); + }); + test('run option', () => { walkerjs = Walkerjs({ run: false }); expect(walkerjs.allowed).toBeFalsy(); diff --git a/packages/clients/walkerjs/src/index.ts b/packages/clients/walkerjs/src/index.ts index bf18331e..032fd865 100644 --- a/packages/clients/walkerjs/src/index.ts +++ b/packages/clients/walkerjs/src/index.ts @@ -183,94 +183,111 @@ export function Walkerjs( nameOrEvent: unknown, pushData: WebClient.PushData, pushContext: WebClient.PushContext, - nested: WalkerOS.Entities, - custom: WalkerOS.Properties, - trigger: WebClient.PushOptions = '', + initialNested: WalkerOS.Entities, + initialCustom: WalkerOS.Properties, + initialTrigger: WebClient.PushOptions = '', ): { event?: WalkerOS.Event; command?: string } { - if (!nameOrEvent || !isSameType(nameOrEvent, '' as string)) return {}; + // Determine the partial event + const partialEvent: WalkerOS.PartialEvent = isSameType( + nameOrEvent, + '' as string, + ) + ? { event: nameOrEvent } + : ((nameOrEvent || {}) as WalkerOS.PartialEvent); + + if (!partialEvent.event) return {}; // Check for valid entity and action event format - const [entity, action] = nameOrEvent.split(' '); + const [entity, action] = partialEvent.event.split(' '); if (!entity || !action) return {}; // It's a walker command if (isCommand(entity)) return { command: action }; // Regular event - // Increase event counter ++instance.count; - const timestamp = Date.now(); - const { group, count } = instance; - const id = `${timestamp}-${group}-${count}`; - const source = { - type: 'web', - id: window.location.href, - previous_id: document.referrer, - }; + // Extract properties with default fallbacks + const { + timestamp = Date.now(), + group = instance.group, + count = instance.count, + source = { + type: 'web', + id: window.location.href, + previous_id: document.referrer, + }, + context = partialEvent.context || {}, + globals = instance.globals, + user = instance.user, + nested = partialEvent.nested || initialNested || [], + consent = instance.consent, + trigger = isSameType(initialTrigger, '') ? initialTrigger : '', + version = { tagging: instance.config.tagging }, + } = partialEvent; // Get data and context either from elements or parameters - let data: WalkerOS.Properties = {}; - let context: WalkerOS.OrderedProperties = {}; + let data: WalkerOS.Properties = + partialEvent.data || + (isSameType(pushData, {} as WalkerOS.Properties) ? pushData : {}); + + let eventContext: WalkerOS.OrderedProperties = context; let elemParameter: undefined | Element; let dataIsElem = false; if (isElementOrDocument(pushData)) { elemParameter = pushData; dataIsElem = true; - } else if (isSameType(pushData, {} as WalkerOS.Properties)) { - data = pushData; } if (isElementOrDocument(pushContext)) { elemParameter = pushContext; } else if (isSameType(pushContext, {} as WalkerOS.OrderedProperties)) { - context = pushContext; + eventContext = pushContext; } if (elemParameter) { - // Filter for the entity type from the events name const entityObj = getEntities(instance.config.prefix, elemParameter).find( (obj) => obj.type == entity, ); - if (entityObj) { if (dataIsElem) data = entityObj.data; - context = entityObj.context; + eventContext = entityObj.context; } } - // Special case for page entity to add the id by default if (entity === 'page') { data.id = data.id || window.location.pathname; } - return { - event: { - event: `${entity} ${action}`, - data, - context, - custom: custom || {}, - globals: instance.globals, - user: instance.user, - nested: nested || [], - consent: instance.consent, - id, - trigger: isSameType(trigger, '') ? trigger : '', - entity, - action, - timestamp, - timing: Math.round((performance.now() - instance.timing) / 10) / 100, - group, - count, - version: { - client: instance.client, - tagging: instance.config.tagging, - }, - source, + const event: WalkerOS.Event = { + event: `${entity} ${action}`, + data, + context: eventContext, + custom: partialEvent.custom || initialCustom || {}, + globals, + user, + nested, + consent, + trigger, + entity, + action, + timestamp, + timing: + partialEvent.timing || + Math.round((performance.now() - instance.timing) / 10) / 100, + group, + count, + id: `${timestamp}-${group}-${count}`, + version: { + client: instance.client, + tagging: version.tagging, }, + source, }; + + return { event }; } function elbLayerInit(instance: WebClient.Instance) { @@ -467,7 +484,7 @@ export function Walkerjs( } function push( - nameOrEvent?: unknown, // @TODO can also be an event object + nameOrEvent?: unknown, pushData: WebClient.PushData = {}, options: WebClient.PushOptions = '', pushContext: WebClient.PushContext = {}, diff --git a/packages/types/src/walkeros.ts b/packages/types/src/walkeros.ts index 38b90435..8b21ebb8 100644 --- a/packages/types/src/walkeros.ts +++ b/packages/types/src/walkeros.ts @@ -53,6 +53,7 @@ export interface Elb { nested?: Entities, custom?: Properties, ): R; + (partialEvent: PartialEvent): R; } export type PushData = string | Partial | Consent | User | Properties;