@sumaris-net/ngx-components 18.24.24 → 18.25.0

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.
Files changed (37) hide show
  1. package/doc/changelog.md +7 -0
  2. package/esm2022/src/app/core/services/account.service.mjs +33 -10
  3. package/esm2022/src/app/core/services/platform.service.mjs +3 -3
  4. package/esm2022/src/app/core/services/startup.constants.mjs +10 -0
  5. package/esm2022/src/app/core/services/startup.model.mjs +2 -0
  6. package/esm2022/src/app/core/services/startup.service.mjs +148 -0
  7. package/esm2022/src/app/shared/shared.module.mjs +2 -2
  8. package/esm2022/src/app/shared/storage/storage.service.mjs +2 -3
  9. package/esm2022/src/environments/environment.class.mjs +4 -1
  10. package/esm2022/src/environments/environment.mjs +2 -1
  11. package/esm2022/testing/sumaris-net-ngx-components-testing.mjs +5 -0
  12. package/esm2022/testing/test/login-env.mjs +122 -0
  13. package/esm2022/testing/testing_api.mjs +10 -0
  14. package/esm2022/testing/utils/auth.utils.mjs +64 -0
  15. package/esm2022/testing/utils/ionic.utils.mjs +66 -0
  16. package/esm2022/testing/utils/material.utils.mjs +100 -0
  17. package/esm2022/testing/utils/startup.constants.mjs +4 -0
  18. package/esm2022/testing/utils/ui.utils.mjs +139 -0
  19. package/fesm2022/sumaris-net-ngx-components-testing.mjs +499 -0
  20. package/fesm2022/sumaris-net-ngx-components-testing.mjs.map +1 -0
  21. package/fesm2022/sumaris-net.ngx-components.mjs +314 -139
  22. package/fesm2022/sumaris-net.ngx-components.mjs.map +1 -1
  23. package/package.json +8 -1
  24. package/src/app/core/services/account.service.d.ts +5 -2
  25. package/src/app/core/services/startup.constants.d.ts +1 -0
  26. package/src/app/core/services/startup.model.d.ts +1 -0
  27. package/src/app/core/services/startup.service.d.ts +31 -0
  28. package/src/assets/manifest.json +1 -1
  29. package/src/environments/environment.class.d.ts +2 -0
  30. package/testing/index.d.ts +5 -0
  31. package/testing/test/login-env.d.ts +76 -0
  32. package/testing/testing_api.d.ts +6 -0
  33. package/testing/utils/auth.utils.d.ts +21 -0
  34. package/testing/utils/ionic.utils.d.ts +51 -0
  35. package/testing/utils/material.utils.d.ts +57 -0
  36. package/testing/utils/startup.constants.d.ts +1 -0
  37. package/testing/utils/ui.utils.d.ts +79 -0
@@ -222,6 +222,9 @@ class Environment {
222
222
  // Default authentication /!\ For DEV only
223
223
  // (see values in the test database - XML files in Pod's module)
224
224
  defaultAuthValues;
225
+ // Auto login /!\ For DEV only
226
+ // (the order defines the method precedence)
227
+ startupOrder;
225
228
  // Account
226
229
  account;
227
230
  entityEditor;
@@ -16440,138 +16443,6 @@ const StorageDrivers = {
16440
16443
  };
16441
16444
  const APP_STORAGE = new InjectionToken('Storage');
16442
16445
 
16443
- // This file can be replaced during build by using the `fileReplacements` array.
16444
- // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
16445
- // The list of file replacements can be found in `angular.json`.
16446
- /*
16447
- * In development mode, to ignore zone related error stack frames such as
16448
- * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
16449
- * import the following file, but please comment it out in production mode
16450
- * because it will have performance impact when throw error
16451
- */
16452
- //import 'zone.js/plugins/zone-error';
16453
- const environment = Object.freeze({
16454
- name: '@sumaris-net/ngx-components', // overridden by ENVIRONMENT token
16455
- version: '1.0', // overridden by ENVIRONMENT token
16456
- // Do NOT set to false - because this value will be used by releases
16457
- //production: false,
16458
- production: true,
16459
- // Do NOT set - because this value will be used by releases
16460
- //externalEnvironmentUrl: null,
16461
- baseUrl: '/',
16462
- defaultLocale: 'fr',
16463
- defaultLatLongFormat: 'DDMM',
16464
- apolloFetchPolicy: 'cache-first',
16465
- useHash: false,
16466
- allowDarkMode: true,
16467
- //defaultRoute: '/home',
16468
- //enableMenu: true,
16469
- // FIXME: enable cache
16470
- persistCache: false,
16471
- // TODO: make this works
16472
- //offline: true,
16473
- peerMinVersion: '1.8.0',
16474
- peerDefaultPrefix: 'http://',
16475
- enableSelectPeerByFeature: true,
16476
- sendAppVersionHeaders: true,
16477
- defaultPeer: {
16478
- host: 'localhost',
16479
- port: 8081,
16480
- },
16481
- defaultPeers: [
16482
- {
16483
- host: 'localhost',
16484
- port: 8080,
16485
- },
16486
- {
16487
- host: 'localhost',
16488
- port: 8081,
16489
- },
16490
- {
16491
- host: '192.168.0.45',
16492
- port: 8080,
16493
- },
16494
- {
16495
- host: '192.168.0.24',
16496
- port: 8080,
16497
- },
16498
- {
16499
- host: '192.168.0.29',
16500
- port: 8080,
16501
- },
16502
- {
16503
- host: '192.168.0.107',
16504
- port: 8080,
16505
- },
16506
- {
16507
- host: 'sih.sfa.sc',
16508
- port: 443,
16509
- },
16510
- {
16511
- host: 'test.sumaris.net',
16512
- port: 443,
16513
- },
16514
- {
16515
- host: 'open.sumaris.net',
16516
- port: 443,
16517
- },
16518
- {
16519
- host: 'server.e-is.pro',
16520
- port: 443,
16521
- },
16522
- ],
16523
- defaultAppName: 'SUMARiS',
16524
- defaultAndroidInstallUrl: 'https://play.google.com/store/apps/details?id=net.sumaris.app',
16525
- defaultIOSInstallUrl: 'https://apps.apple.com/us/app/sumaris/id6736747523',
16526
- defaultDesktopInstallUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-app/-/releases',
16527
- // Storage
16528
- storage: {
16529
- driverOrder: [StorageDrivers.SQLLite, StorageDrivers.IndexedDB, StorageDrivers.WebSQL, StorageDrivers.LocalStorage],
16530
- },
16531
- // About
16532
- sourceUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components',
16533
- reportIssueUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components/-/issues',
16534
- forumUrl: null, //'https://forum.sumaris.net',
16535
- helpUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-doc/-/blob/master/user-manual/index_fr.md',
16536
- privacyPolicyUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-app/-/raw/master/doc/privacy_policy_fr.md',
16537
- termsOfUseUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-app/-/raw/master/doc/terms_of_use_fr.md?ref_type=heads',
16538
- // Development
16539
- defaultAuthValues: {
16540
- // Token auth (using Person.pubkey)
16541
- username: 'admin@sumaris.net',
16542
- password: 'admin',
16543
- },
16544
- account: {
16545
- enableListenChanges: true,
16546
- listenIntervalInSeconds: 60,
16547
- enableAvatarEdit: true,
16548
- },
16549
- entityEditor: {
16550
- enableListenChanges: true,
16551
- listenIntervalInSeconds: 60,
16552
- },
16553
- feed: {
16554
- jsonFeed: {
16555
- fr: [
16556
- '/api/feed.json',
16557
- 'https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components/-/raw/master/doc/feed/feed-fr.json',
16558
- // Example with JsonFeed version 1 (and not 1.1)
16559
- //'https://raw.githubusercontent.com/duniter/cesium/master/doc/feed/feed-fr.json',
16560
- // Example with discourse API :
16561
- //'https://raw.githubusercontent.com/duniter/cesium/master/doc/feed/1.1/feed-fr-FR.json',
16562
- ],
16563
- en: [
16564
- '/api/feed.json',
16565
- 'https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components/-/raw/master/doc/feed/feed-en.json'
16566
- ],
16567
- },
16568
- maxContentLength: 1000,
16569
- maxAgeInMonths: -1,
16570
- maxCount: 3,
16571
- },
16572
- buildDate: new Date().toISOString(),
16573
- });
16574
-
16575
16446
  class StorageService extends StartableService {
16576
16447
  storage;
16577
16448
  environment;
@@ -16587,7 +16458,7 @@ class StorageService extends StartableService {
16587
16458
  }
16588
16459
  async ngOnStart() {
16589
16460
  try {
16590
- console.debug(`[storage] Starting... {driverOrder: ${environment.storage?.driverOrder}}`);
16461
+ console.debug(`[storage] Starting... {driverOrder: ${this.environment.storage?.driverOrder}}`);
16591
16462
  // Define Cordova SQLLite driver
16592
16463
  await this.storage.defineDriver(CordovaSQLiteDriver);
16593
16464
  // Create the storage instance
@@ -17106,6 +16977,139 @@ function isOnFieldMode(value) {
17106
16977
  }
17107
16978
  const APP_LOCALES = new InjectionToken('locales');
17108
16979
 
16980
+ // This file can be replaced during build by using the `fileReplacements` array.
16981
+ // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
16982
+ // The list of file replacements can be found in `angular.json`.
16983
+ /*
16984
+ * In development mode, to ignore zone related error stack frames such as
16985
+ * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
16986
+ * import the following file, but please comment it out in production mode
16987
+ * because it will have performance impact when throw error
16988
+ */
16989
+ //import 'zone.js/plugins/zone-error';
16990
+ const environment = Object.freeze({
16991
+ name: '@sumaris-net/ngx-components', // overridden by ENVIRONMENT token
16992
+ version: '1.0', // overridden by ENVIRONMENT token
16993
+ // Do NOT set to false - because this value will be used by releases
16994
+ //production: false,
16995
+ production: true,
16996
+ // Do NOT set - because this value will be used by releases
16997
+ //externalEnvironmentUrl: null,
16998
+ baseUrl: '/',
16999
+ defaultLocale: 'fr',
17000
+ defaultLatLongFormat: 'DDMM',
17001
+ apolloFetchPolicy: 'cache-first',
17002
+ useHash: false,
17003
+ allowDarkMode: true,
17004
+ //defaultRoute: '/home',
17005
+ //enableMenu: true,
17006
+ // FIXME: enable cache
17007
+ persistCache: false,
17008
+ // TODO: make this works
17009
+ //offline: true,
17010
+ peerMinVersion: '1.8.0',
17011
+ peerDefaultPrefix: 'http://',
17012
+ enableSelectPeerByFeature: true,
17013
+ sendAppVersionHeaders: true,
17014
+ defaultPeer: {
17015
+ host: 'localhost',
17016
+ port: 8081,
17017
+ },
17018
+ defaultPeers: [
17019
+ {
17020
+ host: 'localhost',
17021
+ port: 8080,
17022
+ },
17023
+ {
17024
+ host: 'localhost',
17025
+ port: 8081,
17026
+ },
17027
+ {
17028
+ host: '192.168.0.45',
17029
+ port: 8080,
17030
+ },
17031
+ {
17032
+ host: '192.168.0.24',
17033
+ port: 8080,
17034
+ },
17035
+ {
17036
+ host: '192.168.0.29',
17037
+ port: 8080,
17038
+ },
17039
+ {
17040
+ host: '192.168.0.107',
17041
+ port: 8080,
17042
+ },
17043
+ {
17044
+ host: 'sih.sfa.sc',
17045
+ port: 443,
17046
+ },
17047
+ {
17048
+ host: 'test.sumaris.net',
17049
+ port: 443,
17050
+ },
17051
+ {
17052
+ host: 'open.sumaris.net',
17053
+ port: 443,
17054
+ },
17055
+ {
17056
+ host: 'server.e-is.pro',
17057
+ port: 443,
17058
+ },
17059
+ ],
17060
+ defaultAppName: 'SUMARiS',
17061
+ defaultAndroidInstallUrl: 'https://play.google.com/store/apps/details?id=net.sumaris.app',
17062
+ defaultIOSInstallUrl: 'https://apps.apple.com/us/app/sumaris/id6736747523',
17063
+ defaultDesktopInstallUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-app/-/releases',
17064
+ // Storage
17065
+ storage: {
17066
+ driverOrder: [StorageDrivers.SQLLite, StorageDrivers.IndexedDB, StorageDrivers.WebSQL, StorageDrivers.LocalStorage],
17067
+ },
17068
+ // About
17069
+ sourceUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components',
17070
+ reportIssueUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components/-/issues',
17071
+ forumUrl: null, //'https://forum.sumaris.net',
17072
+ helpUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-doc/-/blob/master/user-manual/index_fr.md',
17073
+ privacyPolicyUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-app/-/raw/master/doc/privacy_policy_fr.md',
17074
+ termsOfUseUrl: 'https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-app/-/raw/master/doc/terms_of_use_fr.md?ref_type=heads',
17075
+ // Development
17076
+ defaultAuthValues: {
17077
+ // Token auth (using Person.pubkey)
17078
+ username: 'admin@sumaris.net',
17079
+ password: 'admin',
17080
+ },
17081
+ startupOrder: ['url', 'window', 'environment'],
17082
+ account: {
17083
+ enableListenChanges: true,
17084
+ listenIntervalInSeconds: 60,
17085
+ enableAvatarEdit: true,
17086
+ },
17087
+ entityEditor: {
17088
+ enableListenChanges: true,
17089
+ listenIntervalInSeconds: 60,
17090
+ },
17091
+ feed: {
17092
+ jsonFeed: {
17093
+ fr: [
17094
+ '/api/feed.json',
17095
+ 'https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components/-/raw/master/doc/feed/feed-fr.json',
17096
+ // Example with JsonFeed version 1 (and not 1.1)
17097
+ //'https://raw.githubusercontent.com/duniter/cesium/master/doc/feed/feed-fr.json',
17098
+ // Example with discourse API :
17099
+ //'https://raw.githubusercontent.com/duniter/cesium/master/doc/feed/1.1/feed-fr-FR.json',
17100
+ ],
17101
+ en: [
17102
+ '/api/feed.json',
17103
+ 'https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components/-/raw/master/doc/feed/feed-en.json'
17104
+ ],
17105
+ },
17106
+ maxContentLength: 1000,
17107
+ maxAgeInMonths: -1,
17108
+ maxCount: 3,
17109
+ },
17110
+ buildDate: new Date().toISOString(),
17111
+ });
17112
+
17109
17113
  class EntityClasses {
17110
17114
  static CLASSES_BY_NAME = new Map();
17111
17115
  static register(typename, entityClass) {
@@ -23893,6 +23897,154 @@ class Base58 {
23893
23897
  }
23894
23898
  }
23895
23899
 
23900
+ // Standalone startup constants, with NO Angular DI dependency.
23901
+ // Kept separate from startup.service.ts so it can be safely imported by e2e tests
23902
+ // (Playwright's transpiler does not support Angular parameter decorators).
23903
+ // Key used to bridge auto-peer/login data across a version-check reload.
23904
+ // platform.service may reload the page via location.href = ..., which destroys both
23905
+ // URL params (hash/search) and the window object. sessionStorage survives same-tab
23906
+ // reloads, is tab-scoped, non-persistent (cleared on tab close), and not accessible
23907
+ // cross-origin — making it safe for transient credential bridging.
23908
+ const STARTUP_DATA_STORAGE_KEY = '__appStartupData';
23909
+
23910
+ class StartupService {
23911
+ _data = { password: null, username: null, offline: null, peerUrl: null };
23912
+ storage = inject(StorageService);
23913
+ environment = inject(ENVIRONMENT, { optional: true });
23914
+ get data() {
23915
+ return this._data;
23916
+ }
23917
+ set data(data) {
23918
+ if (isNotNilOrBlank(data.username))
23919
+ this._data.username = data.username;
23920
+ if (isNotNilOrBlank(data.password))
23921
+ this._data.password = data.password;
23922
+ if (isNotNil(data.offline))
23923
+ this._data.offline = data.offline;
23924
+ if (isNotNilOrBlank(data.peerUrl))
23925
+ this._data.peerUrl = data.peerUrl;
23926
+ }
23927
+ hasPeer() {
23928
+ return isNotNilOrBlank(this._data?.peerUrl);
23929
+ }
23930
+ consumePeer() {
23931
+ if (!this._data)
23932
+ return null;
23933
+ const autoPeer = this._data?.peerUrl;
23934
+ this._data.peerUrl = null;
23935
+ return autoPeer;
23936
+ }
23937
+ hasAuth() {
23938
+ return isNotNilOrBlank(this._data?.username) && isNotNilOrBlank(this._data?.password);
23939
+ }
23940
+ consumeAuth() {
23941
+ if (!this._data)
23942
+ return null;
23943
+ const { username, password, offline } = this._data;
23944
+ this._data.username = null;
23945
+ this._data.password = null;
23946
+ this._data.offline = null;
23947
+ return { username, password, offline };
23948
+ }
23949
+ async start() {
23950
+ const authMethods = this.environment?.startupOrder;
23951
+ if (isEmptyArray(authMethods))
23952
+ return; // Skip if no auth methods configured
23953
+ await this.storage.ready();
23954
+ console.debug(`[startup] Initializing methods: ${authMethods.join(' -> ')}`);
23955
+ const urlHashParams = new URLSearchParams(window.location.hash?.slice(1) || '');
23956
+ const urlSearchParams = new URLSearchParams(window.location.search);
23957
+ const windowStartupData = window[STARTUP_DATA_STORAGE_KEY];
23958
+ const rawData = sessionStorage.getItem(STARTUP_DATA_STORAGE_KEY);
23959
+ const data = rawData ? JSON.parse(rawData) : null;
23960
+ const settingsRaw = await this.storage.get('settings');
23961
+ const settings = typeof settingsRaw === 'string' ? JSON.parse(settingsRaw) : (settingsRaw ?? {});
23962
+ // Resolve auto auth data from each configured source
23963
+ if (data) {
23964
+ // Restore from sessionStorage in case of a previous version-check reload
23965
+ this.data = data;
23966
+ }
23967
+ else {
23968
+ // Resolve each configured source by priority (first method has highest priority)
23969
+ let username = null;
23970
+ let password = null;
23971
+ let offline = null;
23972
+ let peerUrl = null;
23973
+ for (const authMethod of authMethods.reverse()) {
23974
+ switch (authMethod) {
23975
+ case 'url':
23976
+ username = urlHashParams.get('username') || urlSearchParams.get('username');
23977
+ password = urlHashParams.get('password') || urlSearchParams.get('password');
23978
+ offline = urlHashParams.get('offline') === 'true' || urlSearchParams.get('offline') === 'true';
23979
+ peerUrl = urlHashParams.get('peerUrl') || urlSearchParams.get('peerUrl');
23980
+ break;
23981
+ case 'window':
23982
+ username = windowStartupData?.username ?? null;
23983
+ password = windowStartupData?.password ?? null;
23984
+ offline = windowStartupData?.offline ?? null;
23985
+ peerUrl = windowStartupData?.peerUrl ?? null;
23986
+ break;
23987
+ case 'environment':
23988
+ username = this.environment?.defaultAuthValues?.username;
23989
+ password = this.environment?.defaultAuthValues?.password;
23990
+ offline = this.environment?.offline;
23991
+ peerUrl = Peer.fromObject(this.environment?.peer)?.url ||
23992
+ settings?.peerUrl || Peer.fromObject(this.environment.defaultPeer)?.url;
23993
+ break;
23994
+ default:
23995
+ console.warn('[startup] Unknown method:', authMethod);
23996
+ }
23997
+ this.data = { username, password, offline, peerUrl };
23998
+ }
23999
+ }
24000
+ const sensitiveParams = ['username', 'password', 'offline', 'peerUrl'];
24001
+ const hasHashSensitiveParam = sensitiveParams.some((p) => urlHashParams.has(p));
24002
+ const hasSearchSensitiveParam = sensitiveParams.some((p) => urlSearchParams.has(p));
24003
+ const hasWindowData = !!windowStartupData;
24004
+ const hasExternalSource = hasHashSensitiveParam || hasSearchSensitiveParam || hasWindowData;
24005
+ // Persist to sessionStorage so data survives a potential version-check reload
24006
+ if (hasExternalSource && (this.hasPeer() || this.hasAuth())) {
24007
+ sessionStorage.setItem(STARTUP_DATA_STORAGE_KEY, JSON.stringify(this._data));
24008
+ }
24009
+ // Apply auto peer by saving peerUrl to localStorage so the app connects to the right peer
24010
+ if (this.hasPeer()) {
24011
+ settings.peerUrl = this.consumePeer();
24012
+ console.debug(`[startup] Set peer URL to ${settings.peerUrl}`);
24013
+ await this.storage.set('settings', JSON.stringify(settings));
24014
+ }
24015
+ // Remove sensitive parameters from the URL
24016
+ if (hasHashSensitiveParam || hasSearchSensitiveParam) {
24017
+ sensitiveParams.forEach((p) => urlSearchParams.delete(p));
24018
+ const search = urlSearchParams.toString() ? `?${urlSearchParams}` : '';
24019
+ window.history.replaceState(null, '', window.location.pathname + search);
24020
+ }
24021
+ // Clear sessionStorage bridge after consumption (post-reload path only)
24022
+ if (data) {
24023
+ sessionStorage.removeItem(STARTUP_DATA_STORAGE_KEY);
24024
+ }
24025
+ // Remove the window bridge object
24026
+ delete window[STARTUP_DATA_STORAGE_KEY];
24027
+ }
24028
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StartupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
24029
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StartupService, providedIn: 'root' });
24030
+ }
24031
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StartupService, decorators: [{
24032
+ type: Injectable,
24033
+ args: [{ providedIn: 'root' }]
24034
+ }] });
24035
+ /**
24036
+ * Factory function for the app startup initializer.
24037
+ * In Angular 18, this is used with APP_INITIALIZER:
24038
+ * { provide: APP_INITIALIZER, useFactory: createAppStartupInitializer, multi: true }
24039
+ *
24040
+ * inject() is called during factory execution (in injection context), then the
24041
+ * returned function calls the already-injected service.
24042
+ */
24043
+ function createAppStartupInitializer() {
24044
+ const service = inject(StartupService);
24045
+ return () => service.start();
24046
+ }
24047
+
23896
24048
  const TOKEN_STORAGE_KEY = 'token';
23897
24049
  const PUBKEY_STORAGE_KEY = 'pubkey';
23898
24050
  const SECKEY_STORAGE_KEY = 'seckey';
@@ -24089,6 +24241,7 @@ class AccountService extends BaseGraphqlService {
24089
24241
  settings;
24090
24242
  storage;
24091
24243
  file;
24244
+ startupService;
24092
24245
  translate;
24093
24246
  toastController;
24094
24247
  environment;
@@ -24164,13 +24317,14 @@ class AccountService extends BaseGraphqlService {
24164
24317
  get remoteLocalSettingsKeys() {
24165
24318
  return this._remoteLocalSettingsKeys;
24166
24319
  }
24167
- constructor(network, graphql, settings, storage, file, translate, toastController, environment, options, accountOptions) {
24320
+ constructor(network, graphql, settings, storage, file, startupService, translate, toastController, environment, options, accountOptions) {
24168
24321
  super(graphql, environment);
24169
24322
  this.network = network;
24170
24323
  this.graphql = graphql;
24171
24324
  this.settings = settings;
24172
24325
  this.storage = storage;
24173
24326
  this.file = file;
24327
+ this.startupService = startupService;
24174
24328
  this.translate = translate;
24175
24329
  this.toastController = toastController;
24176
24330
  this.environment = environment;
@@ -24213,7 +24367,11 @@ class AccountService extends BaseGraphqlService {
24213
24367
  this.restart();
24214
24368
  }
24215
24369
  }));
24216
- await this.restoreLocally();
24370
+ // Try to auto login, or restore locally
24371
+ const autoLogin = await this.autoLogin();
24372
+ if (!autoLogin) {
24373
+ await this.restoreLocally();
24374
+ }
24217
24375
  await this.listenSettings();
24218
24376
  return this._data;
24219
24377
  }
@@ -24859,6 +25017,20 @@ class AccountService extends BaseGraphqlService {
24859
25017
  .pipe(debounceTime(2000), filter(() => this.isLogin() && this.network.online))
24860
25018
  .subscribe((settings) => this.saveLocalSettingsRemotely(settings)));
24861
25019
  }
25020
+ async autoLogin() {
25021
+ if (!this.startupService?.hasAuth())
25022
+ return false; // Skip if no auth data
25023
+ try {
25024
+ const authData = this.startupService.consumeAuth();
25025
+ console.debug('[account] Attempting auto login as:', authData.username);
25026
+ await this.login(authData);
25027
+ return true;
25028
+ }
25029
+ catch (error) {
25030
+ console.warn('[account] Auto auth failed:', error);
25031
+ return false;
25032
+ }
25033
+ }
24862
25034
  async restoreLocally() {
24863
25035
  // Restore from storage
24864
25036
  const values = await Promise.all([
@@ -25238,13 +25410,15 @@ class AccountService extends BaseGraphqlService {
25238
25410
  showToast(opts) {
25239
25411
  return Toasts.show(this.toastController, this.translate, opts);
25240
25412
  }
25241
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AccountService, deps: [{ token: NetworkService }, { token: GraphqlService }, { token: LocalSettingsService }, { token: i2$4.Storage }, { token: FileService }, { token: i1$1.TranslateService, optional: true }, { token: i2$1.ToastController, optional: true }, { token: ENVIRONMENT }, { token: APP_USER_SETTINGS_OPTIONS, optional: true }, { token: APP_ACCOUNT_SERVICE_OPTIONS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
25413
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AccountService, deps: [{ token: NetworkService }, { token: GraphqlService }, { token: LocalSettingsService }, { token: i2$4.Storage }, { token: FileService }, { token: StartupService, optional: true }, { token: i1$1.TranslateService, optional: true }, { token: i2$1.ToastController, optional: true }, { token: ENVIRONMENT }, { token: APP_USER_SETTINGS_OPTIONS, optional: true }, { token: APP_ACCOUNT_SERVICE_OPTIONS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
25242
25414
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AccountService, providedIn: 'root' });
25243
25415
  }
25244
25416
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AccountService, decorators: [{
25245
25417
  type: Injectable,
25246
25418
  args: [{ providedIn: 'root', deps: [ENVIRONMENT] }]
25247
- }], ctorParameters: () => [{ type: NetworkService }, { type: GraphqlService }, { type: LocalSettingsService }, { type: i2$4.Storage }, { type: FileService }, { type: i1$1.TranslateService, decorators: [{
25419
+ }], ctorParameters: () => [{ type: NetworkService }, { type: GraphqlService }, { type: LocalSettingsService }, { type: i2$4.Storage }, { type: FileService }, { type: StartupService, decorators: [{
25420
+ type: Optional
25421
+ }] }, { type: i1$1.TranslateService, decorators: [{
25248
25422
  type: Optional
25249
25423
  }] }, { type: i2$1.ToastController, decorators: [{
25250
25424
  type: Optional
@@ -26278,7 +26452,8 @@ class PlatformService extends StartableService {
26278
26452
  // Hide accessory bar (iOS only)
26279
26453
  if (this.isApp() && this.isIOS()) {
26280
26454
  pluginName = CapacitorPlugins.Keyboard;
26281
- await Keyboard.setAccessoryBarVisible({ isVisible: false });
26455
+ // Let Capacitor config handle accessory bar
26456
+ //await Keyboard.setAccessoryBarVisible({ isVisible: false });
26282
26457
  }
26283
26458
  }
26284
26459
  catch (err) {
@@ -27346,7 +27521,7 @@ class SharedModule {
27346
27521
  },
27347
27522
  {
27348
27523
  provide: ENVIRONMENT,
27349
- deps: [EnvironmentLoader, APP_INITIALIZER],
27524
+ deps: [EnvironmentLoader],
27350
27525
  useFactory: (loader) => loader.get(),
27351
27526
  },
27352
27527
  ]