web-manager 4.3.3 → 4.3.5

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.
package/dist/index.js CHANGED
@@ -99,7 +99,10 @@ class Manager {
99
99
  // convention). Reads flat `firebaseConfig` (BEM/BXM/EM canonical shape) and falls
100
100
  // back to nested `firebase.app.config` (UJM's current `_config.yml` shape).
101
101
  // Once UJM migrates to the flat shape this fallback can be dropped.
102
- if (this._resolveFirebaseConfig()) {
102
+ // Initialize Firebase only when the resolved config can actually boot the
103
+ // SDK — apiKey is mandatory (init without one crashes with auth/invalid-api-key).
104
+ // Configs carrying only projectId/authDomain still resolve for URL derivation.
105
+ if (this._resolveFirebaseConfig()?.apiKey) {
103
106
  await this._initializeFirebase();
104
107
  }
105
108
 
@@ -394,14 +397,20 @@ class Manager {
394
397
 
395
398
  // Resolve the Firebase web SDK config blob. Flat `firebaseConfig` first (canonical
396
399
  // shape — BEM/BXM/EM), then nested `firebase.app.config` (UJM legacy yaml shape).
397
- // Returns the blob when it has at least one own key, otherwise null.
400
+ // A blob only counts when at least one value is non-empty — framework config merges
401
+ // (e.g. UJM's Jekyll chain) inject all-empty-string blobs into Firebase-less sites,
402
+ // and those must resolve to null (no init, no URL derivation).
398
403
  _resolveFirebaseConfig() {
404
+ const hasValues = (blob) => !!blob
405
+ && typeof blob === 'object'
406
+ && Object.values(blob).some((value) => value);
407
+
399
408
  const flat = this.config.firebaseConfig;
400
- if (flat && typeof flat === 'object' && Object.keys(flat).length > 0) {
409
+ if (hasValues(flat)) {
401
410
  return flat;
402
411
  }
403
412
  const nested = this.config.firebase?.app?.config;
404
- if (nested && typeof nested === 'object' && Object.keys(nested).length > 0) {
413
+ if (hasValues(nested)) {
405
414
  return nested;
406
415
  }
407
416
  return null;
@@ -506,7 +515,9 @@ class Manager {
506
515
  || this.config.environment;
507
516
 
508
517
  if (env === 'development') {
509
- return 'http://localhost:5002';
518
+ // BEM's `mgr serve` exposes the local API over HTTPS (mkcert proxy on 5002,
519
+ // since backend-manager 5.7.0) — plain http:// cannot connect to it.
520
+ return 'https://localhost:5002';
510
521
  }
511
522
 
512
523
  const apiDomain = this._resolveFirebaseConfig()?.authDomain; // Has to be this since some projects like Clockii use ITW Universal Auth
@@ -526,6 +537,14 @@ class Manager {
526
537
  const returnUrlObject = new URL(decodeURIComponent(url));
527
538
  const currentUrlObject = new URL(window.location.href);
528
539
 
540
+ // Loopback returns (RFC 8252 §7.3) are valid while the SITE runs in development:
541
+ // native apps (Electron Manager) can't OS-register their custom scheme in dev, so
542
+ // their sign-in flow returns to an ephemeral 127.0.0.1 listener instead. Any port —
543
+ // the app binds it at flow start. Production sites never match this branch.
544
+ if (this.isDevelopment() && ['127.0.0.1', '[::1]', 'localhost'].includes(returnUrlObject.hostname)) {
545
+ return true;
546
+ }
547
+
529
548
  return returnUrlObject.host === currentUrlObject.host
530
549
  || returnUrlObject.protocol === this.config.brand?.id + ':'
531
550
  || (this.config.validRedirectHosts || []).includes(returnUrlObject.host);
@@ -50,3 +50,10 @@ Manager (index.js)
50
50
  ├── DOM utilities (standalone)
51
51
  └── Utilities (standalone)
52
52
  ```
53
+
54
+ ## Firebase Initialization
55
+
56
+ `initialize(config)` boots Firebase only when a usable web SDK config resolves:
57
+
58
+ - `_resolveFirebaseConfig()` checks the flat `firebaseConfig` blob first (canonical shape — BEM/BXM/EM), then the nested `firebase.app.config` (UJM yaml shape). A blob only counts when **at least one value is non-empty** — framework config merges (e.g. UJM's Jekyll chain) inject all-empty-string blobs into Firebase-less sites, and those resolve to `null` (no init, no URL derivation).
59
+ - Initialization additionally requires a **non-empty `apiKey`** — the SDK cannot boot without one (it crashes the page with `auth/invalid-api-key`). Configs carrying only `projectId`/`authDomain` still resolve so `getFunctionsUrl()`/`getApiUrl()` can derive URLs, but Firebase itself stays uninitialized.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-manager",
3
- "version": "4.3.3",
3
+ "version": "4.3.5",
4
4
  "description": "Easily access important variables such as the query string, current domain, and current page in a single object.",
5
5
  "main": "dist/index.js",
6
6
  "files": [
package/src/index.js CHANGED
@@ -99,7 +99,10 @@ class Manager {
99
99
  // convention). Reads flat `firebaseConfig` (BEM/BXM/EM canonical shape) and falls
100
100
  // back to nested `firebase.app.config` (UJM's current `_config.yml` shape).
101
101
  // Once UJM migrates to the flat shape this fallback can be dropped.
102
- if (this._resolveFirebaseConfig()) {
102
+ // Initialize Firebase only when the resolved config can actually boot the
103
+ // SDK — apiKey is mandatory (init without one crashes with auth/invalid-api-key).
104
+ // Configs carrying only projectId/authDomain still resolve for URL derivation.
105
+ if (this._resolveFirebaseConfig()?.apiKey) {
103
106
  await this._initializeFirebase();
104
107
  }
105
108
 
@@ -394,14 +397,20 @@ class Manager {
394
397
 
395
398
  // Resolve the Firebase web SDK config blob. Flat `firebaseConfig` first (canonical
396
399
  // shape — BEM/BXM/EM), then nested `firebase.app.config` (UJM legacy yaml shape).
397
- // Returns the blob when it has at least one own key, otherwise null.
400
+ // A blob only counts when at least one value is non-empty — framework config merges
401
+ // (e.g. UJM's Jekyll chain) inject all-empty-string blobs into Firebase-less sites,
402
+ // and those must resolve to null (no init, no URL derivation).
398
403
  _resolveFirebaseConfig() {
404
+ const hasValues = (blob) => !!blob
405
+ && typeof blob === 'object'
406
+ && Object.values(blob).some((value) => value);
407
+
399
408
  const flat = this.config.firebaseConfig;
400
- if (flat && typeof flat === 'object' && Object.keys(flat).length > 0) {
409
+ if (hasValues(flat)) {
401
410
  return flat;
402
411
  }
403
412
  const nested = this.config.firebase?.app?.config;
404
- if (nested && typeof nested === 'object' && Object.keys(nested).length > 0) {
413
+ if (hasValues(nested)) {
405
414
  return nested;
406
415
  }
407
416
  return null;
@@ -506,7 +515,9 @@ class Manager {
506
515
  || this.config.environment;
507
516
 
508
517
  if (env === 'development') {
509
- return 'http://localhost:5002';
518
+ // BEM's `mgr serve` exposes the local API over HTTPS (mkcert proxy on 5002,
519
+ // since backend-manager 5.7.0) — plain http:// cannot connect to it.
520
+ return 'https://localhost:5002';
510
521
  }
511
522
 
512
523
  const apiDomain = this._resolveFirebaseConfig()?.authDomain; // Has to be this since some projects like Clockii use ITW Universal Auth
@@ -526,6 +537,14 @@ class Manager {
526
537
  const returnUrlObject = new URL(decodeURIComponent(url));
527
538
  const currentUrlObject = new URL(window.location.href);
528
539
 
540
+ // Loopback returns (RFC 8252 §7.3) are valid while the SITE runs in development:
541
+ // native apps (Electron Manager) can't OS-register their custom scheme in dev, so
542
+ // their sign-in flow returns to an ephemeral 127.0.0.1 listener instead. Any port —
543
+ // the app binds it at flow start. Production sites never match this branch.
544
+ if (this.isDevelopment() && ['127.0.0.1', '[::1]', 'localhost'].includes(returnUrlObject.hostname)) {
545
+ return true;
546
+ }
547
+
529
548
  return returnUrlObject.host === currentUrlObject.host
530
549
  || returnUrlObject.protocol === this.config.brand?.id + ':'
531
550
  || (this.config.validRedirectHosts || []).includes(returnUrlObject.host);