diff --git a/README.md b/README.md index da98aa131..6b57dfd41 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,56 @@ # Alloy -Alloy is the code name for the Adobe Experience Platform Web SDK. It allows for streaming data into the platform, syncing identities, personalizing content, and more. +Alloy is the code name for the Adobe Experience Platform Web SDK. It allows for recording events into the Adobe Experience Platform, syncing identities, personalizing content, and more. For documentation on how to use Alloy, please see the [user documentation](https://adobe.ly/36dGGp6). For documentation on how to contribute to Alloy, please see the [developer documentation](https://github.com/adobe/alloy/wiki). + +## Installation + +There are three supported ways to use Alloy. + 1. Using Adobe Launch, install the Adobe Experience Platform Web SDK Extension. + 2. Use the pre-built, minified version available via a CDN. You could also self-host this version. + 3. Use the NPM library which exports an ES6 module. + +### Using the launch extension + +For documentation on the AEP Web SDK Launch Extension see the [launch documentation](https://docs.adobe.com/content/help/en/launch/using/extensions-ref/adobe-extension/aep-extension/overview.html) + +### Using the stand alone version + +```html + + + +``` + +### Using the NPM library + +```bash +npm install @adobe/alloy +``` + +Using the library: + +```javascript +import { baseCode, core } from "@adobe/alloy"; +baseCode(["alloy"]); // creates the window.alloy function +core(); // runs + +window.alloy("config", { ... }); +window.alloy("sendEvent", { ... }); +``` + +The ES6 exports are exposed via the NPM "module" property, so you may need to adjust your rollup system to look for the module property. + + diff --git a/coverageignore.js b/coverageignore.js index 14360c9d6..907d92910 100644 --- a/coverageignore.js +++ b/coverageignore.js @@ -14,4 +14,10 @@ governing permissions and limitations under the License. * Patterns of source files (files within the src directory) that should be * ignored for test coverage checks and reporting. */ -module.exports = ["**/.*", "**/constants/**", "**/index.js"]; +module.exports = [ + "**/.*", + "**/constants/**", + "**/index.js", + "src/baseCode.js", + "src/standAlone.js" +]; diff --git a/package-lock.json b/package-lock.json index 82479ab3b..8ed3fe4df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,41 +5,46 @@ "requires": true, "dependencies": { "@adobe/reactor-cookie": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@adobe/reactor-cookie/-/reactor-cookie-1.0.0.tgz", - "integrity": "sha512-MFHSHeuZxLkbe8A8WgXcuLdlOaVdbXzhzylUzVlJ3pOne0u0pmJUke5dXBIju7zCFk0rEJ0tjwR9eDjpcu8m1Q==", + "version": "1.1.0", + "resolved": "https://artifactory.corp.adobe.com:443/artifactory/api/npm/npm-adobe-release/@adobe/reactor-cookie/-/reactor-cookie-1.1.0.tgz", + "integrity": "sha1-nBMgH8TdQbdgCqkR5YdTm3ueQhY=", + "dev": true, "requires": { - "js-cookie": "2.1.4" + "js-cookie": "2.2.1" } }, "@adobe/reactor-load-script": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@adobe/reactor-load-script/-/reactor-load-script-1.1.1.tgz", - "integrity": "sha512-zshG46a+KpTPrSO2C5YJCZa1XEel2DNZijtsitHHsGMChQkSx6lfVH3JH2vuqUxCSq8bKC2eyBKcoDZkEZImgg==", + "resolved": "https://artifactory.corp.adobe.com:443/artifactory/api/npm/npm-adobe-release/@adobe/reactor-load-script/-/reactor-load-script-1.1.1.tgz", + "integrity": "sha1-Qbbm35itDeX6p11PZyyQ4mI6os0=", + "dev": true, "requires": { "@adobe/reactor-promise": "*" } }, "@adobe/reactor-object-assign": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@adobe/reactor-object-assign/-/reactor-object-assign-1.0.0.tgz", - "integrity": "sha512-WI3uplIKeFqqGYyU0IRbXwq+7Nk40EF40s7UmDNL5hdVkiDhEtXmWmbuGPjapKQfe3BoxMlH+pk/rxTva/DaUw==", + "resolved": "https://artifactory.corp.adobe.com:443/artifactory/api/npm/npm-adobe-release/@adobe/reactor-object-assign/-/reactor-object-assign-1.0.0.tgz", + "integrity": "sha1-m8Aty/8qKK1vVaDl/YDzfJP3Yko=", + "dev": true, "requires": { "object-assign": "4.1.1" } }, "@adobe/reactor-promise": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@adobe/reactor-promise/-/reactor-promise-1.2.0.tgz", - "integrity": "sha512-0haTPOfJRKvTuG5Sbja3xAFPdv8aJUz+CiU2ocV5F88az0g6fOwt4+NLlLKzJcbh7qcg6MjDMZopbNc0xqUUVg==", + "resolved": "https://artifactory.corp.adobe.com:443/artifactory/api/npm/npm-adobe-release/@adobe/reactor-promise/-/reactor-promise-1.2.0.tgz", + "integrity": "sha1-fvHvKFBAClrCCx1zRkAqNZ355HE=", + "dev": true, "requires": { "promise-polyfill": "8.1.3" } }, "@adobe/reactor-query-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@adobe/reactor-query-string/-/reactor-query-string-1.0.0.tgz", - "integrity": "sha512-Y6Cb9azVk+zIs9wEoOTMa01pzMqxFDPhRCfvZeW3YTAeR/b3kZOjD8loTpDt7bDj0vCZPRB2mhnVGOMCnsvBFQ==", + "resolved": "https://artifactory.corp.adobe.com:443/artifactory/api/npm/npm-adobe-release/@adobe/reactor-query-string/-/reactor-query-string-1.0.0.tgz", + "integrity": "sha1-5/b5vYnQqE2sWmxQIlXysgpWh8E=", + "dev": true, "requires": { "querystring": "0.2.0" } @@ -6772,9 +6777,10 @@ "dev": true }, "js-cookie": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.1.4.tgz", - "integrity": "sha1-2k7FA4ZvFJ0WTPJfV57zEBUCXY0=" + "version": "2.2.1", + "resolved": "https://artifactory.corp.adobe.com:443/artifactory/api/npm/npm-adobe-release/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha1-aeEG3F1YBolFYpAqpbrsN0Tpsrg=", + "dev": true }, "js-levenshtein": { "version": "1.1.6", @@ -8128,7 +8134,8 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object-component": { "version": "0.0.3", @@ -8764,7 +8771,8 @@ "promise-polyfill": { "version": "8.1.3", "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz", - "integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==" + "integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==", + "dev": true }, "promisify-event": { "version": "1.0.0", @@ -8885,8 +8893,9 @@ }, "querystring": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "resolved": "https://artifactory.corp.adobe.com:443/artifactory/api/npm/npm-adobe-release/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true }, "querystringify": { "version": "2.1.1", diff --git a/package.json b/package.json index e48201a6e..5e3fff745 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,11 @@ { "name": "@adobe/alloy", "version": "2.2.0", - "description": "Client-Side SDK for Unified Data Collection", - "main": "src/core/index.js", + "description": "Adobe Experience Platform Web SDK", + "module": "dist/index.js", + "files": [ + "dist/index.js" + ], "scripts": { "clean": "rimraf dist", "lint": "eslint --fix \"*.js\" \"src/**/*.js\" \"test/**/*.js\"", @@ -28,12 +31,10 @@ "prebuild": "npm run clean && npm run format && npm run lint", "build": "rollup -c", "prebuild:prod": "npm run prebuild", - "build:prod:standalone:unminified": "rollup -c --environment BUILD:prodStandalone", - "build:prod:standalone:minified": "rollup -c --environment MINIFY,BUILD:prodStandalone", - "build:prod:reactor:unminified": "rollup -c --environment BUILD:prodReactor", - "build:prod": "npm-run-all --parallel build:prod:standalone:unminified build:prod:standalone:minified build:prod:reactor:unminified", + "build:prod:unminified": "rollup -c --environment BUILD:prod", + "build:prod:minified": "rollup -c --environment MINIFY,BUILD:prod", + "build:prod": "npm-run-all --parallel build:prod:unminified build:prod:minified", "build:watch": "rollup -c -w", - "build:basecode": "terser src/baseCode/index.js --mangle --compress unused=false", "sandbox": "cd sandbox && export REACT_APP_NONCE=321 && npm start", "sandbox:install": "cd sandbox && npm install", "sandbox:build": "cd sandbox && npm run build", @@ -77,14 +78,20 @@ } ], "dependencies": { + "css.escape": "^1.5.1", + "uuid": "^3.3.2" + }, + "peerDependencies": { "@adobe/reactor-cookie": "^1.0.0", "@adobe/reactor-load-script": "^1.1.1", "@adobe/reactor-object-assign": "^1.0.0", - "@adobe/reactor-query-string": "^1.0.0", - "css.escape": "^1.5.1", - "uuid": "^3.3.2" + "@adobe/reactor-query-string": "^1.0.0" }, "devDependencies": { + "@adobe/reactor-cookie": "^1.0.0", + "@adobe/reactor-load-script": "^1.1.1", + "@adobe/reactor-object-assign": "^1.0.0", + "@adobe/reactor-query-string": "^1.0.0", "@babel/core": "^7.2.2", "@babel/plugin-proposal-object-rest-spread": "^7.3.2", "@babel/plugin-transform-template-literals": "^7.4.4", diff --git a/rollup.config.js b/rollup.config.js index 6a6beccbd..ec49fcc5f 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -11,7 +11,6 @@ governing permissions and limitations under the License. */ import path from "path"; -import jscc from "rollup-plugin-jscc"; import resolve from "rollup-plugin-node-resolve"; import commonjs from "rollup-plugin-commonjs"; import babel from "rollup-plugin-babel"; @@ -19,14 +18,12 @@ import { terser } from "rollup-plugin-terser"; import license from "rollup-plugin-license"; const buildTargets = { - PROD_STANDALONE: "prodStandalone", - PROD_REACTOR: "prodReactor", + PROD: "prod", DEV: "dev" }; const destDirectoryByBuildTarget = { - [buildTargets.PROD_STANDALONE]: "dist/standalone/", - [buildTargets.PROD_REACTOR]: "dist/reactor/", + [buildTargets.PROD]: "dist/", [buildTargets.DEV]: "sandbox/public/" }; @@ -35,14 +32,14 @@ const minify = process.env.MINIFY; const destDirectory = destDirectoryByBuildTarget[buildTarget]; const minifiedExtension = minify ? ".min" : ""; +const baseCodeTerser = terser({ + mangle: true, + compress: { + unused: false + } +}); const plugins = [ - jscc({ - values: { - _DEV: buildTarget === buildTargets.DEV, - _REACTOR: buildTarget === buildTargets.PROD_REACTOR - } - }), resolve({ preferBuiltins: false, // Support the browser field in dependencies' package.json. @@ -53,10 +50,6 @@ const plugins = [ babel() ]; -if (minify) { - plugins.push(terser()); -} - if (buildTarget !== buildTargets.DEV) { plugins.push( license({ @@ -69,52 +62,53 @@ if (buildTarget !== buildTargets.DEV) { ); } -const config = { - input: "src/core/index.js", +const config = []; + +if (buildTarget === buildTargets.PROD) { + config.push({ + input: "src/baseCode.js", + output: [ + { + file: `${destDirectory}baseCode${minifiedExtension}.js`, + format: "iife" + } + ], + plugins: minify ? [...plugins, baseCodeTerser] : plugins + }); +} + +config.push({ + input: "src/standAlone.js", output: [ { file: `${destDirectory}alloy${minifiedExtension}.js`, - // For the Reactor-specific build, we need to use the CommonJS format - // for output instead of IIFE, otherwise Rollup doesn't know whether the - // "external" modules (as defined elsewhere in this configuration) are - // coming from global variables or from another CommonJS bundler, so - // it adds a bunch of cruft to accommodate and logs build warnings. - // Because we have to use the CommonJS format for the Reactor-specific - // build, we can't just use an "intro" that looks like: - // if (IE less than version 11) { - // console.warn("unsupported browser"); - // return; - // } - // because you can't "return" from a CommonJS module. Therefore, we have - // to do an if-else for an "intro" and "outro". - // If we do an if-else, we're not compliant with strict mode, because - // babel inserts its function declarations directly inside our if-else. - // Because function declarations are not allowed directly within an - // if-else in strict mode, we need to wrap babel's - // function declarations (and our own code) inside an IIFE. - // So, what we end up with is output using "format: cjs" but with an - // appropriate intro and outro that provides browser checking and an - // IIFE. This works for both Reactor-specific and standalone use cases. - format: "cjs", - // Allow non-IE browsers and IE11 - // document.documentMode was added in IE8, and is specific to IE. - // IE7 and lower are not ES5 compatible so will get a parse error loading - // the library. + format: "iife", intro: "if (document.documentMode && document.documentMode < 11) {\n" + " console.warn('The Adobe Experience Cloud Web SDK does not support IE 10 and below.');\n" + - "} else {\n" + - " (function() {", - outro: " })();\n}" + " return;\n" + + "}\n" } ], - plugins -}; + plugins: minify ? [...plugins, terser()] : plugins +}); -// If we're building for Reactor, we'll use Reactor's core modules -// (named @adobe/reactor-*) instead of including the packages directly. -if (buildTarget === buildTargets.PROD_REACTOR) { - config.external = name => /^@adobe\/reactor-/.test(name); +if (buildTarget === buildTargets.PROD && !minify) { + config.push({ + input: "src/index.js", + output: [ + { + file: `${destDirectory}index.js`, + format: "es" + } + ], + // The @adobe/reactor-* dependencies are specified as peerDependencies so no need to include them in the + // module build. The Launch extension does not need them included. + external(name) { + return /^@adobe\/reactor-/.test(name); + }, + plugins + }); } export default config; diff --git a/src/baseCode.js b/src/baseCode.js new file mode 100644 index 000000000..cd34e8c43 --- /dev/null +++ b/src/baseCode.js @@ -0,0 +1,17 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +// This file is used by rollup to create a base code example + +import baseCode from "./baseCode/index"; + +baseCode(["alloy"]); diff --git a/src/baseCode/index.js b/src/baseCode/index.js index b39a87b52..2b2eb4ad5 100644 --- a/src/baseCode/index.js +++ b/src/baseCode/index.js @@ -33,7 +33,7 @@ governing permissions and limitations under the License. * particularly sensitive to base code size. */ -(function(window, instanceNames) { +export default instanceNames => { instanceNames.forEach(function(instanceName) { if (!window[instanceName]) { // __alloyNS stores a name of each "instance", or in other words, each @@ -59,4 +59,4 @@ governing permissions and limitations under the License. window[instanceName].q = []; } }); -})(window, ["alloy"]); +}; diff --git a/src/components/EventMerge/createComponent.js b/src/components/EventMerge/createComponent.js new file mode 100644 index 000000000..86499873b --- /dev/null +++ b/src/components/EventMerge/createComponent.js @@ -0,0 +1,21 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +export default ({ createEventMergeId }) => { + return { + commands: { + createEventMergeId: { + run: createEventMergeId + } + } + }; +}; diff --git a/src/components/EventMerge/createEventMergeId.js b/src/components/EventMerge/createEventMergeId.js new file mode 100644 index 000000000..95c969feb --- /dev/null +++ b/src/components/EventMerge/createEventMergeId.js @@ -0,0 +1,19 @@ +/* +Copyright 20219 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +import { uuid } from "../../utils"; + +export default () => { + return { + eventMergeId: uuid() + }; +}; diff --git a/src/components/EventMerge/index.js b/src/components/EventMerge/index.js index e5d51bfea..4a57a3ea9 100644 --- a/src/components/EventMerge/index.js +++ b/src/components/EventMerge/index.js @@ -10,40 +10,14 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -import { uuid } from "../../utils"; -import { callback } from "../../utils/validation"; +import createEventMergeId from "./createEventMergeId"; +import createComponent from "./createComponent"; -const generateEventMergeIdResult = () => { - return { - eventMergeId: uuid() - }; -}; - -const createEventMerge = ({ config }) => { - // #if _REACTOR - // This is a way for the Event Merge ID data element in the Reactor extension - // to get an event merge ID synchronously since data elements are required - // to be synchronous. - config.reactorRegisterCreateEventMergeId(generateEventMergeIdResult); - // #endif - - return { - commands: { - createEventMergeId: { - run: generateEventMergeIdResult - } - } - }; +const createEventMerge = () => { + return createComponent(createEventMergeId); }; createEventMerge.namespace = "EventMerge"; createEventMerge.configValidators = {}; -// #if _REACTOR -// Not much need to validate since we are our own consumer. -createEventMerge.configValidators.reactorRegisterCreateEventMergeId = callback().default( - () => {} -); -// #endif - export default createEventMerge; diff --git a/src/components/Identity/configValidators.js b/src/components/Identity/configValidators.js index 4c788b646..5c22d63f3 100644 --- a/src/components/Identity/configValidators.js +++ b/src/components/Identity/configValidators.js @@ -10,16 +10,11 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -import { boolean, callback } from "../../utils/validation"; +import { boolean } from "../../utils/validation"; const configValidators = { thirdPartyCookiesEnabled: boolean().default(true), idMigrationEnabled: boolean().default(true) }; -// #if _REACTOR -// Not much need to validate since we are our own consumer. -configValidators.reactorRegisterGetEcid = callback().default(() => {}); -// #endif - export default configValidators; diff --git a/src/constants/libraryName.js b/src/constants/libraryName.js index 887128929..52d0d3e4b 100644 --- a/src/constants/libraryName.js +++ b/src/constants/libraryName.js @@ -10,8 +10,4 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -/* #if _REACTOR -export default "https://ns.adobe.com/experience/alloy/reactor"; -//#else */ export default "https://ns.adobe.com/experience/alloy"; -// #endif diff --git a/src/constants/libraryVersion.js b/src/constants/libraryVersion.js index 529960d55..18c692536 100644 --- a/src/constants/libraryVersion.js +++ b/src/constants/libraryVersion.js @@ -11,14 +11,6 @@ governing permissions and limitations under the License. */ // The __VERSION__ keyword will be replace at alloy build time with the package.json version. -// The __EXTENSION_VERSION__ keyword will be replaced at extension build time with the -// launch extension's package.json version. // see babel-plugin-version -/* #if _REACTOR -const alloyVersion = "__VERSION__"; -const extensionVersion = "__EXTENSION_VERSION__"; -export default `${alloyVersion}+${extensionVersion}`; -//#else */ export default "__VERSION__"; -// #endif diff --git a/src/core/index.js b/src/core/index.js index 8dd1e387f..f905710b6 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -38,127 +38,129 @@ import injectProcessWarningsAndErrors from "./edgeNetwork/injectProcessWarningsA import validateNetworkResponseIsWellFormed from "./edgeNetwork/validateNetworkResponseIsWellFormed"; import isRetryableHttpStatusCode from "./network/isRetryableHttpStatusCode"; -// eslint-disable-next-line no-underscore-dangle -const instanceNames = window.__alloyNS; +export default () => { + // eslint-disable-next-line no-underscore-dangle + const instanceNames = window.__alloyNS; -const createNamespacedStorage = injectStorage(window); + const createNamespacedStorage = injectStorage(window); -const { console } = window; + const { console } = window; -// set this up as a function so that monitors can be added at anytime -// eslint-disable-next-line no-underscore-dangle -const getMonitors = () => window.__alloyMonitors || []; + // set this up as a function so that monitors can be added at anytime + // eslint-disable-next-line no-underscore-dangle + const getMonitors = () => window.__alloyMonitors || []; -const coreConfigValidators = createCoreConfigs(); -const apexDomain = getApexDomain(window, cookieJar); + const coreConfigValidators = createCoreConfigs(); + const apexDomain = getApexDomain(window, cookieJar); -if (instanceNames) { - instanceNames.forEach(instanceName => { - const { - setDebugEnabled, - logger, - createComponentLogger - } = createLogController({ - console, - locationSearch: window.location.search, - createLogger, - instanceName, - createNamespacedStorage, - getMonitors - }); - const componentRegistry = createComponentRegistry(); - const lifecycle = createLifecycle(componentRegistry); - const networkStrategy = injectNetworkStrategy({ window, logger }); - - const setDebugCommand = options => { - setDebugEnabled(options.enabled, { fromConfig: false }); - }; - - const configureCommand = options => { - const config = buildAndValidateConfig({ - options, - componentCreators, - coreConfigValidators, - createConfig, + if (instanceNames) { + instanceNames.forEach(instanceName => { + const { + setDebugEnabled, logger, - setDebugEnabled - }); - const cookieTransfer = createCookieTransfer({ - cookieJar, - orgId: config.orgId, - apexDomain - }); - const sendNetworkRequest = injectSendNetworkRequest({ - logger, - networkStrategy, - isRetryableHttpStatusCode - }); - const processWarningsAndErrors = injectProcessWarningsAndErrors({ - logger - }); - const sendEdgeNetworkRequest = injectSendEdgeNetworkRequest({ - config, - lifecycle, - cookieTransfer, - sendNetworkRequest, - createResponse, - processWarningsAndErrors, - validateNetworkResponseIsWellFormed + createComponentLogger + } = createLogController({ + console, + locationSearch: window.location.search, + createLogger, + instanceName, + createNamespacedStorage, + getMonitors }); - const generalConsentState = createConsentStateMachine(); - const consent = createConsent({ - generalConsentState, + const componentRegistry = createComponentRegistry(); + const lifecycle = createLifecycle(componentRegistry); + const networkStrategy = injectNetworkStrategy({ window, logger }); + + const setDebugCommand = options => { + setDebugEnabled(options.enabled, { fromConfig: false }); + }; + + const configureCommand = options => { + const config = buildAndValidateConfig({ + options, + componentCreators, + coreConfigValidators, + createConfig, + logger, + setDebugEnabled + }); + const cookieTransfer = createCookieTransfer({ + cookieJar, + orgId: config.orgId, + apexDomain + }); + const sendNetworkRequest = injectSendNetworkRequest({ + logger, + networkStrategy, + isRetryableHttpStatusCode + }); + const processWarningsAndErrors = injectProcessWarningsAndErrors({ + logger + }); + const sendEdgeNetworkRequest = injectSendEdgeNetworkRequest({ + config, + lifecycle, + cookieTransfer, + sendNetworkRequest, + createResponse, + processWarningsAndErrors, + validateNetworkResponseIsWellFormed + }); + const generalConsentState = createConsentStateMachine(); + const consent = createConsent({ + generalConsentState, + logger + }); + const eventManager = createEventManager({ + config, + logger, + lifecycle, + consent, + createEvent, + createDataCollectionRequestPayload, + sendEdgeNetworkRequest + }); + return initializeComponents({ + componentCreators, + lifecycle, + componentRegistry, + getImmediatelyAvailableTools(componentName) { + const componentLogger = createComponentLogger(componentName); + return { + config, + consent, + eventManager, + logger: componentLogger, + lifecycle, + sendEdgeNetworkRequest, + handleError: injectHandleError({ + errorPrefix: `[${instanceName}] [${componentName}]`, + logger: componentLogger + }) + }; + } + }); + }; + + const handleError = injectHandleError({ + errorPrefix: `[${instanceName}]`, logger }); - const eventManager = createEventManager({ - config, + + const executeCommand = injectExecuteCommand({ logger, - lifecycle, - consent, - createEvent, - createDataCollectionRequestPayload, - sendEdgeNetworkRequest + configureCommand, + setDebugCommand, + handleError, + validateCommandOptions }); - return initializeComponents({ - componentCreators, - lifecycle, - componentRegistry, - getImmediatelyAvailableTools(componentName) { - const componentLogger = createComponentLogger(componentName); - return { - config, - consent, - eventManager, - logger: componentLogger, - lifecycle, - sendEdgeNetworkRequest, - handleError: injectHandleError({ - errorPrefix: `[${instanceName}] [${componentName}]`, - logger: componentLogger - }) - }; - } - }); - }; - const handleError = injectHandleError({ - errorPrefix: `[${instanceName}]`, - logger - }); + const instance = createInstance(executeCommand); - const executeCommand = injectExecuteCommand({ - logger, - configureCommand, - setDebugCommand, - handleError, - validateCommandOptions + const queue = window[instanceName].q; + queue.push = instance; + logger.logOnInstanceCreated({ instance }); + queue.forEach(instance); }); - - const instance = createInstance(executeCommand); - - const queue = window[instanceName].q; - queue.push = instance; - logger.logOnInstanceCreated({ instance }); - queue.forEach(instance); - }); -} + } +}; diff --git a/src/index.js b/src/index.js new file mode 100644 index 000000000..1bf2594f2 --- /dev/null +++ b/src/index.js @@ -0,0 +1,24 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +// This file is used to rollup the code into an ES module version to be used by other npm projects +// like the launch extension. Everything that is exported here can be used independently by other +// npm projects. + +export { default as baseCode } from "./baseCode/index"; + +export { default as core } from "./core"; + +// createEventMergeId is used by the Launch extension to provide a synchronous way to create an id +export { + default as createEventMergeId +} from "./components/EventMerge/createEventMergeId"; diff --git a/src/standalone.js b/src/standalone.js new file mode 100644 index 000000000..2889bdb56 --- /dev/null +++ b/src/standalone.js @@ -0,0 +1,17 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +// This file is used by rollup to create the browser version that is uploaded to cdn + +import core from "./core"; + +core(); diff --git a/src/utils/index.js b/src/utils/index.js index d50446add..cd66e951a 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -13,21 +13,27 @@ governing permissions and limitations under the License. /* eslint-disable import/prefer-default-export */ // Please keep in alphabetical order. -export { default as areThirdPartyCookiesSupportedByDefault } from "./areThirdPartyCookiesSupportedByDefault"; +export { + default as areThirdPartyCookiesSupportedByDefault +} from "./areThirdPartyCookiesSupportedByDefault"; export { default as assign } from "./assign"; export { default as assignIf } from "./assignIf"; export { default as clone } from "./clone"; export { default as convertTimes } from "./convertTimes"; export { default as cookieJar } from "./cookieJar"; export { default as createMerger } from "./createMerger"; -export { default as createCallbackAggregator } from "./createCallbackAggregator"; +export { + default as createCallbackAggregator +} from "./createCallbackAggregator"; export { default as createTaskQueue } from "./createTaskQueue"; export { default as defer } from "./defer"; export { default as deepAssign } from "./deepAssign"; export { default as endsWith } from "./endsWith"; export { default as find } from "./find"; export { default as fireImage } from "./fireImage"; -export { default as fireReferrerHideableImage } from "./fireReferrerHideableImage"; +export { + default as fireReferrerHideableImage +} from "./fireReferrerHideableImage"; export { default as flatMap } from "./flatMap"; export { default as getApexDomain } from "./getApexDomain"; export { default as getLastArrayItems } from "./getLastArrayItems"; @@ -50,7 +56,9 @@ export { default as memoize } from "./memoize"; export { default as noop } from "./noop"; export { default as padStart } from "./padStart"; export { default as queryString } from "./querystring"; -export { default as sanitizeOrgIdForCookieName } from "./sanitizeOrgIdForCookieName"; +export { + default as sanitizeOrgIdForCookieName +} from "./sanitizeOrgIdForCookieName"; export { default as stackError } from "./stackError"; export { default as injectStorage } from "./injectStorage"; export { default as stringToBoolean } from "./stringToBoolean"; diff --git a/test/functional/helpers/createFixture/clientScripts.js b/test/functional/helpers/createFixture/clientScripts.js index 1a48c0a54..c48baf555 100644 --- a/test/functional/helpers/createFixture/clientScripts.js +++ b/test/functional/helpers/createFixture/clientScripts.js @@ -31,10 +31,7 @@ const alloyPageSnippetPath = path.join( __dirname, "../alloyPageSnippet/index.js" ); -const localAlloyLibraryPath = path.join( - __dirname, - "../../../../dist/standalone/alloy.js" -); +const localAlloyLibraryPath = path.join(__dirname, "../../../../dist/alloy.js"); const remoteAlloyLibraryUrl = "https://cdn1.adoberesources.net/alloy/latest/alloy.js"; diff --git a/test/unit/specs/baseCode.spec.js b/test/unit/specs/baseCode.spec.js new file mode 100644 index 000000000..33436f4cb --- /dev/null +++ b/test/unit/specs/baseCode.spec.js @@ -0,0 +1,14 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +// eslint-disable-next-line no-unused-vars +import baseCode from "../../../src/baseCode"; diff --git a/test/unit/specs/components/EventMerge/createComponent.spec.js b/test/unit/specs/components/EventMerge/createComponent.spec.js new file mode 100644 index 000000000..693f792c8 --- /dev/null +++ b/test/unit/specs/components/EventMerge/createComponent.spec.js @@ -0,0 +1,26 @@ +/* +Copyright 2019 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +import createComponent from "../../../../../src/components/EventMerge/createComponent"; + +describe("EventMerge:createComponent", () => { + it("creates a component", () => { + const createEventMergeId = () => undefined; + expect(createComponent({ createEventMergeId })).toEqual({ + commands: { + createEventMergeId: { + run: createEventMergeId + } + } + }); + }); +}); diff --git a/test/unit/specs/components/EventMerge/createEventMergeId.spec.js b/test/unit/specs/components/EventMerge/createEventMergeId.spec.js new file mode 100644 index 000000000..30c7f6180 --- /dev/null +++ b/test/unit/specs/components/EventMerge/createEventMergeId.spec.js @@ -0,0 +1,25 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +import createEventMergeId from "../../../../../src/components/EventMerge/createEventMergeId"; + +const uuidv4Regex = /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; + +describe("EventMerge:createEventMergeId", () => { + it("returns a UUID v4-compliant Id", () => { + expect(uuidv4Regex.test(createEventMergeId().eventMergeId)).toBe(true); + }); + + it("doesn't return any other fields in the response", () => { + expect(Object.keys(createEventMergeId())).toEqual(["eventMergeId"]); + }); +}); diff --git a/test/unit/specs/components/EventMerge/index.spec.js b/test/unit/specs/components/EventMerge/index.spec.js deleted file mode 100644 index 38491fb1e..000000000 --- a/test/unit/specs/components/EventMerge/index.spec.js +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2019 Adobe. All rights reserved. -This file is licensed to you 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 REPRESENTATIONS -OF ANY KIND, either express or implied. See the License for the specific language -governing permissions and limitations under the License. -*/ - -import createEventMerge from "../../../../../src/components/EventMerge"; -import createConfig from "../../../../../src/core/config/createConfig"; - -const uuidv4Regex = /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; - -describe("EventMerge", () => { - let eventMerge; - let reactorRegisterCreateEventMergeId; - - beforeAll(() => { - reactorRegisterCreateEventMergeId = jasmine.createSpy(); - eventMerge = createEventMerge({ - config: createConfig({ - reactorRegisterCreateEventMergeId - }) - }); - }); - - describe("commands", () => { - describe("createEventMergeId", () => { - it("returns a UUID v4-compliant Id", () => { - expect( - uuidv4Regex.test( - eventMerge.commands.createEventMergeId.run().eventMergeId - ) - ).toBe(true); - }); - }); - }); - - describe("reactor-specific functionality", () => { - it("registers a function for creating an event merge ID", () => { - const createEventMergeId = reactorRegisterCreateEventMergeId.calls.first() - .args[0]; - expect(uuidv4Regex.test(createEventMergeId().eventMergeId)).toBe(true); - }); - }); -}); diff --git a/test/unit/specs/components/LibraryInfo/index.spec.js b/test/unit/specs/components/LibraryInfo/index.spec.js index 6245b8933..4e941d507 100644 --- a/test/unit/specs/components/LibraryInfo/index.spec.js +++ b/test/unit/specs/components/LibraryInfo/index.spec.js @@ -2,11 +2,9 @@ import createLibraryInfo from "../../../../../src/components/LibraryInfo"; describe("LibraryInfo", () => { it("returns library information", () => { - const alloyVersion = "__VERSION__"; - const extensionVersion = "__EXTENSION_VERSION__"; expect(createLibraryInfo().commands.getLibraryInfo.run()).toEqual({ libraryInfo: { - version: `${alloyVersion}+${extensionVersion}` + version: `__VERSION__` } }); }); diff --git a/test/unit/specs/standalone.spec.js b/test/unit/specs/standalone.spec.js new file mode 100644 index 000000000..91fc9d2ca --- /dev/null +++ b/test/unit/specs/standalone.spec.js @@ -0,0 +1,14 @@ +/* +Copyright 2020 Adobe. All rights reserved. +This file is licensed to you 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +// eslint-disable-next-line no-unused-vars +import standalone from "../../../src/standalone";