Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions api-docs/docs/browser-tracker/browser-tracker.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,7 @@ export interface ClientSession extends Record<string, unknown> {
}

// @public
export interface CommonEventProperties<T extends {
[_: string]: unknown;
} = Record<string, unknown>> {
export interface CommonEventProperties<T = Record<string, unknown>> {
context?: Array<SelfDescribingJson<T>> | null;
timestamp?: Timestamp | null;
}
Expand Down Expand Up @@ -433,16 +431,14 @@ Array<ContextPrimitive> | ContextPrimitive
];

// @public
export interface SelfDescribingEvent {
event: SelfDescribingJson;
export interface SelfDescribingEvent<T = Record<string, unknown>> {
event: SelfDescribingJson<T>;
}

// @public
export type SelfDescribingJson<T extends {
[_: string]: unknown;
} = Record<string, unknown>> = {
export type SelfDescribingJson<T = Record<string, unknown>> = {
schema: string;
data: T;
data: T extends any[] ? never : T extends {} ? T : never;
};

// @public
Expand Down Expand Up @@ -574,7 +570,7 @@ export interface TrackerCore {
export function trackPageView(event?: PageViewEvent & CommonEventProperties, trackers?: Array<string>): void;

// @public
export function trackSelfDescribingEvent(event: SelfDescribingEvent & CommonEventProperties, trackers?: Array<string>): void;
export function trackSelfDescribingEvent<T = Record<string, unknown>>(event: SelfDescribingEvent<T> & CommonEventProperties, trackers?: Array<string>): void;

// @public
export function trackStructEvent(event: StructuredEvent & CommonEventProperties, trackers?: Array<string>): void;
Expand Down
12 changes: 5 additions & 7 deletions api-docs/docs/node-tracker/node-tracker.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export function buildRemoveFromCart(event: RemoveFromCartEvent): PayloadBuilder;
export function buildScreenView(event: ScreenViewEvent): PayloadBuilder;

// @public
export function buildSelfDescribingEvent(event: SelfDescribingEvent): PayloadBuilder;
export function buildSelfDescribingEvent<T = Record<string, unknown>>(event: SelfDescribingEvent<T>): PayloadBuilder;

// @public
export function buildSiteSearch(event: SiteSearchEvent): PayloadBuilder;
Expand Down Expand Up @@ -459,16 +459,14 @@ export interface ScreenViewEvent {
}

// @public
export interface SelfDescribingEvent {
event: SelfDescribingJson;
export interface SelfDescribingEvent<T = Record<string, unknown>> {
event: SelfDescribingJson<T>;
}

// @public
export type SelfDescribingJson<T extends {
[_: string]: unknown;
} = Record<string, unknown>> = {
export type SelfDescribingJson<T = Record<string, unknown>> = {
schema: string;
data: T;
data: T extends any[] ? never : T extends {} ? T : never;
};

// @public
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@snowplow/browser-plugin-snowplow-ecommerce",
"comment": "",
"type": "none"
}
],
"packageName": "@snowplow/browser-plugin-snowplow-ecommerce"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@snowplow/tracker-core",
"comment": "Fix regression in SelfDescribingJson type from #1330",
"type": "none"
}
],
"packageName": "@snowplow/tracker-core"
}
12 changes: 8 additions & 4 deletions libraries/tracker-core/src/contexts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,9 @@ export interface PluginContexts {
/**
* Returns list of contexts from all active plugins
*/
addPluginContexts: (additionalContexts?: SelfDescribingJson[] | null) => SelfDescribingJson[];
addPluginContexts: <T = Record<string, unknown>>(
additionalContexts?: SelfDescribingJson<T>[] | null
) => SelfDescribingJson[];
}

export function pluginContexts(plugins: Array<CorePlugin>): PluginContexts {
Expand All @@ -257,8 +259,10 @@ export function pluginContexts(plugins: Array<CorePlugin>): PluginContexts {
* @returns userContexts combined with commonContexts
*/
return {
addPluginContexts: (additionalContexts?: SelfDescribingJson[] | null): SelfDescribingJson[] => {
const combinedContexts: SelfDescribingJson[] = additionalContexts ? [...additionalContexts] : [];
addPluginContexts: <T = Record<string, unknown>>(additionalContexts?: SelfDescribingJson<T>[] | null) => {
const combinedContexts: SelfDescribingJson<T | Record<string, unknown>>[] = additionalContexts
? [...additionalContexts]
: [];

plugins.forEach((plugin) => {
try {
Expand All @@ -270,7 +274,7 @@ export function pluginContexts(plugins: Array<CorePlugin>): PluginContexts {
}
});

return combinedContexts;
return combinedContexts as SelfDescribingJson[];
},
};
}
Expand Down
18 changes: 9 additions & 9 deletions libraries/tracker-core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import { LOG } from './logger';
* Export interface for any Self-Describing JSON such as context or Self Describing events
* @typeParam T - The type of the data object within a SelfDescribingJson
*/
export type SelfDescribingJson<T extends { [_: string]: unknown } = Record<string, unknown>> = {
export type SelfDescribingJson<T = Record<string, unknown>> = {
/**
* The schema string
* @example 'iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0'
Expand All @@ -54,14 +54,14 @@ export type SelfDescribingJson<T extends { [_: string]: unknown } = Record<strin
/**
* The data object which should conform to the supplied schema
*/
data: T;
data: T extends any[] ? never : T extends {} ? T : never;
};

/**
* Export interface for any Self-Describing JSON which has the data attribute as an array
* @typeParam T - The type of the data object within the SelfDescribingJson data array
*/
export type SelfDescribingJsonArray<T extends { [_: string]: unknown } = Record<string, unknown>> = {
export type SelfDescribingJsonArray<T = Record<string, unknown>> = {
/**
* The schema string
* @example 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-1'
Expand Down Expand Up @@ -119,7 +119,7 @@ function getTimestamp(timestamp?: Timestamp | null): TimestampPayload {
}

/** Additional data points to set when tracking an event */
export interface CommonEventProperties<T extends { [_: string]: unknown } = Record<string, unknown>> {
export interface CommonEventProperties<T = Record<string, unknown>> {
/** Add context to an event by setting an Array of Self Describing JSON */
context?: Array<SelfDescribingJson<T>> | null;
/** Set the true timestamp or overwrite the device sent timestamp on an event */
Expand Down Expand Up @@ -382,9 +382,9 @@ export function trackerCore(configuration: CoreConfiguration = {}): TrackerCore
* @param timestamp - Timestamp of the event
* @returns Payload after the callback is applied or undefined if the event is skipped
*/
function track(
function track<C = Record<string, unknown>>(
pb: PayloadBuilder,
context?: Array<SelfDescribingJson> | null,
context?: Array<SelfDescribingJson<C>> | null,
timestamp?: Timestamp | null
): Payload | undefined {
pb.withJsonProcessor(payloadJsonProcessor(encodeBase64));
Expand Down Expand Up @@ -565,9 +565,9 @@ export function trackerCore(configuration: CoreConfiguration = {}): TrackerCore
* A custom event type, allowing for an event to be tracked using your own custom schema
* and a data object which conforms to the supplied schema
*/
export interface SelfDescribingEvent {
export interface SelfDescribingEvent<T = Record<string, unknown>> {
/** The Self Describing JSON which describes the event */
event: SelfDescribingJson;
event: SelfDescribingJson<T>;
}

/**
Expand All @@ -578,7 +578,7 @@ export interface SelfDescribingEvent {
* @param event - Contains the properties and schema location for the event
* @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track}
*/
export function buildSelfDescribingEvent(event: SelfDescribingEvent): PayloadBuilder {
export function buildSelfDescribingEvent<T = Record<string, unknown>>(event: SelfDescribingEvent<T>): PayloadBuilder {
const {
event: { schema, data },
} = event,
Expand Down
7 changes: 3 additions & 4 deletions plugins/browser-plugin-snowplow-ecommerce/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommonEventProperties, SelfDescribingJson } from '@snowplow/tracker-core';
import { CommonEventProperties } from '@snowplow/tracker-core';

/**
* Type/Schema for an ecommerce Action
Expand Down Expand Up @@ -317,10 +317,9 @@ export interface User {
email?: string;
}

export interface CommonEcommerceEventProperties<T extends { [_: string]: unknown } = Record<string, unknown>>
extends CommonEventProperties<T> {
export interface CommonEcommerceEventProperties<T = Record<string, unknown>> extends CommonEventProperties<T> {
/** Add context to an event by setting an Array of Self Describing JSON */
context?: Array<SelfDescribingJson<T>>;
context?: Exclude<CommonEventProperties<T>['context'], null>;
}

export type ListViewEvent = { name: string; products: Product[] };
Expand Down
5 changes: 4 additions & 1 deletion trackers/browser-tracker/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,10 @@ export function trackStructEvent(event: StructuredEvent & CommonEventProperties,
* @param event - The event information
* @param trackers - The tracker identifiers which the event will be sent to
*/
export function trackSelfDescribingEvent(event: SelfDescribingEvent & CommonEventProperties, trackers?: Array<string>) {
export function trackSelfDescribingEvent<T = Record<string, unknown>>(
event: SelfDescribingEvent<T> & CommonEventProperties,
trackers?: Array<string>
) {
dispatchToTrackers(trackers, (t) => {
t.core.track(buildSelfDescribingEvent({ event: event.event }), event.context, event.timestamp);
});
Expand Down
82 changes: 82 additions & 0 deletions trackers/browser-tracker/test/snowtype.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
describe('Snowtype compat', () => {
it('pass if this snowtype-generated file passes typechecks', () => {});
});
// generated with Snowtype v0.8.4, package import on below line needs to be updated to '../src'

import { trackSelfDescribingEvent, CommonEventProperties, SelfDescribingJson } from '../src';
// Automatically generated by Snowtype

/**
* Schema for an example event
*/
export type SubscriptionFunnel = {
/**
* the action of the funnel step
*/
action?: null | string;
/**
* the number of the funnel step
*/
step: number;
/**
* the type of subscription the user is signing up to
*/
subscription_type?: null | string;
};

/**
* Creates a Snowplow Event Specification entity.
*/
export function createEventSpecification(eventSpecification: EventSpecification) {
return {
schema: 'iglu:com.snowplowanalytics.snowplow/event_specification/jsonschema/1-0-2',
data: eventSpecification,
};
}

/**
* Automatically attached context for event specifications
*/
interface EventSpecification {
id: string;
name: string;
data_product_id: string;
data_product_name: string;
}

type ContextsOrTimestamp<T = any> = Omit<CommonEventProperties<T>, 'context'> & {
context?: SelfDescribingJson<T>[] | null | undefined;
};
/**
* Track a Snowplow event for SubscriptionFunnel.
* Schema for an example event
*/
export function trackSubscriptionFunnel<T extends {} = any>(
subscriptionFunnel: SubscriptionFunnel & ContextsOrTimestamp<T>,
trackers?: string[]
) {
const { context, timestamp, ...data } = subscriptionFunnel;
const event: SelfDescribingJson<typeof data> = {
schema: 'iglu:com.example/subscription_funnel/jsonschema/1-0-0',
data,
};

trackSelfDescribingEvent(
{
event,
context,
timestamp,
},
trackers
);
}

/**
* Creates a Snowplow SubscriptionFunnel entity.
*/
export function createSubscriptionFunnel(subscriptionFunnel: SubscriptionFunnel) {
return {
schema: 'iglu:com.example/subscription_funnel/jsonschema/1-0-0',
data: subscriptionFunnel,
};
}
86 changes: 86 additions & 0 deletions trackers/node-tracker/test/snowtype.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import test from 'ava';
test('pass if this snowtype-generated file passes typechecks', () => {});
// generated with Snowtype v0.8.4, package import on below line needs to be updated to '../src'

import { buildSelfDescribingEvent, SelfDescribingJson, Timestamp, Tracker } from '../src';
// Automatically generated by Snowtype

/**
* Schema for an example event
*/
export type SubscriptionFunnel = {
/**
* the action of the funnel step
*/
action?: null | string;
/**
* the number of the funnel step
*/
step: number;
/**
* the type of subscription the user is signing up to
*/
subscription_type?: null | string;
};

interface CommonEventProperties<T = Record<string, unknown>> {
/** Add context to an event by setting an Array of Self Describing JSON */
context?: Array<SelfDescribingJson<T>> | null;
/** Set the true timestamp or overwrite the device sent timestamp on an event */
timestamp?: Timestamp | null;
}

/**
* Creates a Snowplow Event Specification entity.
*/
export function createEventSpecification(eventSpecification: EventSpecification) {
return {
schema: 'iglu:com.snowplowanalytics.snowplow/event_specification/jsonschema/1-0-2',
data: eventSpecification,
};
}

/**
* Automatically attached context for event specifications
*/
interface EventSpecification {
id: string;
name: string;
data_product_id: string;
data_product_name: string;
}

type ContextsOrTimestamp<T = any> = Omit<CommonEventProperties<T>, 'context'> & {
context?: SelfDescribingJson<T>[] | null | undefined;
};

/**
* Track a Snowplow event for SubscriptionFunnel.
* Schema for an example event
*/
export function trackSubscriptionFunnel<T extends {} = any>(
tracker: Tracker,
subscriptionFunnel: SubscriptionFunnel & ContextsOrTimestamp<T>
) {
const { context, timestamp, ...data } = subscriptionFunnel;
tracker.track(
buildSelfDescribingEvent({
event: {
schema: 'iglu:com.example/subscription_funnel/jsonschema/1-0-0',
data,
},
}),
context,
timestamp
);
}

/**
* Creates a Snowplow SubscriptionFunnel entity.
*/
export function createSubscriptionFunnel(subscriptionFunnel: SubscriptionFunnel) {
return {
schema: 'iglu:com.example/subscription_funnel/jsonschema/1-0-0',
data: subscriptionFunnel,
};
}