Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PoC: Lazy load more dependencies #891

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions lib/2fa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const get2fa = function(
deps: InjectedDependenciesParam,
opts: InjectedOptionsParam,
) {
const { auth, request } = deps;
const { apiUrl } = opts;

/**
Expand Down Expand Up @@ -53,7 +52,7 @@ const get2fa = function(
function isEnabled(
callback?: (error?: Error, result?: boolean) => void,
): Promise<boolean> {
return auth
return deps.auth
.needs2FA()
.then(twoFactorRequired => twoFactorRequired != null)
.asCallback(callback);
Expand Down Expand Up @@ -88,7 +87,7 @@ const get2fa = function(
function isPassed(
callback?: (error?: Error, result?: boolean) => void,
): Promise<boolean> {
return auth
return deps.auth
.needs2FA()
.then(twoFactorRequired => !twoFactorRequired)
.asCallback(callback);
Expand Down Expand Up @@ -116,15 +115,15 @@ const get2fa = function(
code: string,
callback?: (error?: Error) => void,
): Promise<void> {
return request
return deps.request
.send({
method: 'POST',
url: '/auth/totp/verify',
baseUrl: apiUrl,
body: { code },
})
.get('body')
.then(auth.setKey)
.then(deps.auth.setKey)
.asCallback(callback);
}

Expand Down
24 changes: 10 additions & 14 deletions lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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,
);

Expand All @@ -78,7 +74,7 @@ const getAuth = function(
if (userDetailsCache) {
return userDetailsCache;
}
return request
return deps.request
.send<WhoamiResult>({
method: 'GET',
url: '/user/v1/whoami',
Expand Down Expand Up @@ -171,7 +167,7 @@ const getAuth = function(
},
callback?: (error?: Error, result?: string) => void,
): Promise<string> {
return request
return deps.request
.send<string>({
method: 'POST',
baseUrl: apiUrl,
Expand Down Expand Up @@ -447,7 +443,7 @@ const getAuth = function(
},
callback?: (error?: Error, result?: string) => void,
): Promise<string> {
return request
return deps.request
.send({
method: 'POST',
url: '/user/register',
Expand Down
108 changes: 59 additions & 49 deletions lib/balena.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
});

/**
Expand Down Expand Up @@ -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);
},
});

Expand All @@ -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
Expand All @@ -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
Expand All @@ -251,7 +261,7 @@ const getSdk = function(opts) {
* }
* });
*/
sdk.pine = pine;
defineProperty(sdk, 'pine', () => deps.pine);

/**
* @summary Balena errors module
Expand All @@ -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;
};
Expand Down