UNPKG

@zephr/saas-node-server-sdk

Version:
478 lines (402 loc) 14.3 kB
var fetch = require('node-fetch'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch); var id = 0; function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; } function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; } const Deferred = () => { let resolve; let reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); return { promise, resolve, reject }; }; /** * Zephr Access Controller * * @public * @class * @property {string} orgId The Zephr Organisation ID * @property {string} apiEndpoint The Zephr API endpoint url * @property {boolean} hasStarted Has the access controller started? */ var _accessParams = /*#__PURE__*/_classPrivateFieldLooseKey("accessParams"); var _accessState = /*#__PURE__*/_classPrivateFieldLooseKey("accessState"); var _updateCallbacks = /*#__PURE__*/_classPrivateFieldLooseKey("updateCallbacks"); var _deferredStart = /*#__PURE__*/_classPrivateFieldLooseKey("deferredStart"); var _getCurrentAccessState = /*#__PURE__*/_classPrivateFieldLooseKey("getCurrentAccessState"); var _runDynamicFeature = /*#__PURE__*/_classPrivateFieldLooseKey("runDynamicFeature"); var _runRuleDecision = /*#__PURE__*/_classPrivateFieldLooseKey("runRuleDecision"); var _triggerOnUpdate = /*#__PURE__*/_classPrivateFieldLooseKey("triggerOnUpdate"); class ZephrAccessController { /** * Create access controller instance * * @param {object} args Constructor arguments * @param {string=} args.apiEndpoint The Zephr API endpoint url. */ constructor({ apiEndpoint } = {}) { Object.defineProperty(this, _triggerOnUpdate, { value: _triggerOnUpdate2 }); Object.defineProperty(this, _runRuleDecision, { value: _runRuleDecision2 }); Object.defineProperty(this, _runDynamicFeature, { value: _runDynamicFeature2 }); Object.defineProperty(this, _getCurrentAccessState, { value: _getCurrentAccessState2 }); this.hasStarted = false; Object.defineProperty(this, _accessParams, { writable: true, value: {} }); Object.defineProperty(this, _accessState, { writable: true, value: {} }); Object.defineProperty(this, _updateCallbacks, { writable: true, value: [] }); Object.defineProperty(this, _deferredStart, { writable: true, value: void 0 }); if (!apiEndpoint) throw new Error('API endpoint must be provided'); this.apiEndpoint = apiEndpoint; _classPrivateFieldLooseBase(this, _deferredStart)[_deferredStart] = Deferred(); } /** * Start Zephr access controller * * @description The Zephr access controller determines the current access state of a user * @async * @param {object} args Access controller arguments * @param {string=} args.jwt Secure JWT token * @param {string=} args.path URL path of initial page * @returns {Promise<void|Error>} Promise resolves when started */ async startAccessController({ jwt, path = '/', ...inputs } = {}) { console.debug('Starting access controller...'); if (!jwt) { throw new Error('JWT token must be provided'); } _classPrivateFieldLooseBase(this, _accessParams)[_accessParams].jwt = jwt; _classPrivateFieldLooseBase(this, _accessParams)[_accessParams].path = path; try { const accessState = await _classPrivateFieldLooseBase(this, _getCurrentAccessState)[_getCurrentAccessState](inputs); _classPrivateFieldLooseBase(this, _accessState)[_accessState] = accessState; this.hasStarted = true; _classPrivateFieldLooseBase(this, _deferredStart)[_deferredStart].resolve(); console.debug('Access controller has started successfully'); } catch (err) { console.error('Access controller failed to start', err); const errorReason = new Error('Failed to get access state.'); _classPrivateFieldLooseBase(this, _deferredStart)[_deferredStart].reject(errorReason); } } /** * Update Zephr access controller parameters * * @description Update Zephr access controller when user state has changed * e.g. logged in/out * @async * @param {object} args Access controller arguments * @param {string=} args.jwt Secure JWT token * @param {string=} args.path URL path of current page * @returns {Promise<void|Error>} Promise resolves when update has finished */ async updateAccessController({ jwt, path, ...inputs }) { console.debug('Updating access controller...'); if (typeof jwt === 'string') { _classPrivateFieldLooseBase(this, _accessParams)[_accessParams].jwt = jwt; } if (typeof path === 'string') { _classPrivateFieldLooseBase(this, _accessParams)[_accessParams].path = path; } try { const accessState = await _classPrivateFieldLooseBase(this, _getCurrentAccessState)[_getCurrentAccessState](inputs); _classPrivateFieldLooseBase(this, _accessState)[_accessState] = accessState; console.debug('Access controller has updated successfully'); _classPrivateFieldLooseBase(this, _triggerOnUpdate)[_triggerOnUpdate](); } catch (err) { console.error('Access controller failed to update', err); } } /** * Access controller ready promise * * @returns {Promise<void|Error>} Ready to use promise */ onReady() { return _classPrivateFieldLooseBase(this, _deferredStart)[_deferredStart].promise; } /** * Access controller update listener * * @param {Function} callback Callback when the user access state is updated */ onUpdate(callback = () => {}) { if (callback && typeof callback === 'function') { _classPrivateFieldLooseBase(this, _updateCallbacks)[_updateCallbacks].push(callback); } } /** * Check if a feature is enabled for the current user * * @param {string} featureSlug The feature slug to check * @param {object} inputs Inputs for Zephr decision making * @param {boolean} [defaultEnabled=false] Is the feature enabled by default * @returns {Promise<boolean>} Is the feature enabled? */ async isFeatureEnabled(featureSlug, inputs = {}, defaultEnabled = false) { var _classPrivateFieldLoo, _classPrivateFieldLoo2; const feature = ((_classPrivateFieldLoo = (_classPrivateFieldLoo2 = _classPrivateFieldLooseBase(this, _accessState)[_accessState]) == null ? void 0 : _classPrivateFieldLoo2.features) != null ? _classPrivateFieldLoo : {})[featureSlug]; if (!feature) { return defaultEnabled; } switch (feature.type) { case 'STATIC': { return feature.enabled; } case 'DYNAMIC': { let featureResult; try { featureResult = await _classPrivateFieldLooseBase(this, _runDynamicFeature)[_runDynamicFeature](featureSlug, inputs); } catch (err) { console.error('Decision engine feature failed to execute', err); return defaultEnabled; } if (Object.values(featureResult.meters).length) { _classPrivateFieldLooseBase(this, _accessState)[_accessState].meters = { ..._classPrivateFieldLooseBase(this, _accessState)[_accessState].meters, ...featureResult.meters }; } return featureResult.enabled; } default: console.error(`Feature ${featureSlug} with type ${feature.type} unrecognised`); return defaultEnabled; } } /** * Check if a feature is enabled for the current user * * @param {string} ruleSlug The rule slug to execute * @param {object} inputs Inputs for Zephr decision making * @returns {Promise<object>} Is the feature enabled? */ async getRuleDecision(ruleSlug, inputs = {}) { let ruleResult; try { ruleResult = await _classPrivateFieldLooseBase(this, _runRuleDecision)[_runRuleDecision](ruleSlug, inputs); } catch (err) { console.error('Rule decision failed to execute', err); return null; } return ruleResult; } /** * Check if the current user is authenticated * * @returns {boolean} Is the current user authenticated? */ isAuthenticated() { var _classPrivateFieldLoo3, _classPrivateFieldLoo4; return (_classPrivateFieldLoo3 = (_classPrivateFieldLoo4 = _classPrivateFieldLooseBase(this, _accessState)[_accessState]) == null ? void 0 : _classPrivateFieldLoo4.authenticated) != null ? _classPrivateFieldLoo3 : false; } /** * Get all of the current users features * * @returns {object[]} Array of the current users features */ getAllFeatures() { var _classPrivateFieldLoo5, _classPrivateFieldLoo6; return (_classPrivateFieldLoo5 = (_classPrivateFieldLoo6 = _classPrivateFieldLooseBase(this, _accessState)[_accessState]) == null ? void 0 : _classPrivateFieldLoo6.features) != null ? _classPrivateFieldLoo5 : []; } /** * Get all of the current users meters * * @returns {object[]} Array of the current users meters */ getAllMeters() { var _classPrivateFieldLoo7, _classPrivateFieldLoo8; return (_classPrivateFieldLoo7 = (_classPrivateFieldLoo8 = _classPrivateFieldLooseBase(this, _accessState)[_accessState]) == null ? void 0 : _classPrivateFieldLoo8.meters) != null ? _classPrivateFieldLoo7 : []; } /** * Run the current access state API * * @private * @async * @param {object} inputs Inputs for Zephr decision making * @returns {Promise<object>} Access state response */ } async function _getCurrentAccessState2(inputs = {}) { return fetch__default["default"](`${this.apiEndpoint}/access/currentState`, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Authorization: `Bearer ${_classPrivateFieldLooseBase(this, _accessParams)[_accessParams].jwt}` }, body: JSON.stringify({ ...inputs, ...{ path: _classPrivateFieldLooseBase(this, _accessParams)[_accessParams].path } }) }).then(response => response.json()).catch(error => { console.error(error); return Promise.reject(error); }); } async function _runDynamicFeature2(featureSlug, inputs = {}) { return fetch__default["default"](`${this.apiEndpoint}/access/feature/${featureSlug}`, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', Accept: 'application/json', Authorization: `Bearer ${_classPrivateFieldLooseBase(this, _accessParams)[_accessParams].jwt}` }, body: JSON.stringify({ ...inputs, ...{ path: _classPrivateFieldLooseBase(this, _accessParams)[_accessParams].path } }) }).then(async response => { if (!response.ok) { console.error('Dynamic feature bad response', await response.text()); throw new Error('Failed response.'); } return response.json(); }); } async function _runRuleDecision2(ruleSlug, inputs = {}) { return fetch__default["default"](`${this.apiEndpoint}/access/decision/${ruleSlug}`, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', Accept: 'application/json', ...(_classPrivateFieldLooseBase(this, _accessParams)[_accessParams].jwt && { Authorization: `Bearer ${_classPrivateFieldLooseBase(this, _accessParams)[_accessParams].jwt}` }) }, body: JSON.stringify({ ...inputs, ...{ path: _classPrivateFieldLooseBase(this, _accessParams)[_accessParams].path } }) }).then(async response => { if (!response.ok) { console.error('Rule decision bad response', await response.text()); throw new Error('Failed response.'); } return response.json(); }); } function _triggerOnUpdate2() { _classPrivateFieldLooseBase(this, _updateCallbacks)[_updateCallbacks].forEach(callback => callback()); } /** * Zephr Server * * @public * @class * @property {string} orgId The Zephr Organisation ID * @property {string} apiEndpoint The Zephr API endpoint url */ class ZephrServer { /** * Create server instance * * @param {object} args Constructor arguments * @param {string} args.orgId The Zephr Organisation ID * @param {string=} args.apiEndpoint Override the Zephr API endpoint url. (Default: https://${orgId}.saas-public-api.zephr.com) */ constructor({ orgId, apiEndpoint } = {}) { if (!orgId) throw new Error('Organisation ID must be provided'); this.orgId = orgId; this.apiEndpoint = apiEndpoint || `https://${orgId}.saas-public-api.zephr.com`; } /** * Create Zephr access controller instance for request * * @description The Zephr access controller determines the current access state of a user * @async * @param {object} args Access controller arguments * @param {string=} args.jwt Secure JWT token * @param {string=} args.path URL path of initial page * @returns {Promise<ZephrAccessController|Error>} Promise resolves a running access controller */ async createAccessController({ jwt, path = '/' } = {}) { const accessController = new ZephrAccessController({ apiEndpoint: this.apiEndpoint }); await accessController.startAccessController({ jwt, path }); return accessController; } } /** * Create an instance of Zephr Server SDK * * @param {string} orgId The Zephr Organisation ID * @param {object=} args Optional arguments * @param {string=} args.apiEndpoint Override the Zephr API endpoint url * @returns {ZephrServer} A ZephrServer instance */ const createInstance = (orgId, { apiEndpoint } = {}) => { const server = new ZephrServer({ orgId, apiEndpoint }); return server; }; /** * @constant {string} version The version of the Zephr SDK */ const version = process.env.npm_package_version; exports.createInstance = createInstance; exports.version = version; //# sourceMappingURL=zephr-server-sdk.cjs.map