@fleetbase/ember-core 0.2.12 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,8 +8,11 @@ import { A, isArray } from '@ember/array';
8
8
  import { later } from '@ember/runloop';
9
9
  import { dasherize, camelize } from '@ember/string';
10
10
  import { getOwner } from '@ember/application';
11
- import { assert } from '@ember/debug';
11
+ import { assert, debug } from '@ember/debug';
12
12
  import RSVP from 'rsvp';
13
+ import loadInstalledExtensions from '../utils/load-installed-extensions';
14
+ import loadExtensions from '../utils/load-extensions';
15
+ import getWithDefault from '../utils/get-with-default';
13
16
 
14
17
  export default class UniverseService extends Service.extend(Evented) {
15
18
  @service router;
@@ -1269,6 +1272,155 @@ export default class UniverseService extends Service.extend(Evented) {
1269
1272
  return null;
1270
1273
  }
1271
1274
 
1275
+ /**
1276
+ * Boot all installed engines, ensuring dependencies are resolved.
1277
+ *
1278
+ * This method attempts to boot all installed engines by first checking if all
1279
+ * their dependencies are already booted. If an engine has dependencies that
1280
+ * are not yet booted, it is deferred and retried after its dependencies are
1281
+ * booted. If some dependencies are never booted, an error is logged.
1282
+ *
1283
+ * @method bootEngines
1284
+ * @param {ApplicationInstance|null} owner - The Ember ApplicationInstance that owns the engines.
1285
+ * @return {void}
1286
+ */
1287
+ bootEngines(owner = null) {
1288
+ const booted = [];
1289
+ const pending = [];
1290
+
1291
+ // If no owner provided use the owner of this service
1292
+ if (owner === null) {
1293
+ owner = getOwner(this);
1294
+ }
1295
+
1296
+ const tryBootEngine = (extension) => {
1297
+ this.loadEngine(extension.name).then((engineInstance) => {
1298
+ if (engineInstance.base && engineInstance.base.setupExtension) {
1299
+ const engineDependencies = getWithDefault(engineInstance.base, 'engineDependencies', []);
1300
+
1301
+ // Check if all dependency engines are booted
1302
+ const allDependenciesBooted = engineDependencies.every((dep) => booted.includes(dep));
1303
+
1304
+ if (!allDependenciesBooted) {
1305
+ pending.push({ extension, engineInstance });
1306
+ return;
1307
+ }
1308
+
1309
+ engineInstance.base.setupExtension(owner, engineInstance, this);
1310
+ booted.push(extension.name);
1311
+ debug(`Booted : ${extension.name}`);
1312
+
1313
+ // Try booting pending engines again
1314
+ tryBootPendingEngines();
1315
+ }
1316
+ });
1317
+ };
1318
+
1319
+ const tryBootPendingEngines = () => {
1320
+ const stillPending = [];
1321
+
1322
+ pending.forEach(({ extension, engineInstance }) => {
1323
+ const engineDependencies = getWithDefault(engineInstance.base, 'engineDependencies', []);
1324
+ const allDependenciesBooted = engineDependencies.every((dep) => booted.includes(dep));
1325
+
1326
+ if (allDependenciesBooted) {
1327
+ engineInstance.base.setupExtension(owner, engineInstance, this);
1328
+ booted.push(extension.name);
1329
+ debug(`Booted : ${extension.name}`);
1330
+ } else {
1331
+ stillPending.push({ extension, engineInstance });
1332
+ }
1333
+ });
1334
+
1335
+ // If no progress was made, log an error in debug/development mode
1336
+ assert('Some engines have unmet dependencies and cannot be booted:', pending.length === stillPending.length);
1337
+
1338
+ pending.length = 0;
1339
+ pending.push(...stillPending);
1340
+ };
1341
+
1342
+ loadInstalledExtensions().then((extensions) => {
1343
+ extensions.forEach((extension) => {
1344
+ tryBootEngine(extension);
1345
+ });
1346
+ });
1347
+ }
1348
+
1349
+ /**
1350
+ * Boots all installed engines, ensuring dependencies are resolved.
1351
+ *
1352
+ * This method loads all installed extensions and then attempts to boot each engine.
1353
+ * For each extension, it loads the engine and, if the engine has a `setupExtension`
1354
+ * method in its base, it calls this method to complete the setup. This function ensures
1355
+ * that dependencies are resolved before booting the engines. If some dependencies are
1356
+ * never booted, an error is logged.
1357
+ *
1358
+ * @method legacyBootEngines
1359
+ * @param {ApplicationInstance|null} owner - The Ember ApplicationInstance that owns the engines.
1360
+ * @return {void}
1361
+ */
1362
+ legacyBootEngines(owner = null) {
1363
+ const booted = [];
1364
+ const pending = [];
1365
+
1366
+ // If no owner provided use the owner of this service
1367
+ if (owner === null) {
1368
+ owner = getOwner(this);
1369
+ }
1370
+
1371
+ const tryBootEngine = (extension) => {
1372
+ this.loadEngine(extension.name).then((engineInstance) => {
1373
+ if (engineInstance.base && engineInstance.base.setupExtension) {
1374
+ const engineDependencies = getWithDefault(engineInstance.base, 'engineDependencies', []);
1375
+
1376
+ // Check if all dependency engines are booted
1377
+ const allDependenciesBooted = engineDependencies.every((dep) => booted.includes(dep));
1378
+
1379
+ if (!allDependenciesBooted) {
1380
+ pending.push({ extension, engineInstance });
1381
+ return;
1382
+ }
1383
+
1384
+ engineInstance.base.setupExtension(owner, engineInstance, this);
1385
+ booted.push(extension.name);
1386
+ debug(`Booted : ${extension.name}`);
1387
+
1388
+ // Try booting pending engines again
1389
+ tryBootPendingEngines();
1390
+ }
1391
+ });
1392
+ };
1393
+
1394
+ const tryBootPendingEngines = () => {
1395
+ const stillPending = [];
1396
+
1397
+ pending.forEach(({ extension, engineInstance }) => {
1398
+ const engineDependencies = getWithDefault(engineInstance.base, 'engineDependencies', []);
1399
+ const allDependenciesBooted = engineDependencies.every((dep) => booted.includes(dep));
1400
+
1401
+ if (allDependenciesBooted) {
1402
+ engineInstance.base.setupExtension(owner, engineInstance, this);
1403
+ booted.push(extension.name);
1404
+ debug(`Booted : ${extension.name}`);
1405
+ } else {
1406
+ stillPending.push({ extension, engineInstance });
1407
+ }
1408
+ });
1409
+
1410
+ // If no progress was made, log an error in debug/development mode
1411
+ assert('Some engines have unmet dependencies and cannot be booted:', pending.length === stillPending.length);
1412
+
1413
+ pending.length = 0;
1414
+ pending.push(...stillPending);
1415
+ };
1416
+
1417
+ loadExtensions().then((extensions) => {
1418
+ extensions.forEach((extension) => {
1419
+ tryBootEngine(extension);
1420
+ });
1421
+ });
1422
+ }
1423
+
1272
1424
  /**
1273
1425
  * Alias for intl service `t`
1274
1426
  *
@@ -0,0 +1,63 @@
1
+ import config from 'ember-get-config';
2
+
3
+ export default async function fleetbaseApiFetch(method, uri, params = {}, fetchOptions = {}) {
4
+ // Prepare base URL
5
+ const baseUrl = `${config.API.host}/${fetchOptions.namespace ?? config.API.namespace}`;
6
+
7
+ // Initialize headers
8
+ const headers = {
9
+ 'Content-Type': 'application/json',
10
+ };
11
+
12
+ // Check localStorage for the session data
13
+ const localStorageSession = JSON.parse(window.localStorage.getItem('ember_simple_auth-session'));
14
+ let token;
15
+ if (localStorageSession) {
16
+ const { authenticated } = localStorageSession;
17
+ if (authenticated) {
18
+ token = authenticated.token;
19
+ }
20
+ }
21
+
22
+ // Set Authorization header if token is available
23
+ if (token) {
24
+ headers['Authorization'] = `Bearer ${token}`;
25
+ }
26
+
27
+ // Configure request options
28
+ const options = {
29
+ method,
30
+ headers,
31
+ };
32
+
33
+ // Handle params based on method
34
+ if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(method) && params) {
35
+ options.body = JSON.stringify(params);
36
+ } else if (method === 'GET' && params) {
37
+ // Add params to URL for GET requests
38
+ const urlParams = new URLSearchParams(params).toString();
39
+ uri += `?${urlParams}`;
40
+ }
41
+
42
+ try {
43
+ // Make the fetch request
44
+ const response = await fetch(`${baseUrl}/${uri}`, options);
45
+
46
+ // Check if the response is OK (status in the range 200-299)
47
+ if (!response.ok) {
48
+ throw new Error(`HTTP error! status: ${response.status}`);
49
+ }
50
+
51
+ // Parse and return the JSON response
52
+ return await response.json();
53
+ } catch (error) {
54
+ // If a fallback response is provided use it instead
55
+ if (fetchOptions && fetchOptions.fallbackResponse !== undefined) {
56
+ return fetchOptions.fallbackResponse;
57
+ }
58
+
59
+ // Handle errors (network errors, JSON parsing errors, etc.)
60
+ console.error('Error making request:', error);
61
+ throw error;
62
+ }
63
+ }
@@ -0,0 +1,16 @@
1
+ import loadExtensions from '../utils/load-extensions';
2
+ import fleetbaseApiFetch from '../utils/fleetbase-api-fetch';
3
+
4
+ export default async function loadInstalledExtensions() {
5
+ const CORE_ENGINES = ['@fleetbase/fleetops-engine', '@fleetbase/storefront-engine', '@fleetbase/registry-bridge-engine', '@fleetbase/dev-engine', '@fleetbase/iam-engine'];
6
+ const INDEXED_ENGINES = await loadExtensions();
7
+ const INSTALLED_ENGINES = await fleetbaseApiFetch('get', 'engines', {}, { namespace: '~registry/v1', fallbackResponse: [] });
8
+
9
+ const isInstalledEngine = (engineName) => {
10
+ return CORE_ENGINES.includes(engineName) || INSTALLED_ENGINES.find((pkg) => pkg.name === engineName);
11
+ };
12
+
13
+ return INDEXED_ENGINES.filter((pkg) => {
14
+ return isInstalledEngine(pkg.name);
15
+ });
16
+ }
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/ember-core/utils/fleetbase-api-fetch';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/ember-core/utils/load-installed-extensions';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/ember-core",
3
- "version": "0.2.12",
3
+ "version": "0.2.13",
4
4
  "description": "Provides all the core services, decorators and utilities for building a Fleetbase extension for the Console.",
5
5
  "keywords": [
6
6
  "fleetbase-core",