Skip to content

feat: Added a Lite bundle excluding Data file manager and Event Processor packages. #699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c49f682
Removed datafile-manager for edge. Still need to remove from unit tests.
yasirfolio3 Aug 16, 2021
d634269
Improvements and fixes for unit tests.
yasirfolio3 Aug 17, 2021
8cf008e
fixes.
yasirfolio3 Aug 17, 2021
a68a918
Added ESM bundle for edge
zashraf1985 Aug 27, 2021
5523f7a
experiment taking out event processor for edge package.
zashraf1985 Aug 30, 2021
77f7a6b
fixed FSC tests
zashraf1985 Aug 31, 2021
1f61a04
reorganized event dispatcher and datafile manager code. Also added fu…
zashraf1985 Sep 1, 2021
69b527d
fixed lint
zashraf1985 Sep 1, 2021
d78a146
Fixed project config manager tests
zashraf1985 Sep 1, 2021
1587eee
Fixed optimizely tests
zashraf1985 Sep 1, 2021
5ed7e07
All unit tests fixed
zashraf1985 Sep 1, 2021
59855e6
fixed umd and cross browser tests
zashraf1985 Sep 2, 2021
8e3db43
renamed bundle to lite
zashraf1985 Sep 3, 2021
c64005e
added unit tests for lite bundle
zashraf1985 Sep 8, 2021
59e9ae9
Added test coverage for httppollingddatafilemanager wrapper
zashraf1985 Sep 8, 2021
0e1dbb6
Added test coverage for no op datafile manager
zashraf1985 Sep 8, 2021
b5c6283
Added unit test coverage for missing utility function
zashraf1985 Sep 8, 2021
753aafe
Added more unit tests
zashraf1985 Sep 8, 2021
5b255a5
incorporated review feedback
zashraf1985 Sep 20, 2021
f6ed35a
Merge branch 'master' into yasir/edge-support-testing
zashraf1985 Sep 20, 2021
b8508cc
updated unit test
zashraf1985 Sep 20, 2021
a9c8865
incorporated more review feedback
zashraf1985 Oct 4, 2021
60ca121
Added missing copyright header
zashraf1985 Oct 4, 2021
b9e8bd5
reverted unneeded formatting changes
zashraf1985 Oct 4, 2021
fe7bcf7
a little cleanup
zashraf1985 Oct 4, 2021
f94e45b
Merge branch 'master' into yasir/edge-support-testing
zashraf1985 Oct 7, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
DECISION_SOURCES,
} from '../../utils/enums';
import { createLogger } from '../../plugins/logger';
import { createForwardingEventProcessor } from '../../plugins/event_processor/forwarding_event_processor';
import { createNotificationCenter } from '../notification_center';
import Optimizely from '../../optimizely';
import projectConfig from '../project_config';
import AudienceEvaluator from '../audience_evaluator';
Expand Down Expand Up @@ -980,7 +982,8 @@ describe('lib/core/decision_service', function() {
jsonSchemaValidator: jsonSchemaValidator,
isValidInstance: true,
logger: createdLogger,
eventDispatcher: eventDispatcher,
eventProcessor: createForwardingEventProcessor(eventDispatcher),
notificationCenter: createNotificationCenter(createdLogger, errorHandler),
errorHandler: errorHandler,
});

Expand Down
267 changes: 267 additions & 0 deletions packages/optimizely-sdk/lib/core/event_builder/build_event_v1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
/**
* Copyright 2021 Optimizely
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a License header

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does event_v1 means?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v1 is the version of event on logx end point

EventTags,
ConversionEvent,
ImpressionEvent,
} from '@optimizely/js-sdk-event-processor';

import { Event } from '../../shared_types';

type ProcessableEvent = ConversionEvent | ImpressionEvent

const ACTIVATE_EVENT_KEY = 'campaign_activated'
const CUSTOM_ATTRIBUTE_FEATURE_TYPE = 'custom'
const BOT_FILTERING_KEY = '$opt_bot_filtering'

export type EventV1 = {
account_id: string
project_id: string
revision: string
client_name: string
client_version: string
anonymize_ip: boolean
enrich_decisions: boolean
visitors: Visitor[]
}

type Visitor = {
snapshots: Snapshot[]
visitor_id: string
attributes: Attribute[]
}

type AttributeType = 'custom'

export type Attribute = {
// attribute id
entity_id: string
// attribute key
key: string
type: AttributeType
value: string | number | boolean
}

export type Snapshot = {
decisions?: Decision[]
events: SnapshotEvent[]
}

type Decision = {
campaign_id: string | null
experiment_id: string | null
variation_id: string | null
metadata: Metadata
}

type Metadata = {
flag_key: string;
rule_key: string;
rule_type: string;
variation_key: string;
enabled: boolean;
}

export type SnapshotEvent = {
entity_id: string | null
timestamp: number
uuid: string
key: string
revenue?: number
value?: number
tags?: EventTags
}

/**
* Given an array of batchable Decision or ConversionEvent events it returns
* a single EventV1 with proper batching
*
* @param {ProcessableEvent[]} events
* @returns {EventV1}
*/
export function makeBatchedEventV1(events: ProcessableEvent[]): EventV1 {
const visitors: Visitor[] = []
const data = events[0]

events.forEach(event => {
if (event.type === 'conversion' || event.type === 'impression') {
const visitor = makeVisitor(event)

if (event.type === 'impression') {
visitor.snapshots.push(makeDecisionSnapshot(event))
} else if (event.type === 'conversion') {
visitor.snapshots.push(makeConversionSnapshot(event))
}

visitors.push(visitor)
}
})

return {
client_name: data.context.clientName,
client_version: data.context.clientVersion,

account_id: data.context.accountId,
project_id: data.context.projectId,
revision: data.context.revision,
anonymize_ip: data.context.anonymizeIP,
enrich_decisions: true,

visitors,
}
}

function makeConversionSnapshot(conversion: ConversionEvent): Snapshot {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assuming this whole code is copied from buildEventV1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes! copied from event processor because we wanted to create a forwarding event processor without importing that package and we still needed this to build the payload.. I know this is not the best way to do it but we plan to consolidate those packages into one anyway. this redundancy will be solved then.

const tags: EventTags = {
...conversion.tags,
}

delete tags['revenue']
delete tags['value']

const event: SnapshotEvent = {
entity_id: conversion.event.id,
key: conversion.event.key,
timestamp: conversion.timestamp,
uuid: conversion.uuid,
}

if (conversion.tags) {
event.tags = conversion.tags
}

if (conversion.value != null) {
event.value = conversion.value
}

if (conversion.revenue != null) {
event.revenue = conversion.revenue
}

return {
events: [event],
}
}

function makeDecisionSnapshot(event: ImpressionEvent): Snapshot {
const { layer, experiment, variation, ruleKey, flagKey, ruleType, enabled } = event
const layerId = layer ? layer.id : null
const experimentId = experiment ? experiment.id : null
const variationId = variation ? variation.id : null
const variationKey = variation ? variation.key : ''

return {
decisions: [
{
campaign_id: layerId,
experiment_id: experimentId,
variation_id: variationId,
metadata: {
flag_key: flagKey,
rule_key: ruleKey,
rule_type: ruleType,
variation_key: variationKey,
enabled: enabled,
},
},
],
events: [
{
entity_id: layerId,
timestamp: event.timestamp,
key: ACTIVATE_EVENT_KEY,
uuid: event.uuid,
},
],
}
}

function makeVisitor(data: ImpressionEvent | ConversionEvent): Visitor {
const visitor: Visitor = {
snapshots: [],
visitor_id: data.user.id,
attributes: [],
}

data.user.attributes.forEach(attr => {
visitor.attributes.push({
entity_id: attr.entityId,
key: attr.key,
type: 'custom' as const, // tell the compiler this is always string "custom"
value: attr.value,
})
})

if (typeof data.context.botFiltering === 'boolean') {
visitor.attributes.push({
entity_id: BOT_FILTERING_KEY,
key: BOT_FILTERING_KEY,
type: CUSTOM_ATTRIBUTE_FEATURE_TYPE,
value: data.context.botFiltering,
})
}
return visitor
}

/**
* Event for usage with v1 logtier
*
* @export
* @interface EventBuilderV1
*/
export function buildImpressionEventV1(data: ImpressionEvent): EventV1 {
const visitor = makeVisitor(data)
visitor.snapshots.push(makeDecisionSnapshot(data))

return {
client_name: data.context.clientName,
client_version: data.context.clientVersion,

account_id: data.context.accountId,
project_id: data.context.projectId,
revision: data.context.revision,
anonymize_ip: data.context.anonymizeIP,
enrich_decisions: true,

visitors: [visitor],
}
}

export function buildConversionEventV1(data: ConversionEvent): EventV1 {
const visitor = makeVisitor(data)
visitor.snapshots.push(makeConversionSnapshot(data))

return {
client_name: data.context.clientName,
client_version: data.context.clientVersion,

account_id: data.context.accountId,
project_id: data.context.projectId,
revision: data.context.revision,
anonymize_ip: data.context.anonymizeIP,
enrich_decisions: true,

visitors: [visitor],
}
}

export function formatEvents(events: ProcessableEvent[]): Event {
return {
url: 'https://logx.optimizely.com/v1/events',
httpVerb: 'POST',
params: makeBatchedEventV1(events),
}
}
Loading