From a8055c10c328b5b2fd085b76e1c9425ff2ca6c94 Mon Sep 17 00:00:00 2001 From: Pagan Gazzard Date: Tue, 21 Apr 2020 17:11:24 +0100 Subject: [PATCH] Lazy load more dependencies Change-type: PoC --- lib/2fa.ts | 9 ++--- lib/auth.ts | 24 +++++------ lib/balena.js | 108 +++++++++++++++++++++++++++----------------------- 3 files changed, 73 insertions(+), 68 deletions(-) diff --git a/lib/2fa.ts b/lib/2fa.ts index bcd47d793..d027cf887 100644 --- a/lib/2fa.ts +++ b/lib/2fa.ts @@ -21,7 +21,6 @@ const get2fa = function( deps: InjectedDependenciesParam, opts: InjectedOptionsParam, ) { - const { auth, request } = deps; const { apiUrl } = opts; /** @@ -53,7 +52,7 @@ const get2fa = function( function isEnabled( callback?: (error?: Error, result?: boolean) => void, ): Promise { - return auth + return deps.auth .needs2FA() .then(twoFactorRequired => twoFactorRequired != null) .asCallback(callback); @@ -88,7 +87,7 @@ const get2fa = function( function isPassed( callback?: (error?: Error, result?: boolean) => void, ): Promise { - return auth + return deps.auth .needs2FA() .then(twoFactorRequired => !twoFactorRequired) .asCallback(callback); @@ -116,7 +115,7 @@ const get2fa = function( code: string, callback?: (error?: Error) => void, ): Promise { - return request + return deps.request .send({ method: 'POST', url: '/auth/totp/verify', @@ -124,7 +123,7 @@ const get2fa = function( body: { code }, }) .get('body') - .then(auth.setKey) + .then(deps.auth.setKey) .asCallback(callback); } diff --git a/lib/auth.ts b/lib/auth.ts index 4b4101c3a..14134c82c 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -24,7 +24,6 @@ const getAuth = function( deps: InjectedDependenciesParam, opts: InjectedOptionsParam, ) { - const { auth: authBase, pubsub, request } = deps; const { apiUrl } = opts; const normalizeAuthError = function(err: errors.BalenaRequestError) { @@ -43,25 +42,22 @@ const getAuth = function( ): T => function() { return fn - .apply(authBase, arguments) - .finally(() => pubsub.publish(eventName)); + .apply(deps.auth, arguments) + .finally(() => deps.pubsub.publish(eventName)); } as T; const auth = { - ...authBase, - setKey: wrapAuthFn('auth.keyChange', authBase.setKey), - removeKey: wrapAuthFn('auth.keyChange', authBase.removeKey), - } as typeof authBase; + ...deps.auth, + setKey: wrapAuthFn('auth.keyChange', deps.auth.setKey), + removeKey: wrapAuthFn('auth.keyChange', deps.auth.removeKey), + } as typeof deps.auth; /** * @namespace balena.auth.twoFactor * @memberof balena.auth */ const twoFactor = (require('./2fa').default as typeof _get2faModel)( - { - ...deps, - auth, - }, + deps, opts, ); @@ -78,7 +74,7 @@ const getAuth = function( if (userDetailsCache) { return userDetailsCache; } - return request + return deps.request .send({ method: 'GET', url: '/user/v1/whoami', @@ -171,7 +167,7 @@ const getAuth = function( }, callback?: (error?: Error, result?: string) => void, ): Promise { - return request + return deps.request .send({ method: 'POST', baseUrl: apiUrl, @@ -447,7 +443,7 @@ const getAuth = function( }, callback?: (error?: Error, result?: string) => void, ): Promise { - return request + return deps.request .send({ method: 'POST', url: '/user/register', diff --git a/lib/balena.js b/lib/balena.js index 70cfae81a..a53595160 100644 --- a/lib/balena.js +++ b/lib/balena.js @@ -35,16 +35,9 @@ const BALENA_SDK_HAS_SET_SHARED_OPTIONS = 'BALENA_SDK_HAS_SET_SHARED_OPTIONS'; */ const getSdk = function(opts) { - let settings; if (opts == null) { opts = {}; } - const version = require('./util/sdk-version').default; - const getRequest = require('balena-request'); - const BalenaAuth = require('balena-auth')['default']; - const getPine = require('balena-pine'); - const errors = require('balena-errors'); - const { PubSub } = require('./util/pubsub'); /** * @namespace models @@ -92,46 +85,65 @@ const getSdk = function(opts) { opts, ); - if (opts.isBrowser) { - const { notImplemented } = require('./util'); - settings = { - get: notImplemented, - getAll: notImplemented, - }; - } else { - settings = require('balena-settings-client'); - if (opts.dataDirectory == null) { - opts.dataDirectory = settings.get('dataDirectory'); - } - } - - const auth = new BalenaAuth(opts); - const request = getRequest(Object.assign({}, opts, { auth })); - const pine = getPine(Object.assign({}, opts, { auth, request })); - const pubsub = new PubSub(); - - const sdk = {}; - const deps = { - settings, - request, - auth, - pine, - pubsub, - sdkInstance: sdk, - }; - - Object.keys(sdkTemplate).forEach(function(moduleName) { - Object.defineProperty(sdk, moduleName, { + const defineProperty = (obj, propName, fn) => { + Object.defineProperty(obj, propName, { enumerable: true, configurable: true, get() { - const moduleFactory = sdkTemplate[moduleName](); // We need the delete first as the current property is read-only // and the delete removes that restriction - delete this[moduleName]; - return (this[moduleName] = moduleFactory(deps, opts)); + delete this[propName]; + return (this[propName] = fn()); }, }); + }; + + const sdk = {}; + Object.keys(sdkTemplate).forEach(function(moduleName) { + defineProperty(sdk, moduleName, () => { + const moduleFactory = sdkTemplate[moduleName](); + return moduleFactory(deps, opts); + }); + }); + + const deps = { + sdkInstance: sdk, + }; + defineProperty(deps, 'auth', () => { + const BalenaAuth = require('balena-auth').default; + return new BalenaAuth(opts); + }); + defineProperty(deps, 'request', () => { + const getRequest = require('balena-request'); + const request = getRequest(Object.assign({}, opts, { auth: deps.auth })); + request.interceptors.push(versionHeaderInterceptor); + return request; + }); + defineProperty(deps, 'pine', () => { + const getPine = require('balena-pine'); + return getPine( + Object.assign({}, opts, { auth: deps.auth, request: deps.request }), + ); + }); + defineProperty(deps, 'pubsub', () => { + const { PubSub } = require('./util/pubsub'); + return new PubSub(); + }); + defineProperty(deps, 'settings', () => { + let settings; + if (opts.isBrowser) { + const { notImplemented } = require('./util'); + settings = { + get: notImplemented, + getAll: notImplemented, + }; + } else { + settings = require('balena-settings-client'); + if (opts.dataDirectory == null) { + opts.dataDirectory = settings.get('dataDirectory'); + } + } + return settings; }); /** @@ -186,10 +198,10 @@ const getSdk = function(opts) { Object.defineProperty(sdk, 'interceptors', { /** @private @returns Interceptor[] */ get() { - return request.interceptors; + return deps.request.interceptors; }, set(/** @type Interceptor[] */ interceptors) { - return (request.interceptors = interceptors); + return (deps.request.interceptors = interceptors); }, }); @@ -206,15 +218,13 @@ const getSdk = function(opts) { } if (url.indexOf(opts.apiUrl) === 0) { - $request.headers['X-Balena-Client'] = `balena-sdk/${version}`; + $request.headers['X-Balena-Client'] = `balena-sdk/${sdk.version}`; } return $request; }, }; - sdk.interceptors.push(versionHeaderInterceptor); - /** * @summary Balena request instance * @member {Object} request @@ -229,7 +239,7 @@ const getSdk = function(opts) { * @example * balena.request.send({ url: 'http://api.balena-cloud.com/ping' }); */ - sdk.request = request; + defineProperty(sdk, 'request', () => deps.request); /** * @summary Balena pine instance @@ -251,7 +261,7 @@ const getSdk = function(opts) { * } * }); */ - sdk.pine = pine; + defineProperty(sdk, 'pine', () => deps.pine); /** * @summary Balena errors module @@ -274,9 +284,9 @@ const getSdk = function(opts) { * } * }); */ - sdk.errors = errors; + defineProperty(sdk, 'errors', () => require('balena-errors')); - sdk.version = version; + defineProperty(sdk, 'version', () => require('./util/sdk-version').default); return sdk; };