UNPKG

evrythng

Version:

Official Javascript SDK for the EVRYTHNG API.

171 lines (151 loc) 4.43 kB
import { mixinResources } from '../util/mixin' import AppUser from '../entity/AppUser' import Scope from './Scope' import symbols from '../symbols' import User from './User' /** Action created on each page load automatially. **/ const ACTION_TYPE_PAGE_VISITED = '_PageVisited' /** * Mixin with all the top-level Application resources. * * @mixin */ const ApplicationAccess = mixinResources([ AppUser // C ]) /** * ActionApp is a Scope similar to Application, but with helpers for the simple * 'create anonymous user and actions for analytics' use case. * * @extends Scope * @mixes ApplicationAccess */ export default class ActionApp extends ApplicationAccess(Scope) { /** * Creates an instance of ActionApp. * * @param {string} apiKey - Application API Key. */ constructor (apiKey) { super(apiKey) this.initPromise = super .readAccess() .then((access) => { this.id = access.actor.id this.project = access.project this[symbols.path] = this._getPath() }) .then(() => this.read()) .then(() => this._getAnonUser()) .then((anonUser) => { this.anonUser = anonUser }) } /** * Read the application's data asynchronously, then prepare the anonymous user. * * @returns {Promise} */ init () { return this.initPromise } /** * Record that a page was visited. Make sure the _PageVisited action type is * in the application's project scope. The URL is included in customFields. * * Use evrythng.setup() to disable geolocation if preferred. * * @returns {Promise} */ async pageVisited () { return this.createAction(ACTION_TYPE_PAGE_VISITED, { url: window.location.href }) } /** * Helper function to create an action with extra data. * * @param {string} type - Action Type. Must exist in Application project scope. * @param {Object} [data] - Optional extra action data associated with the web page. * Add 'thng' or 'product' to set that ID as the action target. * @returns {Promise<Object>} The action that was created. */ async createAction (type, data = {}) { if (!this.anonUser) { throw new Error('Anonymous user not yet prepared. Use actionApp.init() to wait for this.') } if (type.startsWith('_')) { // Check the custom action type is visible to the user try { await this.anonUser.actionType(type).read() } catch (e) { console.error(e) throw new Error('The action type was not found. Is it in project scope?') } } const { thng, product, ...customFields } = data if (thng && product) { throw new Error('Either thng or product can be specified as target, not both') } const payload = { type, customFields } if (thng) { payload.thng = thng } if (product) { payload.product = product } return this.anonUser.action(type).create(payload) } /** * Get the underlying anonymous Application User maintained in localStorage * by this ActionApp. * * @returns {User} Anonymous Application User SDK Scope. */ async getAnonymousUser () { if (!this.anonUser) { throw new Error('Anonymous user not yet prepared. Use actionApp.init() to wait for this.') } return this.anonUser } // PRIVATE /** * Return application endpoint. * * @returns {string} * @private */ _getPath () { return '/applications/me' } /** * Store each user's API key according to the app they are using. * * @returns {string} A per-app localStorage key for the user. */ _getStorageKey () { return `action-app-user-${this.id}` } /** * Create a new anonymous Application User and store in localStorage. * * @returns {Promise} */ async _createAnonUser () { const anonUser = await this.appUser().create({ anonymous: true }) localStorage.setItem(this._getStorageKey(), anonUser.evrythngApiKey) return anonUser } /** * Get the single anonymous Application User this scope uses to create actions. * If none is stored in localStorage, a new one is created. * * @returns {Promise} */ async _getAnonUser () { const apiKey = localStorage.getItem(this._getStorageKey()) if (!apiKey) { return this._createAnonUser() } const anonUser = new User(apiKey) return anonUser.init() } }