core-3nweb-client-lib 0.38.1 → 0.40.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.
@@ -301,22 +301,6 @@ declare namespace web3n.asmail {
301
301
  msgIsBroken?: true;
302
302
  }
303
303
 
304
- interface ServLocException extends RuntimeException {
305
- type: 'service-locating';
306
- address: string;
307
-
308
- /**
309
- * domainNotFound flag indicates that domain in the address doesn't exist.
310
- */
311
- domainNotFound?: true;
312
-
313
- /**
314
- * noServiceRecord flag indicates that 3NWeb services are not set at
315
- * domain in the address.
316
- */
317
- noServiceRecord?: true;
318
- }
319
-
320
304
  interface ASMailSendException extends RuntimeException {
321
305
  type: 'asmail-delivery';
322
306
  address?: string;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright (C) 2016 - 2017, 2020, 2023 3NSoft Inc.
2
+ Copyright (C) 2016 - 2017, 2020, 2023, 2025 3NSoft Inc.
3
3
 
4
4
  This program is free software: you can redistribute it and/or modify it under
5
5
  the terms of the GNU General Public License as published by the Free Software
@@ -70,9 +70,10 @@ declare namespace web3n.startup {
70
70
  * @param progressCB is a callback for progress notification
71
71
  */
72
72
  createUserParams(
73
- pass: string,
74
- progressCB: (progress: number) => void
73
+ pass: string, progressCB: ProgressCB
75
74
  ): Promise<void>;
75
+
76
+ watchBoot(observer: BootProcessObserver): () => void;
76
77
 
77
78
  }
78
79
 
@@ -106,8 +107,7 @@ declare namespace web3n.startup {
106
107
  * @param progressCB is a callback for progress notification
107
108
  */
108
109
  completeLoginAndLocalSetup(
109
- pass: string,
110
- progressCB: (progress: number) => void
110
+ pass: string, progressCB: ProgressCB
111
111
  ): Promise<boolean>;
112
112
 
113
113
  /**
@@ -119,12 +119,22 @@ declare namespace web3n.startup {
119
119
  * @param progressCB is a callback for progress notification
120
120
  */
121
121
  useExistingStorage(
122
- address: string, pass: string,
123
- progressCB: (progress: number) => void
122
+ address: string, pass: string, progressCB: ProgressCB
124
123
  ): Promise<boolean>;
124
+
125
+ watchBoot(observer: BootProcessObserver): () => void;
125
126
 
126
127
  }
127
128
 
129
+ type ProgressCB = (progress: number) => void;
130
+ type BootProcessObserver = Observer<BootEvent>;
131
+ interface BootEvent {
132
+ coreApp?: string;
133
+ message: string;
134
+ isError?: true;
135
+ isWarning?: true;
136
+ }
137
+
128
138
  interface W3N {
129
139
  signIn: startup.SignInService;
130
140
  signUp: startup.SignUpService;
@@ -25,7 +25,7 @@
25
25
 
26
26
 
27
27
  declare namespace web3n {
28
-
28
+
29
29
  interface RuntimeException {
30
30
  runtimeException: true;
31
31
  type?: string;
@@ -33,21 +33,47 @@ declare namespace web3n {
33
33
  message?: string;
34
34
  }
35
35
 
36
+ interface ConnectException extends RuntimeException {
37
+ type: 'connect';
38
+ connectType: string;
39
+ }
40
+
36
41
  interface HTTPErrorDetails extends web3n.RuntimeException {
37
42
  url: string;
38
43
  method: string;
39
- message?: string;
40
44
  }
41
-
42
- interface ConnectException extends HTTPErrorDetails {
43
- type: 'http-connect';
45
+
46
+ interface HTTPConnectException extends ConnectException {
47
+ connectType: 'http';
48
+ url?: string;
49
+ method?: string;
50
+ }
51
+
52
+ interface DNSConnectException extends ConnectException {
53
+ connectType: 'dns';
44
54
  }
45
-
55
+
46
56
  interface HTTPException extends HTTPErrorDetails {
47
57
  type: 'http-request';
48
58
  status: number;
49
59
  }
50
-
60
+
61
+ interface ServLocException extends RuntimeException {
62
+ type: 'service-locating';
63
+ address: string;
64
+
65
+ /**
66
+ * domainNotFound flag indicates that domain in the address doesn't exist.
67
+ */
68
+ domainNotFound?: true;
69
+
70
+ /**
71
+ * noServiceRecord flag indicates that 3NWeb services are not set at
72
+ * domain in the address.
73
+ */
74
+ noServiceRecord?: true;
75
+ }
76
+
51
77
  interface EncryptionException {
52
78
  failedCipherVerification?: true;
53
79
  failedSignatureVerification?: true;
@@ -214,7 +214,7 @@ class InboxOnServer {
214
214
  msgIds = await this.msgReceiver.listMsgs(fromTS);
215
215
  }
216
216
  catch (exc) {
217
- if (exc.type !== 'http-connect') {
217
+ if (exc.type !== 'connect') {
218
218
  throw exc;
219
219
  }
220
220
  return this.index.listMsgs(fromTS);
@@ -87,24 +87,33 @@ class AnonymousInvites {
87
87
  });
88
88
  return serverJSON;
89
89
  }
90
- async syncServiceSetting() {
90
+ async syncServiceSetting(rethrowConnectExc = false) {
91
91
  // XXX we may have the following bug here:
92
92
  // Device with older version of param gets to this point, and sets older
93
93
  // value.
94
94
  // To protect aginst this case, absorbing from file must ensure highest
95
95
  // synced version is read.
96
- const infoOnServer = await this.anonInvitesOnServer.getFromServer()
97
- .catch((exc) => {
98
- if (exc.type === 'http-connect') {
99
- return;
96
+ try {
97
+ const infoOnServer = await this.anonInvitesOnServer.getFromServer()
98
+ .catch((exc) => {
99
+ if (exc.type === 'connect') {
100
+ return;
101
+ }
102
+ else {
103
+ throw exc;
104
+ }
105
+ });
106
+ const currentVal = this.toServiceJSON();
107
+ if (!(0, json_utils_1.deepEqual)(infoOnServer, currentVal)) {
108
+ await this.anonInvitesOnServer.setOnServer(currentVal);
100
109
  }
101
- else {
102
- throw exc;
110
+ }
111
+ catch (exc) {
112
+ if (!rethrowConnectExc
113
+ && (exc.type === 'connect')) {
114
+ return;
103
115
  }
104
- });
105
- const currentVal = this.toServiceJSON();
106
- if (!(0, json_utils_1.deepEqual)(infoOnServer, currentVal)) {
107
- await this.anonInvitesOnServer.setOnServer(currentVal);
116
+ throw exc;
108
117
  }
109
118
  }
110
119
  getAll() {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2018, 2020 - 2022 3NSoft Inc.
3
+ Copyright (C) 2015 - 2018, 2020 - 2022, 2025 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -72,15 +72,7 @@ class IdManager {
72
72
  }
73
73
  static async initFromCachedStore(address, fs, resolver, makeNet, logError, logWarning) {
74
74
  const store = key_storage_1.IdKeysStorage.makeWithStorage(fs, logError, logWarning);
75
- const idManager = new IdManager(store, makeNet, resolver, address);
76
- try {
77
- await idManager.provisionUsingSavedKey();
78
- return idManager;
79
- }
80
- catch (err) {
81
- await logError(err, `Can't initialize id manager from local store`);
82
- return;
83
- }
75
+ return new IdManager(store, makeNet, resolver, address);
84
76
  }
85
77
  async startProvisionWithoutSavedKey(address) {
86
78
  const midUrl = await this.midServiceFor(address);
@@ -20,13 +20,14 @@ export declare class Core {
20
20
  private asmail;
21
21
  private keyrings;
22
22
  private idManager;
23
- private isInitialized;
24
23
  private closingProc;
24
+ private isInitialized;
25
25
  private constructor();
26
26
  static make(conf: CoreConf, makeNet: MakeNet, makeResolver: ServiceLocatorMaker, makeCryptor: makeCryptor): Core;
27
27
  start(): {
28
28
  capsForStartup: web3n.startup.W3N;
29
29
  coreInit: Promise<string>;
30
+ coreAppsInit: Promise<void>;
30
31
  };
31
32
  private initForNewUser;
32
33
  private initForExistingUserWithoutCache;
@@ -40,11 +41,9 @@ export declare class Core {
40
41
  private makeKeyringsCAP;
41
42
  private makeLogCAP;
42
43
  private makeMailerIdCAP;
43
- private closeBroadcast;
44
- close$: import("rxjs").Observable<void>;
45
44
  close(): Promise<void>;
46
45
  private performDataMigrationsAtInit;
47
- private initCore;
46
+ private initCoreApps;
48
47
  getStorages(): FactoryOfFSs;
49
48
  }
50
49
  export {};
@@ -24,13 +24,12 @@ const sign_in_1 = require("./startup/sign-in");
24
24
  const asmail_1 = require("./asmail");
25
25
  const error_1 = require("../lib-common/exceptions/error");
26
26
  const json_utils_1 = require("../lib-common/json-utils");
27
- const rxjs_1 = require("rxjs");
28
27
  const log_to_file_1 = require("../lib-client/logging/log-to-file");
29
- const operators_1 = require("rxjs/operators");
30
28
  const app_files_1 = require("./app-files");
31
29
  const keyring_1 = require("./keyring");
32
30
  const constants_1 = require("./storage/common/constants");
33
31
  const config_1 = require("./asmail/config");
32
+ const deferred_1 = require("../lib-common/processes/deferred");
34
33
  class Core {
35
34
  constructor(makeNet, makeResolver, makeCryptor, appDirs, logger, signUpUrl) {
36
35
  this.makeNet = makeNet;
@@ -39,94 +38,184 @@ class Core {
39
38
  this.logger = logger;
40
39
  this.signUpUrl = signUpUrl;
41
40
  this.idManager = undefined;
42
- this.isInitialized = false;
43
41
  this.closingProc = undefined;
44
- this.initForNewUser = async (u) => {
42
+ this.isInitialized = false;
43
+ this.cryptor = makeCryptor(this.logger.logError, this.logger.logWarning);
44
+ this.storages = new storage_1.Storages(this.cryptor.cryptor.sbox, this.appDirs.storagePathFor);
45
+ this.keyrings = new keyring_1.Keyrings(this.cryptor.cryptor.sbox);
46
+ this.asmail = new asmail_1.ASMail(this.cryptor.cryptor.sbox, this.makeNet, this.appDirs.inboxPathFor, this.logger);
47
+ Object.seal(this);
48
+ }
49
+ static make(conf, makeNet, makeResolver, makeCryptor) {
50
+ const dirs = (0, app_files_1.appDirs)(conf.dataDir);
51
+ const logger = (0, log_to_file_1.makeLogger)(dirs.getUtilFS());
52
+ const core = new Core(makeNet, makeResolver, makeCryptor, dirs, logger, conf.signUpUrl);
53
+ return core;
54
+ }
55
+ start() {
56
+ const { promise: midPromise, resolve: midDone } = (0, deferred_1.defer)();
57
+ const { watchBoot, emitBootEvent } = makeForBootEvents();
58
+ const signUp = new sign_up_1.SignUp(this.signUpUrl, this.cryptor.cryptor, this.makeNet, this.appDirs.getUsersOnDisk, user => this.initForNewUser(user, midDone, emitBootEvent), watchBoot, this.logger.logError);
59
+ const signIn = new sign_in_1.SignIn(this.cryptor.cryptor, addr => this.initForExistingUserWithoutCache(addr, midDone, emitBootEvent), (addr, storageKey) => this.initForExistingUserWithCache(addr, storageKey, midDone, emitBootEvent), this.appDirs.getUsersOnDisk, watchBoot, this.logger.logError);
60
+ const capsForStartup = {
61
+ signUp: signUp.exposedService(),
62
+ signIn: signIn.exposedService()
63
+ };
64
+ Object.freeze(capsForStartup);
65
+ const coreInit = midPromise.then(idManager => {
66
+ this.idManager = idManager;
67
+ return this.idManager.getId();
68
+ });
69
+ const coreAppsInit = coreInit.then(async () => {
70
+ // XXX This should be removed, at some point, as there will be no more
71
+ // users with very old data folders.
72
+ await this.performDataMigrationsAtInit();
73
+ await this.initCoreApps(emitBootEvent);
74
+ this.isInitialized = true;
75
+ });
76
+ return { coreInit, coreAppsInit, capsForStartup };
77
+ }
78
+ ;
79
+ async initForNewUser(u, done, emitBootEvent) {
80
+ var _a;
81
+ emitBootEvent({
82
+ message: `Initializing system for new user ${u.address}`
83
+ });
84
+ try {
45
85
  // 1) init of id manager without setting fs
46
- const stepTwo = await id_manager_1.IdManager.initWithoutStore(u.address, this.makeResolver('mailerid'), () => this.makeNet(), this.logger.logError, this.logger.logWarning);
86
+ const stepTwo = await id_manager_1.IdManager.initWithoutStore(u.address, this.makeResolver('mailerid'), this.makeNet, this.logger.logError, this.logger.logWarning);
47
87
  if (!stepTwo) {
48
- throw new Error(`MailerId server doesn't recognize identity ${u.address}`);
88
+ const message = `MailerId server doesn't recognize identity ${u.address}`;
89
+ emitBootEvent({ message, isError: true });
90
+ throw new Error(message);
49
91
  }
92
+ emitBootEvent({ message: `✔️ started login to provision MailerId` });
50
93
  // 2) complete id manager login, without use of fs
51
94
  const idManagerInit = await stepTwo(u.midSKey.default);
52
95
  if (!idManagerInit) {
53
- throw new Error(`Failed to provision MailerId identity`);
96
+ const message = `Failed to provision MailerId identity`;
97
+ emitBootEvent({ message, isError: true });
98
+ throw new Error(message);
54
99
  }
100
+ emitBootEvent({ message: `✔️ MailerId certificate provisioned` });
55
101
  const { idManager, setupManagerStorage } = idManagerInit;
56
102
  // 3) initialize all storages
103
+ emitBootEvent({ message: `Setting up main storage for new user` });
57
104
  const storesUp = await this.storages.initFreshForNewUser(u.address, idManager.getSigner, u.storeParams, u.storeSKey, this.makeNet, this.makeResolver('3nstorage'), this.logger.logError);
58
105
  if (!storesUp) {
59
- throw new Error(`Stores failed to initialize`);
106
+ const message = `Main store failed to initialize for new user`;
107
+ emitBootEvent({ message, isError: true });
108
+ throw new Error(message);
60
109
  }
110
+ emitBootEvent({ message: `✔️ main storage initialized` });
61
111
  // 3) give id manager fs, in which it will record labeled key(s)
112
+ emitBootEvent({ coreApp: constants_1.MAILERID_APP_NAME, message: `setting up storage` });
62
113
  await setupManagerStorage(await this.storages.makeSyncedFSForApp(constants_1.MAILERID_APP_NAME), [u.midSKey.labeled]);
63
- return idManager;
64
- };
65
- this.initForExistingUserWithoutCache = async (address) => {
114
+ emitBootEvent({ coreApp: constants_1.MAILERID_APP_NAME, message: `✔️ storage setup completed` });
115
+ done(idManager);
116
+ }
117
+ catch (exc) {
118
+ if (exc.type === 'connect') {
119
+ emitBootEvent({ message: `🔌 fail due to loss of connectivity`, isError: true });
120
+ }
121
+ else {
122
+ emitBootEvent({ message: (_a = exc.message) !== null && _a !== void 0 ? _a : (0, error_1.stringifyErr)(exc), isError: true });
123
+ }
124
+ throw exc;
125
+ }
126
+ }
127
+ async initForExistingUserWithoutCache(address, done, emitBootEvent) {
128
+ var _a;
129
+ emitBootEvent({
130
+ message: `Initializing system for user ${address}, without local cache on this device`
131
+ });
132
+ try {
66
133
  // 1) init of id manager without setting fs
67
- const stepTwo = await id_manager_1.IdManager.initWithoutStore(address, this.makeResolver('mailerid'), () => this.makeNet(), this.logger.logError, this.logger.logWarning);
134
+ const stepTwo = await id_manager_1.IdManager.initWithoutStore(address, this.makeResolver('mailerid'), this.makeNet, this.logger.logError, this.logger.logWarning);
68
135
  if (!stepTwo) {
136
+ emitBootEvent({
137
+ isError: true, message: `MailerId server doesn't recognize identity ${address}`
138
+ });
69
139
  return;
70
140
  }
71
141
  return async (midLoginKey, storageKey) => {
72
- // 2) complete id manager login, without use of fs
73
- const idManagerInit = await stepTwo(midLoginKey);
74
- if (!idManagerInit) {
75
- return;
142
+ var _a;
143
+ try {
144
+ // 2) complete id manager login, without use of fs
145
+ const idManagerInit = await stepTwo(midLoginKey);
146
+ if (!idManagerInit) {
147
+ emitBootEvent({
148
+ isError: true, message: `password/key is incorrect to provision MailerId certificate`
149
+ });
150
+ return false;
151
+ }
152
+ emitBootEvent({ message: `✔️ MailerId certificate provisioned` });
153
+ const { idManager, setupManagerStorage } = idManagerInit;
154
+ // 3) initialize all storages
155
+ emitBootEvent({ message: `Setting up main storage without local cache` });
156
+ const storeDone = await this.storages.initFromRemote(address, idManager.getSigner, storageKey, this.makeNet, this.makeResolver('3nstorage'), this.logger.logError);
157
+ if (!storeDone) {
158
+ emitBootEvent({ message: `Main store failed to initialize`, isError: true });
159
+ return false;
160
+ }
161
+ emitBootEvent({ message: `✔️ main storage initialized` });
162
+ // 4) complete initialization of id manager
163
+ emitBootEvent({ coreApp: constants_1.MAILERID_APP_NAME, message: `setting up storage` });
164
+ await setupManagerStorage(await this.storages.makeSyncedFSForApp(constants_1.MAILERID_APP_NAME));
165
+ emitBootEvent({ coreApp: constants_1.MAILERID_APP_NAME, message: `✔️ storage setup completed` });
166
+ done(idManager);
167
+ return true;
76
168
  }
77
- const { idManager, setupManagerStorage } = idManagerInit;
78
- // 3) initialize all storages
79
- const storeDone = await this.storages.initFromRemote(address, idManager.getSigner, storageKey, this.makeNet, this.makeResolver('3nstorage'), this.logger.logError);
80
- if (!storeDone) {
81
- return;
169
+ catch (exc) {
170
+ if (exc.type === 'connect') {
171
+ emitBootEvent({ message: `🔌 fail due to loss of connectivity`, isError: true });
172
+ }
173
+ else {
174
+ emitBootEvent({ message: (_a = exc.message) !== null && _a !== void 0 ? _a : (0, error_1.stringifyErr)(exc), isError: true });
175
+ }
176
+ throw exc;
82
177
  }
83
- // 4) complete initialization of id manager
84
- await setupManagerStorage(await this.storages.makeSyncedFSForApp(constants_1.MAILERID_APP_NAME));
85
- return idManager;
86
178
  };
87
- };
88
- this.initForExistingUserWithCache = async (address, storageKey) => {
179
+ }
180
+ catch (exc) {
181
+ if (exc.type === 'connect') {
182
+ emitBootEvent({ message: `🔌 fail due to loss of connectivity`, isError: true });
183
+ }
184
+ else {
185
+ emitBootEvent({ message: (_a = exc.message) !== null && _a !== void 0 ? _a : (0, error_1.stringifyErr)(exc), isError: true });
186
+ }
187
+ throw exc;
188
+ }
189
+ }
190
+ async initForExistingUserWithCache(address, storageKey, done, emitBootEvent) {
191
+ var _a;
192
+ emitBootEvent({
193
+ message: `Initializing system for user ${address}, with local cache on this device`
194
+ });
195
+ try {
196
+ emitBootEvent({ message: `Unlocking data from local cache with provided password/key` });
89
197
  const completeStorageInit = await this.storages.startInitFromCache(address, storageKey, this.makeNet, this.makeResolver('3nstorage'), this.logger.logError);
90
198
  if (!completeStorageInit) {
91
- return;
199
+ emitBootEvent({
200
+ isError: true, message: `password/key is incorrect to decrypt local caches, or caches are damaged`
201
+ });
202
+ return false;
92
203
  }
93
- const idManager = await id_manager_1.IdManager.initFromCachedStore(address, await this.storages.makeSyncedFSForApp(constants_1.MAILERID_APP_NAME), this.makeResolver('mailerid'), () => this.makeNet(), this.logger.logError, this.logger.logWarning);
204
+ emitBootEvent({ message: `✔️ main storage is opened` });
205
+ const idManager = await id_manager_1.IdManager.initFromCachedStore(address, await this.storages.makeSyncedFSForApp(constants_1.MAILERID_APP_NAME), this.makeResolver('mailerid'), this.makeNet, this.logger.logError, this.logger.logWarning);
94
206
  if (!idManager) {
95
- return;
207
+ return false;
96
208
  }
209
+ emitBootEvent({ message: `✔️ MailerId manager is initialized` });
97
210
  completeStorageInit(idManager.getSigner);
98
- return idManager;
99
- };
100
- this.closeBroadcast = new rxjs_1.Subject();
101
- this.close$ = this.closeBroadcast.asObservable();
102
- this.cryptor = makeCryptor(this.logger.logError, this.logger.logWarning);
103
- this.storages = new storage_1.Storages(this.cryptor.cryptor.sbox, this.appDirs.storagePathFor);
104
- this.keyrings = new keyring_1.Keyrings(this.cryptor.cryptor.sbox);
105
- this.asmail = new asmail_1.ASMail(this.cryptor.cryptor.sbox, this.makeNet, this.appDirs.inboxPathFor, this.logger);
106
- Object.seal(this);
107
- }
108
- static make(conf, makeNet, makeResolver, makeCryptor) {
109
- const dirs = (0, app_files_1.appDirs)(conf.dataDir);
110
- const logger = (0, log_to_file_1.makeLogger)(dirs.getUtilFS());
111
- const core = new Core(makeNet, makeResolver, makeCryptor, dirs, logger, conf.signUpUrl);
112
- return core;
113
- }
114
- start() {
115
- const signUp = new sign_up_1.SignUp(this.signUpUrl, this.cryptor.cryptor, this.makeNet.bind(this), this.appDirs.getUsersOnDisk, this.logger.logError);
116
- const signIn = new sign_in_1.SignIn(this.cryptor.cryptor, this.initForExistingUserWithoutCache, this.initForExistingUserWithCache, this.appDirs.getUsersOnDisk, this.logger.logError);
117
- const capsForStartup = {
118
- signUp: signUp.exposedService(),
119
- signIn: signIn.exposedService()
120
- };
121
- Object.freeze(capsForStartup);
122
- const initFromSignUp$ = signUp.newUser$
123
- .pipe((0, operators_1.mergeMap)(this.initForNewUser, 1));
124
- const initFromSignIn$ = signIn.existingUser$;
125
- const coreInit = (0, rxjs_1.lastValueFrom)((0, rxjs_1.merge)(initFromSignIn$, initFromSignUp$)
126
- .pipe((0, operators_1.take)(1), (0, operators_1.mergeMap)(idManager => this.initCore(idManager), 1)));
127
- return { coreInit, capsForStartup };
211
+ done(idManager);
212
+ return true;
213
+ }
214
+ catch (exc) {
215
+ emitBootEvent({ message: (_a = exc.message) !== null && _a !== void 0 ? _a : (0, error_1.stringifyErr)(exc), isError: true });
216
+ throw exc;
217
+ }
128
218
  }
129
- ;
130
219
  makeCAPsForApp(appDomain, requestedCAPs) {
131
220
  if (!this.isInitialized || this.closingProc) {
132
221
  throw new Error(`Core is either not yet initialized, or is already closed.`);
@@ -203,7 +292,6 @@ class Core {
203
292
  }
204
293
  await this.cryptor.close();
205
294
  this.cryptor = undefined;
206
- this.closeBroadcast.next();
207
295
  })();
208
296
  }
209
297
  await this.closingProc;
@@ -213,25 +301,26 @@ class Core {
213
301
  await this.storages.migrateCoreAppDataOnFirstRun('synced', `${constants_1.ASMAIL_APP_NAME}/config/introductory-key.json`, `${constants_1.KEYRINGS_APP_NAME}/introductory-keys/published-on-server.json`);
214
302
  await this.storages.migrateCoreAppDataOnFirstRun('synced', `${constants_1.ASMAIL_APP_NAME}/config/anonymous/invites.json`, `${constants_1.ASMAIL_APP_NAME}/sending-params/anonymous-invites.json`);
215
303
  }
216
- async initCore(idManager) {
304
+ async initCoreApps(emitBootEvent) {
305
+ // XXX push events to this.bootProcObserver
306
+ var _a;
217
307
  try {
218
- this.idManager = idManager;
219
308
  const address = this.idManager.getId();
220
309
  const getSigner = this.idManager.getSigner;
221
310
  const asmailServerConfig = new config_1.ConfigOfASMailServer(address, getSigner, this.makeResolver('asmail'), this.makeNet());
222
- // XXX This should be removed, at some point, as there will be no more
223
- // users with very old data folders.
224
- await this.performDataMigrationsAtInit();
311
+ emitBootEvent({ coreApp: constants_1.KEYRINGS_APP_NAME, message: `starting initialization` });
225
312
  const keyringsSyncedFS = await this.storages.makeSyncedFSForApp(constants_1.KEYRINGS_APP_NAME);
226
313
  await this.keyrings.init(keyringsSyncedFS, this.idManager.getSigner, asmailServerConfig.makeParamSetterAndGetter('init-pub-key'));
314
+ emitBootEvent({ coreApp: constants_1.KEYRINGS_APP_NAME, message: `✔️ initialized` });
315
+ emitBootEvent({ coreApp: constants_1.ASMAIL_APP_NAME, message: `starting initialization` });
227
316
  const inboxSyncedFS = await this.storages.makeSyncedFSForApp(constants_1.ASMAIL_APP_NAME);
228
317
  const inboxLocalFS = await this.storages.makeLocalFSForApp(constants_1.ASMAIL_APP_NAME);
229
318
  await this.asmail.init(this.idManager.getId(), this.idManager.getSigner, inboxSyncedFS, inboxLocalFS, this.storages.storageGetterForASMail(), this.makeResolver, asmailServerConfig, this.keyrings.forASMail());
230
- this.isInitialized = true;
231
- return this.idManager.getId();
319
+ emitBootEvent({ coreApp: constants_1.ASMAIL_APP_NAME, message: `✔️ initialized` });
232
320
  }
233
321
  catch (err) {
234
- throw (0, error_1.errWithCause)(err, 'Failed to initialize core');
322
+ emitBootEvent({ isError: true, message: (_a = err.message) !== null && _a !== void 0 ? _a : (0, error_1.stringifyErr)(err) });
323
+ throw (0, error_1.errWithCause)(err, 'Failed to initialize core apps');
235
324
  }
236
325
  }
237
326
  getStorages() {
@@ -241,6 +330,25 @@ class Core {
241
330
  exports.Core = Core;
242
331
  Object.freeze(Core.prototype);
243
332
  Object.freeze(Core);
333
+ function makeForBootEvents() {
334
+ let bootProcObserver = undefined;
335
+ return {
336
+ watchBoot(obs) {
337
+ var _a;
338
+ if (bootProcObserver) {
339
+ (_a = bootProcObserver.error) === null || _a === void 0 ? void 0 : _a.call(bootProcObserver, `New observer is added, and it stops the previous one.`);
340
+ }
341
+ bootProcObserver = obs;
342
+ return () => {
343
+ bootProcObserver = undefined;
344
+ };
345
+ },
346
+ emitBootEvent(ev) {
347
+ var _a;
348
+ (_a = bootProcObserver === null || bootProcObserver === void 0 ? void 0 : bootProcObserver.next) === null || _a === void 0 ? void 0 : _a.call(bootProcObserver, ev);
349
+ }
350
+ };
351
+ }
244
352
  function makeStoragePolicy(appDomain, requestedCAPs) {
245
353
  if (!requestedCAPs.storage) {
246
354
  throw new Error(`Missing storage setting in app's manifest`);
@@ -1,29 +1,27 @@
1
- import type { IdManager } from '../id-manager';
2
1
  import { ScryptGenParams } from '../../lib-client/key-derivation';
3
2
  import type { GetUsersOnDisk } from '../app-files';
4
3
  import { Cryptor } from '../../lib-client/cryptor/cryptor';
5
4
  import { LogError } from '../../lib-client/logging/log-to-file';
6
5
  export type GenerateKey = (derivParams: ScryptGenParams) => Promise<Uint8Array>;
7
6
  export type StartInitWithoutCache = (address: string) => Promise<CompleteInitWithoutCache | undefined>;
8
- export type CompleteInitWithoutCache = (midLoginKey: GenerateKey, storageKey: GenerateKey) => Promise<IdManager | undefined>;
9
- export type InitWithCache = (address: string, storageKey: GenerateKey) => Promise<IdManager | undefined>;
7
+ export type CompleteInitWithoutCache = (midLoginKey: GenerateKey, storageKey: GenerateKey) => Promise<boolean>;
8
+ export type InitWithCache = (address: string, storageKey: GenerateKey) => Promise<boolean>;
10
9
  type SignInService = web3n.startup.SignInService;
10
+ type ProgressCB = web3n.startup.ProgressCB;
11
11
  export declare class SignIn {
12
12
  private cryptor;
13
13
  private startInitWithoutCache;
14
14
  private initWithCache;
15
15
  private getUsersOnDisk;
16
+ private readonly watchBoot;
16
17
  private readonly logError;
17
18
  private completeInitWithoutCache;
18
- constructor(cryptor: Cryptor, startInitWithoutCache: StartInitWithoutCache, initWithCache: InitWithCache, getUsersOnDisk: GetUsersOnDisk, logError: LogError);
19
+ constructor(cryptor: Cryptor, startInitWithoutCache: StartInitWithoutCache, initWithCache: InitWithCache, getUsersOnDisk: GetUsersOnDisk, watchBoot: SignInService['watchBoot'], logError: LogError);
19
20
  exposedService(): SignInService;
20
21
  private startLoginToRemoteStorage;
21
22
  private completeLoginAndLocalSetup;
22
- private readonly doneBroadcast;
23
- readonly existingUser$: import("rxjs").Observable<IdManager>;
24
23
  private useExistingStorage;
25
24
  private logAndWrap;
26
25
  }
27
- export type ProgressCB = (p: number) => void;
28
26
  export declare function makeKeyGenProgressCB(progressStart: number, progressEnd: number, progressCB: ProgressCB): ProgressCB;
29
27
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2018, 2020, 2022 3NSoft Inc.
3
+ Copyright (C) 2015 - 2018, 2020, 2022, 2025 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -19,75 +19,62 @@ Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.SignIn = void 0;
20
20
  exports.makeKeyGenProgressCB = makeKeyGenProgressCB;
21
21
  const key_derivation_1 = require("../../lib-client/key-derivation");
22
- const rxjs_1 = require("rxjs");
23
22
  const error_1 = require("../../lib-common/exceptions/error");
24
23
  class SignIn {
25
- constructor(cryptor, startInitWithoutCache, initWithCache, getUsersOnDisk, logError) {
24
+ constructor(cryptor, startInitWithoutCache, initWithCache, getUsersOnDisk, watchBoot, logError) {
26
25
  this.cryptor = cryptor;
27
26
  this.startInitWithoutCache = startInitWithoutCache;
28
27
  this.initWithCache = initWithCache;
29
28
  this.getUsersOnDisk = getUsersOnDisk;
29
+ this.watchBoot = watchBoot;
30
30
  this.logError = logError;
31
31
  this.completeInitWithoutCache = undefined;
32
- this.startLoginToRemoteStorage = async (address) => {
33
- try {
34
- this.completeInitWithoutCache = await this.startInitWithoutCache(address);
35
- return !!this.completeInitWithoutCache;
36
- }
37
- catch (err) {
38
- throw await this.logAndWrap(err, 'Fail to start login to remote storage');
39
- }
40
- };
41
- this.completeLoginAndLocalSetup = async (pass, progressCB) => {
42
- if (!this.completeInitWithoutCache) {
43
- throw new Error(`Call method startLoginToRemoteStorage() before calling this.`);
44
- }
45
- try {
46
- const midKeyProgressCB = makeKeyGenProgressCB(0, 50, progressCB);
47
- const midKeyGen = async (params) => (await (0, key_derivation_1.deriveMidKeyPair)(this.cryptor, pass, params, midKeyProgressCB)).skey;
48
- const storeKeyProgressCB = makeKeyGenProgressCB(51, 100, progressCB);
49
- const storeKeyGen = params => (0, key_derivation_1.deriveStorageSKey)(this.cryptor, pass, params, storeKeyProgressCB);
50
- const idManager = await this.completeInitWithoutCache(midKeyGen, storeKeyGen);
51
- if (!idManager) {
52
- return false;
53
- }
54
- this.doneBroadcast.next(idManager);
55
- return true;
56
- }
57
- catch (err) {
58
- throw await this.logAndWrap(err, 'Fail to initialize from a state without cache');
59
- }
60
- };
61
- this.doneBroadcast = new rxjs_1.Subject();
62
- this.existingUser$ = this.doneBroadcast.asObservable();
63
- this.useExistingStorage = async (user, pass, progressCB) => {
64
- try {
65
- const storeKeyProgressCB = makeKeyGenProgressCB(0, 99, progressCB);
66
- const storeKeyGen = params => (0, key_derivation_1.deriveStorageSKey)(this.cryptor, pass, params, storeKeyProgressCB);
67
- const idManager = await this.initWithCache(user, storeKeyGen);
68
- if (idManager) {
69
- this.doneBroadcast.next(idManager);
70
- return true;
71
- }
72
- else {
73
- return false;
74
- }
75
- }
76
- catch (err) {
77
- throw await this.logAndWrap(err, 'Failing to start in a state with cache');
78
- }
79
- };
80
32
  Object.seal(this);
81
33
  }
82
34
  exposedService() {
83
35
  const service = {
84
- completeLoginAndLocalSetup: this.completeLoginAndLocalSetup,
36
+ completeLoginAndLocalSetup: this.completeLoginAndLocalSetup.bind(this),
85
37
  getUsersOnDisk: this.getUsersOnDisk,
86
- startLoginToRemoteStorage: this.startLoginToRemoteStorage,
87
- useExistingStorage: this.useExistingStorage
38
+ startLoginToRemoteStorage: this.startLoginToRemoteStorage.bind(this),
39
+ useExistingStorage: this.useExistingStorage.bind(this),
40
+ watchBoot: this.watchBoot
88
41
  };
89
42
  return Object.freeze(service);
90
43
  }
44
+ async startLoginToRemoteStorage(address) {
45
+ try {
46
+ this.completeInitWithoutCache = await this.startInitWithoutCache(address);
47
+ return !!this.completeInitWithoutCache;
48
+ }
49
+ catch (err) {
50
+ throw await this.logAndWrap(err, 'Fail to start login to remote storage');
51
+ }
52
+ }
53
+ async completeLoginAndLocalSetup(pass, progressCB) {
54
+ if (!this.completeInitWithoutCache) {
55
+ throw new Error(`Call method startLoginToRemoteStorage() before calling this.`);
56
+ }
57
+ try {
58
+ const midKeyProgressCB = makeKeyGenProgressCB(0, 50, progressCB);
59
+ const midKeyGen = async (params) => (await (0, key_derivation_1.deriveMidKeyPair)(this.cryptor, pass, params, midKeyProgressCB)).skey;
60
+ const storeKeyProgressCB = makeKeyGenProgressCB(51, 100, progressCB);
61
+ const storeKeyGen = params => (0, key_derivation_1.deriveStorageSKey)(this.cryptor, pass, params, storeKeyProgressCB);
62
+ return await this.completeInitWithoutCache(midKeyGen, storeKeyGen);
63
+ }
64
+ catch (err) {
65
+ throw await this.logAndWrap(err, 'Fail to initialize from a state without cache');
66
+ }
67
+ }
68
+ async useExistingStorage(user, pass, progressCB) {
69
+ try {
70
+ const storeKeyProgressCB = makeKeyGenProgressCB(0, 99, progressCB);
71
+ const storeKeyGen = params => (0, key_derivation_1.deriveStorageSKey)(this.cryptor, pass, params, storeKeyProgressCB);
72
+ return await this.initWithCache(user, storeKeyGen);
73
+ }
74
+ catch (err) {
75
+ throw await this.logAndWrap(err, 'Failing to start in a state with cache');
76
+ }
77
+ }
91
78
  async logAndWrap(err, msg) {
92
79
  await this.logError(err, msg);
93
80
  return (0, error_1.errWithCause)(err, msg);
@@ -15,14 +15,18 @@ export declare class SignUp {
15
15
  private cryptor;
16
16
  private makeNet;
17
17
  private getUsersOnDisk;
18
+ private initForNewUser;
19
+ private readonly watchBoot;
18
20
  private readonly logError;
19
21
  private mid;
20
22
  private store;
21
23
  private serviceURL;
22
24
  private netLazyInit;
23
25
  private get net();
24
- constructor(serviceURL: string, cryptor: Cryptor, makeNet: () => NetClient, getUsersOnDisk: GetUsersOnDisk, logError: LogError);
26
+ constructor(serviceURL: string, cryptor: Cryptor, makeNet: () => NetClient, getUsersOnDisk: GetUsersOnDisk, initForNewUser: (u: CreatedUser) => Promise<void>, watchBoot: SignUpService['watchBoot'], logError: LogError);
25
27
  private setServiceURL;
28
+ private getAvailableDomains;
29
+ private getAvailableAddresses;
26
30
  exposedService(): SignUpService;
27
31
  private createUserParams;
28
32
  private genStorageParams;
@@ -30,8 +34,6 @@ export declare class SignUp {
30
34
  private addUser;
31
35
  private logAndWrap;
32
36
  private forgetKeys;
33
- private doneBroadcast;
34
- newUser$: import("rxjs").Observable<CreatedUser>;
35
37
  }
36
38
  export interface CreatedUser {
37
39
  address: string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2020, 2022 - 2023 3NSoft Inc.
3
+ Copyright (C) 2015 - 2020, 2022 - 2023, 2025 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -26,7 +26,6 @@ const keyDeriv = require("../../lib-client/key-derivation");
26
26
  const random = require("../../lib-common/random-node");
27
27
  const ecma_nacl_1 = require("ecma-nacl");
28
28
  const sign_in_1 = require("./sign-in");
29
- const rxjs_1 = require("rxjs");
30
29
  const error_1 = require("../../lib-common/exceptions/error");
31
30
  /**
32
31
  * With these parameters scrypt shall use memory around:
@@ -63,54 +62,21 @@ class SignUp {
63
62
  }
64
63
  return this.netLazyInit;
65
64
  }
66
- constructor(serviceURL, cryptor, makeNet, getUsersOnDisk, logError) {
65
+ constructor(serviceURL, cryptor, makeNet, getUsersOnDisk, initForNewUser, watchBoot, logError) {
67
66
  this.cryptor = cryptor;
68
67
  this.makeNet = makeNet;
69
68
  this.getUsersOnDisk = getUsersOnDisk;
69
+ this.initForNewUser = initForNewUser;
70
+ this.watchBoot = watchBoot;
70
71
  this.logError = logError;
71
72
  this.mid = undefined;
72
73
  this.store = undefined;
73
74
  this.serviceURL = undefined;
74
75
  this.netLazyInit = undefined;
75
- this.createUserParams = async (pass, progressCB) => {
76
- await this.genMidParams(pass, 0, 50, progressCB);
77
- await this.genStorageParams(pass, 51, 100, progressCB);
78
- };
79
- this.addUser = async (address, signupToken) => {
80
- for (const user of await this.getUsersOnDisk()) {
81
- if ((0, canonical_address_1.areAddressesEqual)(address, user)) {
82
- throw new Error(`Account ${user} already exists on a disk.`);
83
- }
84
- }
85
- const accountCreated = await (0, _3nweb_signup_1.addUser)(this.net, this.serviceURL, {
86
- userId: address,
87
- mailerId: this.mid.params,
88
- storage: this.store.params,
89
- signupToken
90
- }).catch(async (err) => {
91
- throw await this.logAndWrap(err, `Failed to create user account ${address}.`);
92
- });
93
- if (!accountCreated) {
94
- return false;
95
- }
96
- this.doneBroadcast.next({
97
- address,
98
- midSKey: {
99
- default: this.mid.defaultSKey,
100
- labeled: this.mid.labeledSKey
101
- },
102
- storeSKey: this.store.skey,
103
- storeParams: this.store.params.kdParams
104
- });
105
- this.forgetKeys();
106
- return true;
107
- };
108
- this.doneBroadcast = new rxjs_1.Subject();
109
- this.newUser$ = this.doneBroadcast.asObservable();
110
76
  this.setServiceURL(serviceURL);
111
77
  Object.seal(this);
112
78
  }
113
- setServiceURL(serviceURL) {
79
+ async setServiceURL(serviceURL) {
114
80
  const url = (0, url_1.parse)(serviceURL);
115
81
  if (url.protocol !== 'https:') {
116
82
  throw new Error("Url protocol must be https.");
@@ -120,17 +86,28 @@ class SignUp {
120
86
  this.serviceURL += '/';
121
87
  }
122
88
  }
89
+ async getAvailableDomains(signupToken) {
90
+ return await (0, _3nweb_signup_1.checkAvailableDomains)(this.net, this.serviceURL, signupToken);
91
+ }
92
+ async getAvailableAddresses(name, signupToken) {
93
+ return await (0, _3nweb_signup_1.checkAvailableAddressesForName)(this.net, this.serviceURL, name, signupToken);
94
+ }
123
95
  exposedService() {
124
96
  const service = {
125
- setSignUpServer: async (srvUrl) => this.setServiceURL(srvUrl),
126
- getAvailableDomains: signupToken => (0, _3nweb_signup_1.checkAvailableDomains)(this.net, this.serviceURL, signupToken),
127
- addUser: this.addUser,
128
- createUserParams: this.createUserParams,
129
- getAvailableAddresses: (name, signupToken) => (0, _3nweb_signup_1.checkAvailableAddressesForName)(this.net, this.serviceURL, name, signupToken),
130
- isActivated: async () => { throw new Error(`Not implemented, yet`); }
97
+ setSignUpServer: this.setServiceURL.bind(this),
98
+ getAvailableDomains: this.getAvailableDomains.bind(this),
99
+ addUser: this.addUser.bind(this),
100
+ createUserParams: this.createUserParams.bind(this),
101
+ getAvailableAddresses: this.getAvailableAddresses.bind(this),
102
+ isActivated: () => { throw new Error(`Not implemented, yet`); },
103
+ watchBoot: this.watchBoot
131
104
  };
132
105
  return Object.freeze(service);
133
106
  }
107
+ async createUserParams(pass, progressCB) {
108
+ await this.genMidParams(pass, 0, 50, progressCB);
109
+ await this.genStorageParams(pass, 51, 100, progressCB);
110
+ }
134
111
  async genStorageParams(pass, progressStart, progressEnd, originalProgressCB) {
135
112
  const derivParams = {
136
113
  logN: defaultDerivParams.logN,
@@ -169,6 +146,35 @@ class SignUp {
169
146
  }
170
147
  };
171
148
  }
149
+ async addUser(address, signupToken) {
150
+ for (const user of await this.getUsersOnDisk()) {
151
+ if ((0, canonical_address_1.areAddressesEqual)(address, user)) {
152
+ throw new Error(`Account ${user} already exists on a disk.`);
153
+ }
154
+ }
155
+ const accountCreated = await (0, _3nweb_signup_1.addUser)(this.net, this.serviceURL, {
156
+ userId: address,
157
+ mailerId: this.mid.params,
158
+ storage: this.store.params,
159
+ signupToken
160
+ }).catch(async (err) => {
161
+ throw await this.logAndWrap(err, `Failed to create user account ${address}.`);
162
+ });
163
+ if (!accountCreated) {
164
+ return false;
165
+ }
166
+ this.initForNewUser({
167
+ address,
168
+ midSKey: {
169
+ default: this.mid.defaultSKey,
170
+ labeled: this.mid.labeledSKey
171
+ },
172
+ storeSKey: this.store.skey,
173
+ storeParams: this.store.params.kdParams
174
+ });
175
+ this.forgetKeys();
176
+ return true;
177
+ }
172
178
  async logAndWrap(err, msg) {
173
179
  await this.logError(err, msg);
174
180
  return (0, error_1.errWithCause)(err, msg);
@@ -44,7 +44,8 @@ function wrapSignInCAP(cap) {
44
44
  (_b = obs.complete) === null || _b === void 0 ? void 0 : _b.call(obs);
45
45
  }, err => { var _a; return (_a = obs.error) === null || _a === void 0 ? void 0 : _a.call(obs, err); });
46
46
  return noop;
47
- })
47
+ }),
48
+ watchBoot: (0, service_side_wrap_1.wrapObservingFunc)(cap.watchBoot)
48
49
  };
49
50
  }
50
51
  function makeSignInCaller(caller, objPath) {
@@ -66,7 +67,8 @@ function makeSignInCaller(caller, objPath) {
66
67
  obsFn(obs, addr, pass);
67
68
  return promise;
68
69
  };
69
- })()
70
+ })(),
71
+ watchBoot: (0, caller_side_wrap_1.makeObservableFuncCaller)(caller, objPath.concat('watchBoot'))
70
72
  };
71
73
  }
72
74
  function callSignIn(caller, objPath, method) {
@@ -104,7 +106,8 @@ function wrapSignUpCAP(cap) {
104
106
  .then(() => { var _a; return (_a = obs.complete) === null || _a === void 0 ? void 0 : _a.call(obs); }, err => { var _a; return (_a = obs.error) === null || _a === void 0 ? void 0 : _a.call(obs, err); });
105
107
  return noop;
106
108
  }),
107
- isActivated: (0, service_side_wrap_1.wrapReqReplySrvMethod)(cap, 'isActivated')
109
+ isActivated: (0, service_side_wrap_1.wrapReqReplySrvMethod)(cap, 'isActivated'),
110
+ watchBoot: (0, service_side_wrap_1.wrapObservingFunc)(cap.watchBoot)
108
111
  };
109
112
  }
110
113
  function noop() { }
@@ -129,7 +132,8 @@ function makeSignUpCaller(caller, objPath) {
129
132
  return completion.promise;
130
133
  };
131
134
  })(),
132
- isActivated: callSignUp(caller, objPath, 'isActivated')
135
+ isActivated: callSignUp(caller, objPath, 'isActivated'),
136
+ watchBoot: (0, caller_side_wrap_1.makeObservableFuncCaller)(caller, objPath.concat('watchBoot'))
133
137
  };
134
138
  }
135
139
  Object.freeze(exports);
@@ -95,7 +95,7 @@ class ServerEvents {
95
95
  if (!exc.runtimeException) {
96
96
  return false;
97
97
  }
98
- if (exc.type === 'http-connect') {
98
+ if (exc.type === 'connect') {
99
99
  return true;
100
100
  }
101
101
  else if (exc.type === 'http-request') {
@@ -24,6 +24,7 @@ exports.getMailerIdInfoFor = getMailerIdInfoFor;
24
24
  const jwkeys_1 = require("../lib-common/jwkeys");
25
25
  const url_1 = require("url");
26
26
  const request_utils_1 = require("./request-utils");
27
+ const runtime_1 = require("../lib-common/exceptions/runtime");
27
28
  async function readJSONLocatedAt(client, url) {
28
29
  if ((0, url_1.parse)(url).protocol !== 'https:') {
29
30
  throw new Error("Url protocol must be https.");
@@ -143,23 +144,17 @@ function checkAndPrepareURL(value) {
143
144
  return 'https://' + value;
144
145
  }
145
146
  function domainNotFoundExc(address, cause) {
146
- const exc = {
147
- runtimeException: true,
148
- type: 'service-locating',
149
- address,
150
- domainNotFound: true,
151
- cause
152
- };
153
- return exc;
147
+ return (0, runtime_1.makeRuntimeException)('service-locating', { address, cause }, { domainNotFound: true });
154
148
  }
155
149
  function noServiceRecordExc(address) {
156
- const exc = {
157
- runtimeException: true,
158
- type: 'service-locating',
159
- address,
160
- noServiceRecord: true
161
- };
162
- return exc;
150
+ return (0, runtime_1.makeRuntimeException)('service-locating', { address }, { noServiceRecord: true });
151
+ }
152
+ function noConnectionExc(cause) {
153
+ return (0, runtime_1.makeRuntimeException)('connect', {
154
+ connectType: 'dns',
155
+ message: `The most likely cause of this error is device not connected. Next likely cause is DNS not setup, or not connecting properly. Like the saying goes: "It's not DNS. There is no way it's DNS. It was DNS."`,
156
+ cause
157
+ }, {});
163
158
  }
164
159
  /**
165
160
  * This implementation extracts exactly one string value for a given service.
@@ -227,7 +222,8 @@ function getRecordAtStartOf(txt) {
227
222
  }
228
223
  const DNS_ERR_CODE = {
229
224
  NODATA: 'ENODATA',
230
- NOTFOUND: 'ENOTFOUND'
225
+ NOTFOUND: 'ENOTFOUND',
226
+ ESERVFAIL: 'ESERVFAIL'
231
227
  };
232
228
  Object.freeze(DNS_ERR_CODE);
233
229
  function makeServiceLocator(resolver) {
@@ -247,6 +243,9 @@ function makeServiceLocator(resolver) {
247
243
  if (code === DNS_ERR_CODE.NODATA) {
248
244
  throw noServiceRecordExc(address);
249
245
  }
246
+ else if (code === DNS_ERR_CODE.ESERVFAIL) {
247
+ throw noConnectionExc({ code, hostname, message });
248
+ }
250
249
  else if (hostname) {
251
250
  throw domainNotFoundExc(address, { code, hostname, message });
252
251
  }
@@ -1,4 +1,4 @@
1
- export type ConnectException = web3n.ConnectException;
1
+ export type ConnectException = web3n.HTTPConnectException;
2
2
  export type HTTPException = web3n.HTTPException;
3
- export declare function makeConnectionException(url: string | undefined, method: string | undefined, msg?: string, cause?: any): ConnectException;
4
- export declare function makeHTTPException(url: string, method: string, status: number, msg?: string, cause?: any): HTTPException;
3
+ export declare function makeConnectionException(url: string | undefined, method: string | undefined, message?: string, cause?: any): ConnectException;
4
+ export declare function makeHTTPException(url: string, method: string, status: number, message?: string, cause?: any): HTTPException;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 3NSoft Inc.
3
+ Copyright (C) 2015, 2025 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -17,31 +17,11 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.makeConnectionException = makeConnectionException;
19
19
  exports.makeHTTPException = makeHTTPException;
20
- function makeConnectionException(url, method, msg, cause) {
21
- const exc = {
22
- runtimeException: true,
23
- type: 'http-connect',
24
- url: url,
25
- method: method,
26
- cause
27
- };
28
- if (msg) {
29
- exc.message = msg;
30
- }
31
- return exc;
20
+ const runtime_1 = require("./runtime");
21
+ function makeConnectionException(url, method, message, cause) {
22
+ return (0, runtime_1.makeRuntimeException)('connect', { connectType: 'http', url, method, cause, message }, {});
32
23
  }
33
- function makeHTTPException(url, method, status, msg, cause) {
34
- const exc = {
35
- runtimeException: true,
36
- type: 'http-request',
37
- url: url,
38
- method: method,
39
- status: status,
40
- cause
41
- };
42
- if (msg) {
43
- exc.message = msg;
44
- }
45
- return exc;
24
+ function makeHTTPException(url, method, status, message, cause) {
25
+ return (0, runtime_1.makeRuntimeException)('http-request', { url, method, status, cause, message }, {});
46
26
  }
47
27
  Object.freeze(exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "core-3nweb-client-lib",
3
- "version": "0.38.1",
3
+ "version": "0.40.0",
4
4
  "description": "3NWeb client core library, embeddable into different environments",
5
5
  "main": "build/lib-index.js",
6
6
  "types": "build/lib-index.d.ts",