From b80d8f950f4b5bcfa0f39d96820a5125f1e32aaf Mon Sep 17 00:00:00 2001 From: iraklikori Date: Tue, 26 Sep 2023 00:25:45 +0400 Subject: [PATCH 1/8] leave only needed changes and update makefile --- packages/browser/Makefile | 12 ++++++++++++ packages/browser/package.json | 2 +- packages/browser/src/browser/index.ts | 5 ++--- packages/browser/src/core/constants/index.ts | 2 +- packages/browser/src/lib/global-analytics-helper.ts | 2 +- packages/browser/src/plugins/segmentio/index.ts | 5 ++--- packages/browser/src/plugins/segmentio/normalize.ts | 2 ++ 7 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/browser/Makefile b/packages/browser/Makefile index 4a313041c..530e5bb49 100644 --- a/packages/browser/Makefile +++ b/packages/browser/Makefile @@ -25,6 +25,18 @@ clean: ## Clean the build directory rm -rf dist generated .PHONY: clean +attribution: ## Replaces cookie names in the standalone build and remove last line + @gsed -i 's/\"ajs_group_id\"/\"_attrg\"/g' ./dist/umd/standalone.js + @gsed -i 's/\"ajs_group_properties\"/\"attr_group_properties\"/g' ./dist/umd/standalone.js + @gsed -i 's/\"ajs_user_id\"/\"_attru\"/g' ./dist/umd/standalone.js + @gsed -i 's/\"ajs_user\"/\"none\"/g' ./dist/umd/standalone.js + @gsed -i 's/\"ajs_user_traits\"/\"attr_user_traits\"/g' ./dist/umd/standalone.js + @gsed -i 's/\"ajs_anonymous_id\"/\"_attrb\"/g' ./dist/umd/standalone.js + @gsed -i 's/\"_sio\"/\"_attrb\"/g' ./dist/umd/standalone.js + @gsed -i 's/\"analytics.js\"/\"attribution.js\"/g' ./dist/umd/standalone.js + @gsed -i 's/\/\/# sourceMappingURL=standalone.js.map//g' ./dist/umd/standalone.js +.PHONY: attribution + ## Test Commands tdd: node_modules ## Runs unit tests in watch mode diff --git a/packages/browser/package.json b/packages/browser/package.json index e2df1c8fc..d33f61f9a 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -33,7 +33,7 @@ "jest": "yarn run -T jest", "concurrently": "yarn run -T concurrently", "watch": "yarn concurrently 'NODE_ENV=production WATCH=true yarn umd --watch' 'yarn pkg --watch'", - "build": "yarn clean && yarn build-prep && yarn concurrently 'NODE_ENV=production yarn umd' 'yarn pkg' 'yarn cjs'", + "build": "yarn clean && yarn build-prep && NODE_ENV=production yarn umd && yarn pkg && yarn cjs && make attribution", "release:cdn": "yarn . build && NODE_ENV=production bash scripts/release.sh && NODE_ENV=stage bash scripts/release.sh", "pkg": "yarn tsc -p tsconfig.build.json", "cjs": "yarn tsc -p tsconfig.build.json --outDir ./dist/cjs --module commonjs", diff --git a/packages/browser/src/browser/index.ts b/packages/browser/src/browser/index.ts index 1c59af549..4a9f27e49 100644 --- a/packages/browser/src/browser/index.ts +++ b/packages/browser/src/browser/index.ts @@ -267,6 +267,7 @@ async function registerPlugins( if (!shouldIgnoreSegmentio) { toRegister.push( await segmentio( + writeKey, analytics, mergedSettings['Segment.io'] as SegmentioSettings, legacySettings.integrations @@ -309,9 +310,7 @@ async function loadAnalytics( // this is an ugly side-effect, but it's for the benefits of the plugins that get their cdn via getCDN() if (settings.cdnURL) setGlobalCDNUrl(settings.cdnURL) - let legacySettings = - settings.cdnSettings ?? - (await loadLegacySettings(settings.writeKey, settings.cdnURL)) + let legacySettings: any = { integrations: {} } if (options.updateCDNSettings) { legacySettings = options.updateCDNSettings(legacySettings) diff --git a/packages/browser/src/core/constants/index.ts b/packages/browser/src/core/constants/index.ts index dfb7ff833..b7b1aa4b9 100644 --- a/packages/browser/src/core/constants/index.ts +++ b/packages/browser/src/core/constants/index.ts @@ -1 +1 @@ -export const SEGMENT_API_HOST = 'api.segment.io/v1' +export const SEGMENT_API_HOST = 'api.attributionapp.com/v1' diff --git a/packages/browser/src/lib/global-analytics-helper.ts b/packages/browser/src/lib/global-analytics-helper.ts index 6ea1be085..ebed1077c 100644 --- a/packages/browser/src/lib/global-analytics-helper.ts +++ b/packages/browser/src/lib/global-analytics-helper.ts @@ -3,7 +3,7 @@ import { AnalyticsSnippet } from '../browser/standalone-interface' /** * Stores the global window analytics key */ -let _globalAnalyticsKey = 'analytics' +let _globalAnalyticsKey = 'attribution' /** * Gets the global analytics/buffer diff --git a/packages/browser/src/plugins/segmentio/index.ts b/packages/browser/src/plugins/segmentio/index.ts index 2dc8b2967..e17d443bb 100644 --- a/packages/browser/src/plugins/segmentio/index.ts +++ b/packages/browser/src/plugins/segmentio/index.ts @@ -53,6 +53,7 @@ function onAlias(analytics: Analytics, json: JSON): JSON { } export async function segmentio( + writeKey: string, analytics: Analytics, settings?: SegmentioSettings, integrations?: LegacySettings['integrations'] @@ -64,8 +65,6 @@ export async function segmentio( inflightEvents.clear() }) - const writeKey = settings?.apiKey ?? '' - const buffer = analytics.options.disableClientPersistence ? new PriorityQueue(analytics.queue.queue.maxAttempts, []) : new PersistedPriorityQueue( @@ -124,7 +123,7 @@ export async function segmentio( return client .dispatch( `${remote}/${path}`, - normalize(analytics, json, settings, integrations) + normalize(writeKey, analytics, json, settings, integrations) ) .then(() => ctx) .catch(() => { diff --git a/packages/browser/src/plugins/segmentio/normalize.ts b/packages/browser/src/plugins/segmentio/normalize.ts index afb22cf3d..ea89f45b5 100644 --- a/packages/browser/src/plugins/segmentio/normalize.ts +++ b/packages/browser/src/plugins/segmentio/normalize.ts @@ -4,6 +4,7 @@ import { SegmentFacade } from '../../lib/to-facade' import { SegmentioSettings } from './index' export function normalize( + writeKey: string, analytics: Analytics, json: ReturnType, settings?: SegmentioSettings, @@ -14,6 +15,7 @@ export function normalize( delete json.options json.writeKey = settings?.apiKey + json.projectId = writeKey json.userId = json.userId || user.id() json.anonymousId = json.anonymousId || user.anonymousId() From e2d9272f4d18ca00ad37e70c721712489c5ae362 Mon Sep 17 00:00:00 2001 From: iraklikori Date: Tue, 26 Sep 2023 01:25:42 +0400 Subject: [PATCH 2/8] make it work with old snippet --- packages/browser/src/browser/standalone-analytics.ts | 10 ++-------- packages/browser/src/lib/global-analytics-helper.ts | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/browser/src/browser/standalone-analytics.ts b/packages/browser/src/browser/standalone-analytics.ts index b4f52c9c1..e0592805f 100644 --- a/packages/browser/src/browser/standalone-analytics.ts +++ b/packages/browser/src/browser/standalone-analytics.ts @@ -47,14 +47,8 @@ function getWriteKey(): string | undefined { } export async function install(): Promise { - const writeKey = getWriteKey() - const options = getGlobalAnalytics()?._loadOptions ?? {} - if (!writeKey) { - console.error( - 'Failed to load Write Key. Make sure to use the latest version of the Segment snippet, which can be found in your source settings.' - ) - return - } + const options: any = getGlobalAnalytics()?._loadOptions ?? {} + const writeKey = getWriteKey() || options.projectId setGlobalAnalytics( (await AnalyticsBrowser.standalone(writeKey, options)) as AnalyticsSnippet diff --git a/packages/browser/src/lib/global-analytics-helper.ts b/packages/browser/src/lib/global-analytics-helper.ts index ebed1077c..b774d51ad 100644 --- a/packages/browser/src/lib/global-analytics-helper.ts +++ b/packages/browser/src/lib/global-analytics-helper.ts @@ -3,7 +3,7 @@ import { AnalyticsSnippet } from '../browser/standalone-interface' /** * Stores the global window analytics key */ -let _globalAnalyticsKey = 'attribution' +let _globalAnalyticsKey = 'Attribution' /** * Gets the global analytics/buffer From fa3749cfb49401bee24372887f420c57e9480f48 Mon Sep 17 00:00:00 2001 From: iraklikori Date: Tue, 26 Sep 2023 01:46:34 +0400 Subject: [PATCH 3/8] make it cleaner --- packages/browser/src/browser/index.ts | 9 ++------- packages/browser/src/plugins/segmentio/index.ts | 7 ++++--- packages/browser/src/plugins/segmentio/normalize.ts | 8 +++----- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/packages/browser/src/browser/index.ts b/packages/browser/src/browser/index.ts index 4a9f27e49..b9815269e 100644 --- a/packages/browser/src/browser/index.ts +++ b/packages/browser/src/browser/index.ts @@ -16,7 +16,7 @@ import { RemotePlugin, } from '../plugins/remote-loader' import type { RoutingRule } from '../plugins/routing-middleware' -import { segmentio, SegmentioSettings } from '../plugins/segmentio' +import { segmentio } from '../plugins/segmentio' import { validation } from '../plugins/validation' import { AnalyticsBuffered, @@ -266,12 +266,7 @@ async function registerPlugins( if (!shouldIgnoreSegmentio) { toRegister.push( - await segmentio( - writeKey, - analytics, - mergedSettings['Segment.io'] as SegmentioSettings, - legacySettings.integrations - ) + await segmentio(analytics, options, legacySettings.integrations) ) } diff --git a/packages/browser/src/plugins/segmentio/index.ts b/packages/browser/src/plugins/segmentio/index.ts index e17d443bb..62a53460c 100644 --- a/packages/browser/src/plugins/segmentio/index.ts +++ b/packages/browser/src/plugins/segmentio/index.ts @@ -53,9 +53,8 @@ function onAlias(analytics: Analytics, json: JSON): JSON { } export async function segmentio( - writeKey: string, analytics: Analytics, - settings?: SegmentioSettings, + settings?: any, integrations?: LegacySettings['integrations'] ): Promise { // Attach `pagehide` before buffer is created so that inflight events are added @@ -65,6 +64,8 @@ export async function segmentio( inflightEvents.clear() }) + const writeKey = settings?.apiKey ?? '' + const buffer = analytics.options.disableClientPersistence ? new PriorityQueue(analytics.queue.queue.maxAttempts, []) : new PersistedPriorityQueue( @@ -123,7 +124,7 @@ export async function segmentio( return client .dispatch( `${remote}/${path}`, - normalize(writeKey, analytics, json, settings, integrations) + normalize(analytics, json, settings, integrations) ) .then(() => ctx) .catch(() => { diff --git a/packages/browser/src/plugins/segmentio/normalize.ts b/packages/browser/src/plugins/segmentio/normalize.ts index ea89f45b5..2d12b8dfd 100644 --- a/packages/browser/src/plugins/segmentio/normalize.ts +++ b/packages/browser/src/plugins/segmentio/normalize.ts @@ -1,13 +1,11 @@ import { Analytics } from '../../core/analytics' import { LegacySettings } from '../../browser' import { SegmentFacade } from '../../lib/to-facade' -import { SegmentioSettings } from './index' export function normalize( - writeKey: string, analytics: Analytics, json: ReturnType, - settings?: SegmentioSettings, + settings?: any, integrations?: LegacySettings['integrations'] ): object { const user = analytics.user() @@ -15,7 +13,7 @@ export function normalize( delete json.options json.writeKey = settings?.apiKey - json.projectId = writeKey + json.projectId = settings?.projectId json.userId = json.userId || user.id() json.anonymousId = json.anonymousId || user.anonymousId() @@ -55,7 +53,7 @@ export function normalize( const bundledConfigIds: string[] = [] bundled.sort().forEach((name) => { - ;(configIds[name] ?? []).forEach((id) => { + ;(configIds[name] ?? []).forEach((id: any) => { bundledConfigIds.push(id) }) }) From a1b9bfba6efbe5b1c3023a5aff7e34aef74d1a2a Mon Sep 17 00:00:00 2001 From: iraklikori Date: Thu, 12 Oct 2023 01:33:13 +0400 Subject: [PATCH 4/8] commit --- packages/browser/src/browser/index.ts | 5 +++++ packages/browser/src/core/analytics/index.ts | 1 + .../attribution/attribution-integrations.ts | 21 +++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 packages/browser/src/plugins/attribution/attribution-integrations.ts diff --git a/packages/browser/src/browser/index.ts b/packages/browser/src/browser/index.ts index b9815269e..29f1fc34a 100644 --- a/packages/browser/src/browser/index.ts +++ b/packages/browser/src/browser/index.ts @@ -31,6 +31,7 @@ import { ClassicIntegrationSource } from '../plugins/ajs-destination/types' import { attachInspector } from '../core/inspector' import { Stats } from '../core/stats' import { setGlobalAnalyticsKey } from '../lib/global-analytics-helper' +import { addAtbIntegrations } from '../plugins/attribution/attribution-integrations' export interface LegacyIntegrationConfiguration { /* @deprecated - This does not indicate browser types anymore */ @@ -337,6 +338,10 @@ async function loadAnalytics( classicIntegrations ) + if (options.atb_integrations) { + addAtbIntegrations(options.atb_integrations) + } + const search = window.location.search ?? '' const hash = window.location.hash ?? '' diff --git a/packages/browser/src/core/analytics/index.ts b/packages/browser/src/core/analytics/index.ts index 8b88630c8..af0a4956e 100644 --- a/packages/browser/src/core/analytics/index.ts +++ b/packages/browser/src/core/analytics/index.ts @@ -104,6 +104,7 @@ export interface InitOptions { plan?: Plan retryQueue?: boolean obfuscate?: boolean + atb_integrations?: Integrations /** * This callback allows you to update/mutate CDN Settings. * This is called directly after settings are fetched from the CDN. diff --git a/packages/browser/src/plugins/attribution/attribution-integrations.ts b/packages/browser/src/plugins/attribution/attribution-integrations.ts new file mode 100644 index 000000000..a1f93f8c5 --- /dev/null +++ b/packages/browser/src/plugins/attribution/attribution-integrations.ts @@ -0,0 +1,21 @@ +import { loadScript } from '../../lib/load-script' + +async function loadIntegration(name: string, params: any) { + if (params) console.log(params, name) + + const path = 'https://cdn.jsdelivr.net/gh/ugran/JsDelivr@main' + const fullPath = `${path}/${name}.js` + + try { + await loadScript(fullPath) + } catch (err) { + console.log(err) + } +} + +export function addAtbIntegrations(integrations: any) { + Object.keys(integrations).forEach(async (key) => { + const params = integrations[key] + await loadIntegration(key, params) + }) +} From d148d61fc236078d75dfd0297a61e3c1c4fa8d33 Mon Sep 17 00:00:00 2001 From: iraklikori Date: Thu, 12 Oct 2023 01:42:47 +0400 Subject: [PATCH 5/8] rename to atbIntegrations --- packages/browser/src/browser/index.ts | 4 ++-- packages/browser/src/core/analytics/index.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/browser/src/browser/index.ts b/packages/browser/src/browser/index.ts index 29f1fc34a..104f416b6 100644 --- a/packages/browser/src/browser/index.ts +++ b/packages/browser/src/browser/index.ts @@ -338,8 +338,8 @@ async function loadAnalytics( classicIntegrations ) - if (options.atb_integrations) { - addAtbIntegrations(options.atb_integrations) + if (options.atbIntegrations) { + addAtbIntegrations(options.atbIntegrations) } const search = window.location.search ?? '' diff --git a/packages/browser/src/core/analytics/index.ts b/packages/browser/src/core/analytics/index.ts index af0a4956e..fd3853d9f 100644 --- a/packages/browser/src/core/analytics/index.ts +++ b/packages/browser/src/core/analytics/index.ts @@ -104,7 +104,7 @@ export interface InitOptions { plan?: Plan retryQueue?: boolean obfuscate?: boolean - atb_integrations?: Integrations + atbIntegrations?: Integrations /** * This callback allows you to update/mutate CDN Settings. * This is called directly after settings are fetched from the CDN. From 5dc3511e623e36ab0bbef74955ac6e743c0d6590 Mon Sep 17 00:00:00 2001 From: iraklikori Date: Fri, 20 Oct 2023 17:37:33 +0400 Subject: [PATCH 6/8] change integration scripts path --- .../browser/src/plugins/attribution/attribution-integrations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser/src/plugins/attribution/attribution-integrations.ts b/packages/browser/src/plugins/attribution/attribution-integrations.ts index a1f93f8c5..21de7a1d5 100644 --- a/packages/browser/src/plugins/attribution/attribution-integrations.ts +++ b/packages/browser/src/plugins/attribution/attribution-integrations.ts @@ -3,7 +3,7 @@ import { loadScript } from '../../lib/load-script' async function loadIntegration(name: string, params: any) { if (params) console.log(params, name) - const path = 'https://cdn.jsdelivr.net/gh/ugran/JsDelivr@main' + const path = 'https://scripts.attributionapp.com/v3' const fullPath = `${path}/${name}.js` try { From a2b46537856c5cf1c1548beb70da5bcf9f4f4f70 Mon Sep 17 00:00:00 2001 From: iraklikori Date: Fri, 8 Mar 2024 01:58:35 +0400 Subject: [PATCH 7/8] change host url to track.attributionapp.com --- packages/browser/src/core/constants/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser/src/core/constants/index.ts b/packages/browser/src/core/constants/index.ts index b7b1aa4b9..d9b7d4f66 100644 --- a/packages/browser/src/core/constants/index.ts +++ b/packages/browser/src/core/constants/index.ts @@ -1 +1 @@ -export const SEGMENT_API_HOST = 'api.attributionapp.com/v1' +export const SEGMENT_API_HOST = 'track.attributionapp.com/v1' From 16f98c05f08f3f3700e6341a30f938cc0d05f419 Mon Sep 17 00:00:00 2001 From: iraklikori Date: Wed, 5 Jun 2024 17:29:56 +0400 Subject: [PATCH 8/8] add loadScript to Analytics --- packages/browser/src/core/analytics/index.ts | 57 ++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/packages/browser/src/core/analytics/index.ts b/packages/browser/src/core/analytics/index.ts index fd3853d9f..01a8e7d0c 100644 --- a/packages/browser/src/core/analytics/index.ts +++ b/packages/browser/src/core/analytics/index.ts @@ -252,6 +252,63 @@ export class Analytics return this._universalStorage } + loadScript( + src: string, + attributes?: Record + ): Promise { + function findScript(src: string): HTMLScriptElement | undefined { + const scripts = Array.prototype.slice.call( + window.document.querySelectorAll('script') + ) + return scripts.find((s) => s.src === src) + } + + const found = findScript(src) + + if (found !== undefined) { + const status = found?.getAttribute('status') + + if (status === 'loaded') { + return Promise.resolve(found) + } + + if (status === 'loading') { + return new Promise((resolve, reject) => { + found.addEventListener('load', () => resolve(found)) + found.addEventListener('error', (err) => reject(err)) + }) + } + } + + return new Promise((resolve, reject) => { + const script = window.document.createElement('script') + + script.type = 'text/javascript' + script.src = src + script.async = true + + script.setAttribute('status', 'loading') + for (const [k, v] of Object.entries(attributes ?? {})) { + script.setAttribute(k, v) + } + + script.onload = (): void => { + script.onerror = script.onload = null + script.setAttribute('status', 'loaded') + resolve(script) + } + + script.onerror = (): void => { + script.onerror = script.onload = null + script.setAttribute('status', 'error') + reject(new Error(`Failed to load ${src}`)) + } + + const tag = window.document.getElementsByTagName('script')[0] + tag.parentElement?.insertBefore(script, tag) + }) + } + async track(...args: EventParams): Promise { const [name, data, opts, cb] = resolveArguments(...args)