shogun-core 5.2.2 → 6.0.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 (43) hide show
  1. package/README.md +123 -20
  2. package/dist/browser/shogun-core.js +1134 -493
  3. package/dist/browser/shogun-core.js.map +1 -1
  4. package/dist/config/simplified-config.js +108 -40
  5. package/dist/crypto/mls.js +34 -15
  6. package/dist/crypto/sframe.js +13 -11
  7. package/dist/examples/auth-test.js +263 -59
  8. package/dist/examples/crypto-identity-example.js +55 -21
  9. package/dist/examples/mls-3-member-test.js +97 -0
  10. package/dist/examples/mls-multi-member.js +153 -0
  11. package/dist/examples/mls-sframe-test.js +14 -11
  12. package/dist/examples/mls-simple-test.js +58 -0
  13. package/dist/examples/shogun-core-example.js +90 -0
  14. package/dist/examples/zkproof-credentials-example.js +9 -5
  15. package/dist/examples/zkproof-example.js +14 -10
  16. package/dist/gundb/api.js +17 -16
  17. package/dist/gundb/db.js +769 -328
  18. package/dist/index.js +4 -4
  19. package/dist/managers/CoreInitializer.js +21 -15
  20. package/dist/managers/CryptoIdentityManager.js +79 -32
  21. package/dist/plugins/zkproof/zkCredentials.js +4 -1
  22. package/dist/types/config/simplified-config.d.ts +64 -3
  23. package/dist/types/crypto/sframe.d.ts +4 -0
  24. package/dist/types/examples/mls-3-member-test.d.ts +6 -0
  25. package/dist/types/examples/mls-multi-member.d.ts +6 -0
  26. package/dist/types/examples/mls-simple-test.d.ts +6 -0
  27. package/dist/types/examples/shogun-core-example.d.ts +8 -0
  28. package/dist/types/gundb/api.d.ts +6 -13
  29. package/dist/types/gundb/db.d.ts +84 -41
  30. package/dist/types/index.d.ts +4 -2
  31. package/dist/types/interfaces/shogun.d.ts +1 -2
  32. package/dist/types/managers/CryptoIdentityManager.d.ts +2 -1
  33. package/package.json +11 -8
  34. package/dist/examples/mls-advanced-example.js +0 -294
  35. package/dist/examples/quick-auth-test.js +0 -61
  36. package/dist/examples/simple-api-test.js +0 -114
  37. package/dist/examples/simple-crypto-identity-example.js +0 -84
  38. package/dist/examples/timeout-test.js +0 -227
  39. package/dist/types/examples/mls-advanced-example.d.ts +0 -53
  40. package/dist/types/examples/quick-auth-test.d.ts +0 -8
  41. package/dist/types/examples/simple-api-test.d.ts +0 -10
  42. package/dist/types/examples/simple-crypto-identity-example.d.ts +0 -6
  43. package/dist/types/examples/timeout-test.d.ts +0 -8
@@ -96755,9 +96755,15 @@ var AbstractRelay = class {
96755
96755
  publishTimeout = 4400;
96756
96756
  pingFrequency = 2e4;
96757
96757
  pingTimeout = 2e4;
96758
+ resubscribeBackoff = [1e4, 1e4, 1e4, 2e4, 2e4, 3e4, 6e4];
96758
96759
  openSubs = /* @__PURE__ */ new Map();
96759
96760
  enablePing;
96761
+ enableReconnect;
96760
96762
  connectionTimeoutHandle;
96763
+ reconnectTimeoutHandle;
96764
+ pingTimeoutHandle;
96765
+ reconnectAttempts = 0;
96766
+ closedIntentionally = false;
96761
96767
  connectionPromise;
96762
96768
  openCountRequests = /* @__PURE__ */ new Map();
96763
96769
  openEventPublishes = /* @__PURE__ */ new Map();
@@ -96774,6 +96780,7 @@ var AbstractRelay = class {
96774
96780
  this.verifyEvent = opts.verifyEvent;
96775
96781
  this._WebSocket = opts.websocketImplementation || WebSocket;
96776
96782
  this.enablePing = opts.enablePing;
96783
+ this.enableReconnect = opts.enableReconnect || false;
96777
96784
  }
96778
96785
  static async connect(url, opts) {
96779
96786
  const relay = new AbstractRelay(url, opts);
@@ -96797,6 +96804,32 @@ var AbstractRelay = class {
96797
96804
  get connected() {
96798
96805
  return this._connected;
96799
96806
  }
96807
+ async reconnect() {
96808
+ const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)];
96809
+ this.reconnectAttempts++;
96810
+ this.reconnectTimeoutHandle = setTimeout(async () => {
96811
+ try {
96812
+ await this.connect();
96813
+ } catch (err) {
96814
+ }
96815
+ }, backoff);
96816
+ }
96817
+ handleHardClose(reason) {
96818
+ if (this.pingTimeoutHandle) {
96819
+ clearTimeout(this.pingTimeoutHandle);
96820
+ this.pingTimeoutHandle = void 0;
96821
+ }
96822
+ this._connected = false;
96823
+ this.connectionPromise = void 0;
96824
+ const wasIntentional = this.closedIntentionally;
96825
+ this.closedIntentionally = false;
96826
+ this.onclose?.();
96827
+ if (this.enableReconnect && !wasIntentional) {
96828
+ this.reconnect();
96829
+ } else {
96830
+ this.closeAllSubscriptions(reason);
96831
+ }
96832
+ }
96800
96833
  async connect() {
96801
96834
  if (this.connectionPromise)
96802
96835
  return this.connectionPromise;
@@ -96817,8 +96850,20 @@ var AbstractRelay = class {
96817
96850
  return;
96818
96851
  }
96819
96852
  this.ws.onopen = () => {
96853
+ if (this.reconnectTimeoutHandle) {
96854
+ clearTimeout(this.reconnectTimeoutHandle);
96855
+ this.reconnectTimeoutHandle = void 0;
96856
+ }
96820
96857
  clearTimeout(this.connectionTimeoutHandle);
96821
96858
  this._connected = true;
96859
+ this.reconnectAttempts = 0;
96860
+ for (const sub of this.openSubs.values()) {
96861
+ sub.eosed = false;
96862
+ if (typeof this.enableReconnect === "function") {
96863
+ sub.filters = this.enableReconnect(sub.filters);
96864
+ }
96865
+ sub.fire();
96866
+ }
96822
96867
  if (this.enablePing) {
96823
96868
  this.pingpong();
96824
96869
  }
@@ -96827,28 +96872,22 @@ var AbstractRelay = class {
96827
96872
  this.ws.onerror = (ev) => {
96828
96873
  clearTimeout(this.connectionTimeoutHandle);
96829
96874
  reject(ev.message || "websocket error");
96830
- this._connected = false;
96831
- this.connectionPromise = void 0;
96832
- this.onclose?.();
96833
- this.closeAllSubscriptions("relay connection errored");
96875
+ this.handleHardClose("relay connection errored");
96834
96876
  };
96835
96877
  this.ws.onclose = (ev) => {
96836
96878
  clearTimeout(this.connectionTimeoutHandle);
96837
96879
  reject(ev.message || "websocket closed");
96838
- this._connected = false;
96839
- this.connectionPromise = void 0;
96840
- this.onclose?.();
96841
- this.closeAllSubscriptions("relay connection closed");
96880
+ this.handleHardClose("relay connection closed");
96842
96881
  };
96843
96882
  this.ws.onmessage = this._onmessage.bind(this);
96844
96883
  });
96845
96884
  return this.connectionPromise;
96846
96885
  }
96847
- async waitForPingPong() {
96848
- return new Promise((res, err) => {
96886
+ waitForPingPong() {
96887
+ return new Promise((resolve) => {
96849
96888
  ;
96850
- this.ws && this.ws.on && this.ws.on("pong", () => res(true)) || err("ws can't listen for pong");
96851
- this.ws && this.ws.ping && this.ws.ping();
96889
+ this.ws.once("pong", () => resolve(true));
96890
+ this.ws.ping();
96852
96891
  });
96853
96892
  }
96854
96893
  async waitForDummyReq() {
@@ -96865,16 +96904,15 @@ var AbstractRelay = class {
96865
96904
  async pingpong() {
96866
96905
  if (this.ws?.readyState === 1) {
96867
96906
  const result = await Promise.any([
96868
- this.ws && this.ws.ping && this.ws.on ? this.waitForPingPong() : this.waitForDummyReq(),
96907
+ this.ws && this.ws.ping && this.ws.once ? this.waitForPingPong() : this.waitForDummyReq(),
96869
96908
  new Promise((res) => setTimeout(() => res(false), this.pingTimeout))
96870
96909
  ]);
96871
96910
  if (result) {
96872
- setTimeout(() => this.pingpong(), this.pingFrequency);
96911
+ this.pingTimeoutHandle = setTimeout(() => this.pingpong(), this.pingFrequency);
96873
96912
  } else {
96874
- this.closeAllSubscriptions("pingpong timed out");
96875
- this._connected = false;
96876
- this.onclose?.();
96877
- this.ws?.close();
96913
+ if (this.ws?.readyState === this._WebSocket.OPEN) {
96914
+ this.ws?.close();
96915
+ }
96878
96916
  }
96879
96917
  }
96880
96918
  }
@@ -97037,10 +97075,21 @@ var AbstractRelay = class {
97037
97075
  return subscription;
97038
97076
  }
97039
97077
  close() {
97078
+ this.closedIntentionally = true;
97079
+ if (this.reconnectTimeoutHandle) {
97080
+ clearTimeout(this.reconnectTimeoutHandle);
97081
+ this.reconnectTimeoutHandle = void 0;
97082
+ }
97083
+ if (this.pingTimeoutHandle) {
97084
+ clearTimeout(this.pingTimeoutHandle);
97085
+ this.pingTimeoutHandle = void 0;
97086
+ }
97040
97087
  this.closeAllSubscriptions("relay connection closed by us");
97041
97088
  this._connected = false;
97042
97089
  this.onclose?.();
97043
- this.ws?.close();
97090
+ if (this.ws?.readyState === this._WebSocket.OPEN) {
97091
+ this.ws?.close();
97092
+ }
97044
97093
  }
97045
97094
  _onmessage(ev) {
97046
97095
  this.incomingMessageQueue.enqueue(ev.data);
@@ -97113,11 +97162,11 @@ try {
97113
97162
  } catch {
97114
97163
  }
97115
97164
  var Relay = class extends AbstractRelay {
97116
- constructor(url) {
97117
- super(url, { verifyEvent, websocketImplementation: _WebSocket });
97165
+ constructor(url, options) {
97166
+ super(url, { verifyEvent, websocketImplementation: _WebSocket, ...options });
97118
97167
  }
97119
- static async connect(url) {
97120
- const relay = new Relay(url);
97168
+ static async connect(url, options) {
97169
+ const relay = new Relay(url, options);
97121
97170
  await relay.connect();
97122
97171
  return relay;
97123
97172
  }
@@ -97130,12 +97179,14 @@ var AbstractSimplePool = class {
97130
97179
  trackRelays = false;
97131
97180
  verifyEvent;
97132
97181
  enablePing;
97182
+ enableReconnect;
97133
97183
  trustedRelayURLs = /* @__PURE__ */ new Set();
97134
97184
  _WebSocket;
97135
97185
  constructor(opts) {
97136
97186
  this.verifyEvent = opts.verifyEvent;
97137
97187
  this._WebSocket = opts.websocketImplementation;
97138
97188
  this.enablePing = opts.enablePing;
97189
+ this.enableReconnect = opts.enableReconnect;
97139
97190
  }
97140
97191
  async ensureRelay(url, params) {
97141
97192
  url = normalizeURL(url);
@@ -97144,10 +97195,13 @@ var AbstractSimplePool = class {
97144
97195
  relay = new AbstractRelay(url, {
97145
97196
  verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,
97146
97197
  websocketImplementation: this._WebSocket,
97147
- enablePing: this.enablePing
97198
+ enablePing: this.enablePing,
97199
+ enableReconnect: this.enableReconnect
97148
97200
  });
97149
97201
  relay.onclose = () => {
97150
- this.relays.delete(url);
97202
+ if (relay && !relay.enableReconnect) {
97203
+ this.relays.delete(url);
97204
+ }
97151
97205
  };
97152
97206
  if (params?.connectionTimeout)
97153
97207
  relay.connectionTimeout = params.connectionTimeout;
@@ -98642,13 +98696,13 @@ async function getZapEndpoint(metadata) {
98642
98696
  try {
98643
98697
  let lnurl = "";
98644
98698
  let { lud06, lud16 } = JSON.parse(metadata.content);
98645
- if (lud06) {
98699
+ if (lud16) {
98700
+ let [name, domain] = lud16.split("@");
98701
+ lnurl = new URL(`/.well-known/lnurlp/${name}`, `https://${domain}`).toString();
98702
+ } else if (lud06) {
98646
98703
  let { words } = import_base4.bech32.decode(lud06, 1e3);
98647
98704
  let data = import_base4.bech32.fromWords(words);
98648
98705
  lnurl = utf8Decoder.decode(data);
98649
- } else if (lud16) {
98650
- let [name, domain] = lud16.split("@");
98651
- lnurl = new URL(`/.well-known/lnurlp/${name}`, `https://${domain}`).toString();
98652
98706
  } else {
98653
98707
  return null;
98654
98708
  }
@@ -145094,38 +145148,101 @@ module.exports = function whichTypedArray(value) {
145094
145148
  /*!*****************************************!*\
145095
145149
  !*** ./src/config/simplified-config.ts ***!
145096
145150
  \*****************************************/
145097
- /***/ ((__unused_webpack_module, exports) => {
145151
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
145098
145152
 
145099
145153
  "use strict";
145100
145154
 
145101
145155
  /**
145102
145156
  * Simplified configuration options to reduce complexity
145103
145157
  * Provides sensible defaults and easy-to-use presets
145158
+ *
145159
+ * NOTE: This file is deprecated. ShogunCore now requires an existing Gun instance.
145160
+ * Use the examples in the examples/ directory for proper usage.
145104
145161
  */
145162
+ var __importDefault = (this && this.__importDefault) || function (mod) {
145163
+ return (mod && mod.__esModule) ? mod : { "default": mod };
145164
+ };
145105
145165
  Object.defineProperty(exports, "__esModule", ({ value: true }));
145106
- exports.QuickConfig = exports.ConfigHelpers = exports.ShogunConfigBuilder = exports.ShogunPresets = void 0;
145166
+ exports.QuickConfig = exports.ConfigHelpers = exports.ShogunConfigBuilder = exports.ShogunPresets = exports.GunInstanceHelpers = void 0;
145167
+ const gun_1 = __importDefault(__webpack_require__(/*! gun/gun */ "./node_modules/gun/gun.js"));
145168
+ __webpack_require__(/*! gun/lib/then */ "./node_modules/gun/lib/then.js");
145169
+ __webpack_require__(/*! gun/lib/radix */ "./node_modules/gun/lib/radix.js");
145170
+ __webpack_require__(/*! gun/lib/radisk */ "./node_modules/gun/lib/radisk.js");
145171
+ __webpack_require__(/*! gun/lib/store */ "./node_modules/gun/lib/store.js");
145172
+ __webpack_require__(/*! gun/lib/rindexed */ "./node_modules/gun/lib/rindexed.js");
145173
+ __webpack_require__(/*! gun/lib/webrtc */ "./node_modules/gun/lib/webrtc.js");
145174
+ /**
145175
+ * Helper functions to create Gun instances with common configurations
145176
+ * These functions create Gun instances that can be passed to ShogunCore
145177
+ */
145178
+ exports.GunInstanceHelpers = {
145179
+ /**
145180
+ * Create a minimal Gun instance for simple apps
145181
+ */
145182
+ minimal: () => (0, gun_1.default)({
145183
+ peers: ["https://shogunnode.scobrudot.dev/gun"],
145184
+ localStorage: true,
145185
+ }),
145186
+ /**
145187
+ * Create a development Gun instance with local storage
145188
+ */
145189
+ development: () => (0, gun_1.default)({
145190
+ peers: ["https://shogunnode.scobrudot.dev/gun"],
145191
+ localStorage: true,
145192
+ radisk: false,
145193
+ }),
145194
+ /**
145195
+ * Create a production Gun instance with multiple peers
145196
+ */
145197
+ production: (customPeers) => (0, gun_1.default)({
145198
+ peers: customPeers || [
145199
+ "https://shogunnode.scobrudot.dev/gun",
145200
+ "https://peer.wallie.io/gun",
145201
+ ],
145202
+ localStorage: true,
145203
+ radisk: true,
145204
+ }),
145205
+ /**
145206
+ * Create an offline-first Gun instance
145207
+ */
145208
+ offline: () => (0, gun_1.default)({
145209
+ peers: [],
145210
+ localStorage: true,
145211
+ radisk: true,
145212
+ }),
145213
+ /**
145214
+ * Create a Gun instance for Web3-enabled apps
145215
+ */
145216
+ web3: () => (0, gun_1.default)({
145217
+ peers: ["https://shogunnode.scobrudot.dev/gun"],
145218
+ localStorage: true,
145219
+ }),
145220
+ /**
145221
+ * Create a Gun instance for WebAuthn-enabled apps
145222
+ */
145223
+ webauthn: () => (0, gun_1.default)({
145224
+ peers: ["https://shogunnode.scobrudot.dev/gun"],
145225
+ localStorage: true,
145226
+ }),
145227
+ };
145107
145228
  /**
145108
145229
  * Preset configurations for common use cases
145230
+ * @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
145109
145231
  */
145110
145232
  exports.ShogunPresets = {
145111
145233
  /**
145112
145234
  * Minimal configuration for simple apps
145235
+ * @deprecated Use GunInstanceHelpers.minimal() instead
145113
145236
  */
145114
145237
  minimal: () => ({
145115
- gunOptions: {
145116
- peers: ["https://relay.shogun-eco.xyz/gun"],
145117
- localStorage: true,
145118
- },
145238
+ gunInstance: exports.GunInstanceHelpers.minimal(),
145119
145239
  }),
145120
145240
  /**
145121
145241
  * Development configuration with local storage
145242
+ * @deprecated Use GunInstanceHelpers.development() instead
145122
145243
  */
145123
145244
  development: () => ({
145124
- gunOptions: {
145125
- peers: ["https://relay.shogun-eco.xyz/gun"],
145126
- localStorage: true,
145127
- radisk: false,
145128
- },
145245
+ gunInstance: exports.GunInstanceHelpers.development(),
145129
145246
  timeouts: {
145130
145247
  login: 5000,
145131
145248
  signup: 5000,
@@ -145134,16 +145251,10 @@ exports.ShogunPresets = {
145134
145251
  }),
145135
145252
  /**
145136
145253
  * Production configuration with multiple peers
145254
+ * @deprecated Use GunInstanceHelpers.production() instead
145137
145255
  */
145138
145256
  production: (customPeers) => ({
145139
- gunOptions: {
145140
- peers: customPeers || [
145141
- "https://relay.shogun-eco.xyz/gun",
145142
- "https://peer.wallie.io/gun",
145143
- ],
145144
- localStorage: true,
145145
- radisk: true,
145146
- },
145257
+ gunInstance: exports.GunInstanceHelpers.production(customPeers),
145147
145258
  timeouts: {
145148
145259
  login: 10000,
145149
145260
  signup: 10000,
@@ -145152,62 +145263,59 @@ exports.ShogunPresets = {
145152
145263
  }),
145153
145264
  /**
145154
145265
  * Offline-first configuration
145266
+ * @deprecated Use GunInstanceHelpers.offline() instead
145155
145267
  */
145156
145268
  offline: () => ({
145157
- gunOptions: {
145158
- peers: [],
145159
- localStorage: true,
145160
- radisk: true,
145161
- },
145269
+ gunInstance: exports.GunInstanceHelpers.offline(),
145162
145270
  }),
145163
145271
  /**
145164
145272
  * Web3-enabled configuration
145273
+ * @deprecated Use GunInstanceHelpers.web3() instead
145165
145274
  */
145166
145275
  web3: () => ({
145167
- gunOptions: {
145168
- peers: ["https://relay.shogun-eco.xyz/gun"],
145169
- localStorage: true,
145170
- },
145276
+ gunInstance: exports.GunInstanceHelpers.web3(),
145171
145277
  web3: {
145172
145278
  enabled: true,
145173
145279
  },
145174
145280
  }),
145175
145281
  /**
145176
145282
  * WebAuthn-enabled configuration
145283
+ * @deprecated Use GunInstanceHelpers.webauthn() instead
145177
145284
  */
145178
145285
  webauthn: () => ({
145179
- gunOptions: {
145180
- peers: ["https://relay.shogun-eco.xyz/gun"],
145181
- localStorage: true,
145182
- },
145286
+ gunInstance: exports.GunInstanceHelpers.webauthn(),
145183
145287
  webauthn: {
145184
145288
  enabled: true,
145185
145289
  rpName: "My Shogun App",
145186
- rpId: window.location.hostname,
145290
+ rpId: true ? window.location.hostname : 0,
145187
145291
  },
145188
145292
  }),
145189
145293
  };
145190
145294
  /**
145191
145295
  * Configuration builder for custom setups
145296
+ * @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
145192
145297
  */
145193
145298
  class ShogunConfigBuilder {
145194
145299
  constructor() {
145195
145300
  this.config = {};
145301
+ this.gunOptions = {};
145196
145302
  }
145197
145303
  /**
145198
- * Set Gun options
145304
+ * Set Gun options (deprecated - use GunInstanceHelpers instead)
145305
+ * @deprecated Use GunInstanceHelpers to create Gun instances
145199
145306
  */
145200
- gunOptions(options) {
145201
- this.config.gunOptions = { ...this.config.gunOptions, ...options };
145307
+ setGunOptions(options) {
145308
+ this.gunOptions = { ...this.gunOptions, ...options };
145202
145309
  return this;
145203
145310
  }
145204
145311
  /**
145205
- * Add peers
145312
+ * Add peers (deprecated - use GunInstanceHelpers instead)
145313
+ * @deprecated Use GunInstanceHelpers to create Gun instances
145206
145314
  */
145207
145315
  peers(peerList) {
145208
- this.config.gunOptions = {
145209
- ...this.config.gunOptions,
145210
- peers: [...(this.config.gunOptions?.peers || []), ...peerList],
145316
+ this.gunOptions = {
145317
+ ...this.gunOptions,
145318
+ peers: [...(this.gunOptions?.peers || []), ...peerList],
145211
145319
  };
145212
145320
  return this;
145213
145321
  }
@@ -145245,18 +145353,24 @@ class ShogunConfigBuilder {
145245
145353
  }
145246
145354
  /**
145247
145355
  * Build the final configuration
145356
+ * @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
145248
145357
  */
145249
145358
  build() {
145250
- return this.config;
145359
+ return {
145360
+ ...this.config,
145361
+ gunInstance: (0, gun_1.default)(this.gunOptions),
145362
+ };
145251
145363
  }
145252
145364
  }
145253
145365
  exports.ShogunConfigBuilder = ShogunConfigBuilder;
145254
145366
  /**
145255
145367
  * Helper functions for common configuration patterns
145368
+ * @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
145256
145369
  */
145257
145370
  exports.ConfigHelpers = {
145258
145371
  /**
145259
145372
  * Create a configuration for a specific environment
145373
+ * @deprecated Use GunInstanceHelpers instead
145260
145374
  */
145261
145375
  forEnvironment(env) {
145262
145376
  switch (env) {
@@ -145272,12 +145386,14 @@ exports.ConfigHelpers = {
145272
145386
  },
145273
145387
  /**
145274
145388
  * Create a configuration with custom peers
145389
+ * @deprecated Use GunInstanceHelpers.production(peers) instead
145275
145390
  */
145276
145391
  withPeers(peers) {
145277
145392
  return exports.ShogunPresets.production(peers);
145278
145393
  },
145279
145394
  /**
145280
145395
  * Create a configuration for a specific use case
145396
+ * @deprecated Use GunInstanceHelpers instead
145281
145397
  */
145282
145398
  forUseCase(useCase) {
145283
145399
  const baseConfig = exports.ShogunPresets.production();
@@ -145310,26 +145426,32 @@ exports.ConfigHelpers = {
145310
145426
  };
145311
145427
  /**
145312
145428
  * Quick configuration functions
145429
+ * @deprecated Use GunInstanceHelpers to create Gun instances and pass them to ShogunCore
145313
145430
  */
145314
145431
  exports.QuickConfig = {
145315
145432
  /**
145316
145433
  * Minimal setup for quick testing
145434
+ * @deprecated Use GunInstanceHelpers.minimal() instead
145317
145435
  */
145318
145436
  test: () => exports.ShogunPresets.minimal(),
145319
145437
  /**
145320
145438
  * Standard setup for most apps
145439
+ * @deprecated Use GunInstanceHelpers.production() instead
145321
145440
  */
145322
145441
  standard: () => exports.ShogunPresets.production(),
145323
145442
  /**
145324
145443
  * Setup with WebAuthn for secure apps
145444
+ * @deprecated Use GunInstanceHelpers.webauthn() instead
145325
145445
  */
145326
145446
  secure: () => exports.ShogunPresets.webauthn(),
145327
145447
  /**
145328
145448
  * Setup with Web3 for crypto apps
145449
+ * @deprecated Use GunInstanceHelpers.web3() instead
145329
145450
  */
145330
145451
  crypto: () => exports.ShogunPresets.web3(),
145331
145452
  /**
145332
145453
  * Offline setup for local development
145454
+ * @deprecated Use GunInstanceHelpers.offline() instead
145333
145455
  */
145334
145456
  local: () => exports.ShogunPresets.offline(),
145335
145457
  };
@@ -146898,7 +147020,9 @@ class MLSManager {
146898
147020
  console.group("🔍 [MLS Debug] Commit Structure");
146899
147021
  console.log("commitResult keys:", Object.keys(commitResult));
146900
147022
  console.log("commit:", commitResult.commit);
146901
- console.log("commit.privateMessage:", commitResult.commit?.privateMessage);
147023
+ if (commitResult.commit?.wireformat === "mls_private_message") {
147024
+ console.log("commit.privateMessage:", commitResult.commit.privateMessage);
147025
+ }
146902
147026
  console.groupEnd();
146903
147027
  // RFC 9420 Section 11.2: Commit Distribution
146904
147028
  // ⚠️ IMPORTANT: The returned commit MUST be sent to all existing group members
@@ -146962,8 +147086,8 @@ class MLSManager {
146962
147086
  else {
146963
147087
  console.log(` Node ${i}:`, {
146964
147088
  type: typeof node,
146965
- isObject: typeof node === "object",
146966
- hasNodeType: node && typeof node === "object" && "nodeType" in node,
147089
+ isObject: typeof node === "object" && node !== null,
147090
+ hasNodeType: typeof node === "object" && node !== null && "nodeType" in node,
146967
147091
  nodeType: node?.nodeType,
146968
147092
  keys: node && typeof node === "object"
146969
147093
  ? Object.keys(node).slice(0, 5)
@@ -147040,10 +147164,11 @@ class MLSManager {
147040
147164
  }
147041
147165
  // Decode the message
147042
147166
  const decoded = (0, ts_mls_1.decodeMlsMessage)(envelope.ciphertext, 0);
147043
- if (!decoded) {
147167
+ if (!decoded || decoded.length === 0) {
147168
+ // Changed from 0n to 0 to fix type error
147044
147169
  throw new Error("Failed to decode message");
147045
147170
  }
147046
- const [decodedMessage] = decoded;
147171
+ const decodedMessage = decoded[0];
147047
147172
  if (decodedMessage.wireformat !== "mls_private_message") {
147048
147173
  throw new Error("Expected private message");
147049
147174
  }
@@ -147149,7 +147274,7 @@ class MLSManager {
147149
147274
  }
147150
147275
  catch (error) {
147151
147276
  console.error("❌ [MLS] Failed to process commit:", error);
147152
- console.error("❌ [MLS Debug] Error details:", error instanceof Error ? error.stack : "No stack trace");
147277
+ console.error("❌ [MLS Debug] Error details:", error instanceof Error ? error.stack : String(error));
147153
147278
  console.error("❌ [MLS Debug] Error message:", error instanceof Error ? error.message : String(error));
147154
147279
  throw new Error(`Commit processing failed: ${error instanceof Error ? error.message : String(error)}`);
147155
147280
  }
@@ -147169,7 +147294,7 @@ class MLSManager {
147169
147294
  const removeProposals = memberIndices.map((index) => ({
147170
147295
  proposalType: "remove",
147171
147296
  remove: {
147172
- removed: index, // ts-mls expects number, not BigInt
147297
+ removed: index, // Changed from BigInt(index) to number
147173
147298
  },
147174
147299
  }));
147175
147300
  // Create commit with remove proposals
@@ -147177,11 +147302,21 @@ class MLSManager {
147177
147302
  // Update group state
147178
147303
  this.groups.set(groupId, commitResult.newState);
147179
147304
  // Encode the commit
147180
- const encodedCommit = (0, ts_mls_1.encodeMlsMessage)({
147181
- publicMessage: commitResult.publicMessage,
147182
- wireformat: "mls_public_message",
147183
- version: "mls10",
147184
- });
147305
+ let encodedCommit;
147306
+ if (commitResult.commit &&
147307
+ commitResult.commit.wireformat === "mls_public_message") {
147308
+ encodedCommit = (0, ts_mls_1.encodeMlsMessage)({
147309
+ publicMessage: commitResult.commit
147310
+ .publicMessage,
147311
+ wireformat: "mls_public_message",
147312
+ version: "mls10",
147313
+ });
147314
+ }
147315
+ else {
147316
+ // Fallback or error handling if not a public message
147317
+ // For now, we'll assume it should be public for remove operation.
147318
+ throw new Error("Commit result does not contain a public message for encoding.");
147319
+ }
147185
147320
  console.log("✅ [MLS] Members removed");
147186
147321
  return encodedCommit;
147187
147322
  }
@@ -147274,9 +147409,15 @@ class MLSManager {
147274
147409
  const node = state.ratchetTree[i];
147275
147410
  if (node &&
147276
147411
  node.nodeType === "leaf" &&
147277
- node.leaf?.credential) {
147278
- const identity = new TextDecoder().decode(node.leaf.credential.identity);
147279
- members.push(identity);
147412
+ node.leaf.credential) {
147413
+ const credential = node.leaf.credential;
147414
+ if (credential.credentialType === "basic" && credential.identity) {
147415
+ const identity = new TextDecoder().decode(credential.identity);
147416
+ members.push(identity);
147417
+ }
147418
+ else {
147419
+ console.warn("Skipping credential without basic identity:", credential);
147420
+ }
147280
147421
  }
147281
147422
  }
147282
147423
  }
@@ -148181,6 +148322,13 @@ class SFrameManager {
148181
148322
  throw new Error(`SFrame key derivation failed: ${error instanceof Error ? error.message : String(error)}`);
148182
148323
  }
148183
148324
  }
148325
+ /**
148326
+ * Set a shared SFrame key (e.g., from another member)
148327
+ */
148328
+ async setSharedKey(sframeKey) {
148329
+ this.keys.set(sframeKey.keyId, sframeKey);
148330
+ console.log(`✅ [SFrame] Shared key ${sframeKey.keyId} set.`);
148331
+ }
148184
148332
  /**
148185
148333
  * Set the active encryption key
148186
148334
  */
@@ -148226,11 +148374,9 @@ class SFrameManager {
148226
148374
  tagLength: 128, // 128-bit authentication tag
148227
148375
  }, sframeKey.key, frameData);
148228
148376
  // RFC 9605: SFrame format = header + ciphertext (IV is derived, not transmitted)
148229
- // Note: We include IV for now for simplicity, but RFC specifies deriving it from counter
148230
- const encrypted = new Uint8Array(header.length + iv.length + ciphertext.byteLength);
148377
+ const encrypted = new Uint8Array(header.length + ciphertext.byteLength);
148231
148378
  encrypted.set(header, 0);
148232
- encrypted.set(iv, header.length);
148233
- encrypted.set(new Uint8Array(ciphertext), header.length + iv.length);
148379
+ encrypted.set(new Uint8Array(ciphertext), header.length);
148234
148380
  // Increment frame counter
148235
148381
  this.frameCounter++;
148236
148382
  return encrypted;
@@ -148255,20 +148401,17 @@ class SFrameManager {
148255
148401
  if (!sframeKey) {
148256
148402
  throw new Error(`SFrame key ${keyId} not found`);
148257
148403
  }
148258
- // Extract IV (12 bytes after header)
148259
- const iv = encryptedFrame.slice(5, 17);
148260
- // RFC 9605: Verify IV derivation (optional check for debugging)
148261
- // Reconstruct expected IV from frame count and salt
148404
+ // RFC 9605: IV is derived from frame count and salt (not transmitted)
148262
148405
  const counterBytes = new Uint8Array(12);
148263
148406
  const counterView = new DataView(counterBytes.buffer);
148264
148407
  counterView.setUint32(4, Math.floor(frameCount / 0x100000000), false);
148265
148408
  counterView.setUint32(8, frameCount & 0xffffffff, false);
148266
- const expectedIV = new Uint8Array(12);
148409
+ const iv = new Uint8Array(12);
148267
148410
  for (let i = 0; i < 12; i++) {
148268
- expectedIV[i] = sframeKey.salt[i] ^ counterBytes[i];
148411
+ iv[i] = sframeKey.salt[i] ^ counterBytes[i];
148269
148412
  }
148270
148413
  // Extract ciphertext (rest of the data)
148271
- const ciphertext = encryptedFrame.slice(17);
148414
+ const ciphertext = encryptedFrame.slice(header.length);
148272
148415
  // Decrypt the frame with header authentication (RFC 9605 Section 4.3)
148273
148416
  const plaintext = await crypto.subtle.decrypt({
148274
148417
  name: "AES-GCM",
@@ -149170,7 +149313,8 @@ class SimpleGunAPI {
149170
149313
  console.warn("DEPRECATED: putArray() is unreliable with GunDB. Use direct GunDB operations instead.");
149171
149314
  try {
149172
149315
  const indexed = this.arrayToIndexedObject(arr);
149173
- await this.db.put(path, indexed);
149316
+ const node = this.db.getNode(path);
149317
+ node.put(indexed);
149174
149318
  return true;
149175
149319
  }
149176
149320
  catch (error) {
@@ -149187,7 +149331,14 @@ class SimpleGunAPI {
149187
149331
  async getArray(path) {
149188
149332
  console.warn("DEPRECATED: getArray() is unreliable with GunDB. Use direct GunDB operations instead.");
149189
149333
  try {
149190
- const indexedObj = await this.db.getData(path);
149334
+ const node = this.db.getNode(path);
149335
+ const indexedObj = await new Promise((resolve) => {
149336
+ const timeout = setTimeout(() => resolve(null), 2000);
149337
+ node.once((data) => {
149338
+ clearTimeout(timeout);
149339
+ resolve(data);
149340
+ });
149341
+ });
149191
149342
  return this.indexedObjectToArray(indexedObj);
149192
149343
  }
149193
149344
  catch (error) {
@@ -149472,19 +149623,12 @@ class QuickStart {
149472
149623
  }
149473
149624
  exports.QuickStart = QuickStart;
149474
149625
  /**
149475
- * Auto Quick Start helper - creates a simple API with automatic Gun instance creation
149476
- * No need to pass a Gun instance, it creates one automatically
149626
+ * Auto Quick Start helper - creates a simple API with an existing Gun instance
149627
+ * Requires a Gun instance to be passed in
149477
149628
  */
149478
149629
  class AutoQuickStart {
149479
- constructor(config) {
149480
- const gunConfig = {
149481
- peers: config?.peers || [],
149482
- ...config,
149483
- };
149484
- // Remove appScope from gunConfig as it's not a Gun configuration option
149485
- delete gunConfig.appScope;
149486
- this.gunInstance = (0, db_1.createGun)(gunConfig);
149487
- const appScope = config?.appScope || "shogun";
149630
+ constructor(gunInstance, appScope = "shogun") {
149631
+ this.gunInstance = gunInstance;
149488
149632
  this.db = new db_1.DataBase(this.gunInstance, appScope);
149489
149633
  this.simpleAPI = new SimpleGunAPI(this.db);
149490
149634
  }
@@ -149513,10 +149657,10 @@ function quickStart(gunInstance, appScope) {
149513
149657
  return new QuickStart(gunInstance, appScope);
149514
149658
  }
149515
149659
  /**
149516
- * Global helper for auto quick setup - creates Gun instance automatically
149660
+ * Global helper for auto quick setup - requires existing Gun instance
149517
149661
  */
149518
- function autoQuickStart(config) {
149519
- return new AutoQuickStart(config);
149662
+ function autoQuickStart(gunInstance, appScope = "shogun") {
149663
+ return new AutoQuickStart(gunInstance, appScope);
149520
149664
  }
149521
149665
 
149522
149666
 
@@ -149823,6 +149967,7 @@ function randomUUID() {
149823
149967
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
149824
149968
 
149825
149969
  "use strict";
149970
+ /* provided dependency */ var process = __webpack_require__(/*! process/browser */ "./node_modules/process/browser.js");
149826
149971
 
149827
149972
  /**
149828
149973
  * GunDB class with enhanced features:
@@ -149867,17 +150012,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
149867
150012
  return (mod && mod.__esModule) ? mod : { "default": mod };
149868
150013
  };
149869
150014
  Object.defineProperty(exports, "__esModule", ({ value: true }));
149870
- exports.createGun = exports.derive = exports.GunErrors = exports.crypto = exports.RxJS = exports.SEA = exports.DataBase = exports.Gun = void 0;
149871
- const gun_1 = __importDefault(__webpack_require__(/*! gun/gun */ "./node_modules/gun/gun.js"));
149872
- exports.Gun = gun_1.default;
150015
+ exports.derive = exports.GunErrors = exports.crypto = exports.RxJS = exports.SEA = exports.DataBase = void 0;
149873
150016
  const sea_1 = __importDefault(__webpack_require__(/*! gun/sea */ "./node_modules/gun/sea.js"));
149874
150017
  exports.SEA = sea_1.default;
149875
- __webpack_require__(/*! gun/lib/then */ "./node_modules/gun/lib/then.js");
149876
- __webpack_require__(/*! gun/lib/radix */ "./node_modules/gun/lib/radix.js");
149877
- __webpack_require__(/*! gun/lib/radisk */ "./node_modules/gun/lib/radisk.js");
149878
- __webpack_require__(/*! gun/lib/store */ "./node_modules/gun/lib/store.js");
149879
- __webpack_require__(/*! gun/lib/rindexed */ "./node_modules/gun/lib/rindexed.js");
149880
- __webpack_require__(/*! gun/lib/webrtc */ "./node_modules/gun/lib/webrtc.js");
149881
150018
  const derive_1 = __importDefault(__webpack_require__(/*! ./derive */ "./src/gundb/derive.ts"));
149882
150019
  exports.derive = derive_1.default;
149883
150020
  const errorHandler_1 = __webpack_require__(/*! ../utils/errorHandler */ "./src/utils/errorHandler.ts");
@@ -149908,11 +150045,17 @@ class DataBase {
149908
150045
  constructor(gun, appScope = "shogun", core) {
149909
150046
  this.user = null;
149910
150047
  this.onAuthCallbacks = [];
150048
+ // Memory leak prevention
150049
+ this._activeTimeouts = new Set();
150050
+ this._activeIntervals = new Set();
150051
+ this._isDestroyed = false;
149911
150052
  console.log("[DB] Initializing DataBase");
149912
150053
  // Store core reference
149913
150054
  this.core = core;
149914
150055
  // Initialize event emitter
149915
150056
  this.eventEmitter = new eventEmitter_1.EventEmitter();
150057
+ // Setup cleanup handlers
150058
+ this.setupCleanupHandlers();
149916
150059
  // Validate Gun instance
149917
150060
  if (!gun) {
149918
150061
  throw new Error("Gun instance is required but was not provided");
@@ -149954,7 +150097,7 @@ class DataBase {
149954
150097
  this.node = this.gun.get(appScope);
149955
150098
  console.log("[DB] App scope node initialized");
149956
150099
  // Initialize CryptoIdentityManager
149957
- this._cryptoIdentityManager = new CryptoIdentityManager_1.CryptoIdentityManager(this.core);
150100
+ this._cryptoIdentityManager = new CryptoIdentityManager_1.CryptoIdentityManager(this.core, this);
149958
150101
  console.log("[DB] CryptoIdentityManager initialized");
149959
150102
  if (sessionResult.success) {
149960
150103
  console.log("[DB] Session automatically restored");
@@ -150206,46 +150349,26 @@ class DataBase {
150206
150349
  return this.navigateToPath(this.node, path);
150207
150350
  }
150208
150351
  /**
150209
- * Gets data at the specified path (one-time read)
150210
- * @param path Path to get the data from
150211
- * @returns Promise resolving to the data
150212
- */
150213
- async getData(path) {
150214
- const node = this.navigateToPath(this.node, path);
150215
- return new Promise((resolve, reject) => {
150216
- node.once((data) => {
150217
- resolve(data);
150218
- });
150219
- });
150220
- }
150221
- /**
150222
- * Puts data at the specified path
150223
- * @param path Path to store data
150224
- * @param data Data to store
150225
- * @returns Promise resolving to operation result
150352
+ * Gets the Gun instance for direct operations
150353
+ * @returns Gun instance
150226
150354
  */
150227
- async put(path, data) {
150228
- const node = this.navigateToPath(this.node, path);
150229
- return await node.put(data).then();
150355
+ getGunInstance() {
150356
+ return this.gun;
150230
150357
  }
150231
150358
  /**
150232
- * Sets data at the specified path
150233
- * @param path Path to store data
150234
- * @param data Data to store
150235
- * @returns Promise resolving to operation result
150359
+ * Gets the app scope node for direct operations
150360
+ * @returns Gun node
150236
150361
  */
150237
- async set(path, data) {
150238
- const node = this.navigateToPath(this.node, path);
150239
- return await node.set(data).then();
150362
+ getAppNode() {
150363
+ return this.node;
150240
150364
  }
150241
150365
  /**
150242
- * Removes data at the specified path
150243
- * @param path Path to remove
150244
- * @returns Promise resolving to operation result
150366
+ * Helper method to get a node at a specific path for direct GUN operations
150367
+ * @param path Path to the node
150368
+ * @returns Gun node at the specified path
150245
150369
  */
150246
- async remove(path) {
150247
- const node = this.navigateToPath(this.node, path);
150248
- return await node.put(null).then();
150370
+ getNode(path) {
150371
+ return this.navigateToPath(this.node, path);
150249
150372
  }
150250
150373
  /**
150251
150374
  * Checks if a user is currently logged in
@@ -150403,6 +150526,10 @@ class DataBase {
150403
150526
  // Log out user
150404
150527
  try {
150405
150528
  currentUser.leave();
150529
+ // Force clear any pending authentication
150530
+ if (currentUser._ && currentUser._.sea) {
150531
+ currentUser._.sea = null;
150532
+ }
150406
150533
  }
150407
150534
  catch (gunError) {
150408
150535
  console.error("Error during Gun logout:", gunError);
@@ -150511,136 +150638,6 @@ class DataBase {
150511
150638
  // Validate password strength
150512
150639
  return this.validatePasswordStrength(password);
150513
150640
  }
150514
- /**
150515
- * Creates a new user in Gun
150516
- */
150517
- async createNewUser(username, password) {
150518
- return new Promise((resolve) => {
150519
- // Validate inputs before creating user
150520
- if (!username ||
150521
- typeof username !== "string" ||
150522
- username.trim().length === 0) {
150523
- resolve({ success: false, error: "Invalid username provided" });
150524
- return;
150525
- }
150526
- if (!password ||
150527
- typeof password !== "string" ||
150528
- password.length === 0) {
150529
- resolve({ success: false, error: "Invalid password provided" });
150530
- return;
150531
- }
150532
- // Normalize username
150533
- const normalizedUsername = username.trim().toLowerCase();
150534
- if (normalizedUsername.length === 0) {
150535
- resolve({
150536
- success: false,
150537
- error: "Username cannot be empty",
150538
- });
150539
- return;
150540
- }
150541
- this.gun.user().create(normalizedUsername, password, (ack) => {
150542
- if (ack.err) {
150543
- console.error(`User creation error: ${ack.err}`);
150544
- resolve({ success: false, error: ack.err });
150545
- }
150546
- else {
150547
- // Validate that we got a userPub from creation
150548
- const userPub = ack.pub;
150549
- if (!userPub ||
150550
- typeof userPub !== "string" ||
150551
- userPub.trim().length === 0) {
150552
- console.error("User creation successful but no userPub returned:", ack);
150553
- resolve({
150554
- success: false,
150555
- error: "User creation successful but no userPub returned",
150556
- });
150557
- }
150558
- else {
150559
- resolve({ success: true, userPub: userPub });
150560
- }
150561
- }
150562
- });
150563
- });
150564
- }
150565
- /**
150566
- * Authenticates user after creation
150567
- */
150568
- async authenticateNewUser(username, password, pair) {
150569
- return new Promise((resolve) => {
150570
- // Validate inputs before authentication
150571
- if (!username ||
150572
- typeof username !== "string" ||
150573
- username.trim().length === 0) {
150574
- resolve({ success: false, error: "Invalid username provided" });
150575
- return;
150576
- }
150577
- // Skip password validation when using pair authentication
150578
- if (!pair &&
150579
- (!password || typeof password !== "string" || password.length === 0)) {
150580
- resolve({ success: false, error: "Invalid password provided" });
150581
- return;
150582
- }
150583
- // Normalize username to match what was used in creation
150584
- const normalizedUsername = username.trim().toLowerCase();
150585
- if (normalizedUsername.length === 0) {
150586
- resolve({
150587
- success: false,
150588
- error: "Username cannot be empty",
150589
- });
150590
- return;
150591
- }
150592
- if (pair) {
150593
- this.gun.user().auth(pair, (ack) => {
150594
- if (ack.err) {
150595
- console.error(`Authentication after creation failed: ${ack.err}`);
150596
- resolve({ success: false, error: ack.err });
150597
- }
150598
- else {
150599
- // Add a small delay to ensure user state is properly set
150600
- setTimeout(() => {
150601
- // Extract userPub from multiple possible sources
150602
- const userPub = ack.pub || this.gun.user().is?.pub || ack.user?.pub;
150603
- if (!userPub) {
150604
- console.error("Authentication successful but no userPub found");
150605
- resolve({
150606
- success: false,
150607
- error: "No userPub returned from authentication",
150608
- });
150609
- }
150610
- else {
150611
- resolve({ success: true, userPub: userPub });
150612
- }
150613
- }, 100);
150614
- }
150615
- });
150616
- }
150617
- else {
150618
- this.gun.user().auth(normalizedUsername, password, (ack) => {
150619
- if (ack.err) {
150620
- console.error(`Authentication after creation failed: ${ack.err}`);
150621
- resolve({ success: false, error: ack.err });
150622
- }
150623
- else {
150624
- // Add a small delay to ensure user state is properly set
150625
- setTimeout(() => {
150626
- // Extract userPub from multiple possible sources
150627
- const userPub = ack.pub || this.gun.user().is?.pub || ack.user?.pub;
150628
- if (!userPub) {
150629
- console.error("Authentication successful but no userPub found");
150630
- resolve({
150631
- success: false,
150632
- error: "No userPub returned from authentication",
150633
- });
150634
- }
150635
- else {
150636
- resolve({ success: true, userPub: userPub });
150637
- }
150638
- }, 100);
150639
- }
150640
- });
150641
- }
150642
- });
150643
- }
150644
150641
  /**
150645
150642
  * Signs up a new user using direct Gun authentication
150646
150643
  * @param username Username
@@ -150648,13 +150645,34 @@ class DataBase {
150648
150645
  * @param pair Optional SEA pair for Web3 login
150649
150646
  * @returns Promise resolving to signup result
150650
150647
  */
150651
- async signUp(username, password, pair) {
150648
+ async signUp(username, password, pair, retryCount = 0, maxRetries = 3) {
150652
150649
  try {
150650
+ console.log(`🔄 [SIGNUP] Attempting signup for: ${username}`);
150653
150651
  // Validate credentials with enhanced security
150654
150652
  const validation = this.validateSignupCredentials(username, password, pair);
150655
150653
  if (!validation.valid) {
150656
150654
  return { success: false, error: validation.error };
150657
150655
  }
150656
+ // Check if authentication is in progress and retry if needed
150657
+ if (this.isAuthInProgress()) {
150658
+ if (retryCount < maxRetries) {
150659
+ console.warn(`Authentication in progress during signup, retrying... (${retryCount + 1}/${maxRetries})`);
150660
+ this.resetAuthState();
150661
+ const baseDelay = 100 * Math.pow(2, retryCount);
150662
+ const jitter = Math.random() * 100;
150663
+ const delay = Math.min(baseDelay + jitter, 2000);
150664
+ await new Promise((resolve) => setTimeout(resolve, delay));
150665
+ return this.signUp(username, password, pair, retryCount + 1, maxRetries);
150666
+ }
150667
+ else {
150668
+ console.error("Max retries exceeded for signup due to concurrent operations");
150669
+ this.resetAuthState();
150670
+ return {
150671
+ success: false,
150672
+ error: "Signup failed after multiple retries due to concurrent operations",
150673
+ };
150674
+ }
150675
+ }
150658
150676
  let createResult;
150659
150677
  if (pair) {
150660
150678
  // For Web3/plugin authentication, use pair-based creation
@@ -150662,15 +150680,17 @@ class DataBase {
150662
150680
  }
150663
150681
  else {
150664
150682
  // For password authentication, use standard creation
150665
- createResult = await this.createNewUser(username, password);
150683
+ createResult = await this.createNewUserFixed(username, password);
150666
150684
  }
150667
150685
  if (!createResult.success) {
150686
+ // Reset auth state after failed creation to prevent blocking future operations
150687
+ this.resetAuthState();
150668
150688
  return { success: false, error: createResult.error };
150669
150689
  }
150670
150690
  // Add a small delay to ensure user is properly registered
150671
150691
  await new Promise((resolve) => setTimeout(resolve, 100));
150672
150692
  // Authenticate the newly created user
150673
- const authResult = await this.authenticateNewUser(username, password, pair);
150693
+ const authResult = await this.authenticateNewUserFixed(username, password, pair);
150674
150694
  if (!authResult.success) {
150675
150695
  return { success: false, error: authResult.error };
150676
150696
  }
@@ -150747,6 +150767,100 @@ class DataBase {
150747
150767
  resolve({ success: true, userPub: pair.pub });
150748
150768
  });
150749
150769
  }
150770
+ /**
150771
+ * Creates a new user in Gun without waiting for acknowledgment
150772
+ */
150773
+ async createNewUserFixed(username, password) {
150774
+ return new Promise((resolve) => {
150775
+ // Validate inputs before creating user
150776
+ if (!username ||
150777
+ typeof username !== "string" ||
150778
+ username.trim().length === 0) {
150779
+ resolve({ success: false, error: "Invalid username provided" });
150780
+ return;
150781
+ }
150782
+ if (!password ||
150783
+ typeof password !== "string" ||
150784
+ password.length === 0) {
150785
+ resolve({ success: false, error: "Invalid password provided" });
150786
+ return;
150787
+ }
150788
+ // Normalize username
150789
+ const normalizedUsername = username.trim().toLowerCase();
150790
+ if (normalizedUsername.length === 0) {
150791
+ resolve({
150792
+ success: false,
150793
+ error: "Username cannot be empty",
150794
+ });
150795
+ return;
150796
+ }
150797
+ console.log(`🔄 [CREATE] Creating user: ${normalizedUsername}`);
150798
+ // Crea utente senza aspettare acknowledgment
150799
+ this.gun.user().create(normalizedUsername, password, () => { });
150800
+ // Aspetta che la creazione si completi
150801
+ setTimeout(() => {
150802
+ // Controlla se l'utente è stato creato
150803
+ const user = this.gun.user();
150804
+ if (user && user.is && user.is.pub) {
150805
+ console.log("✅ [CREATE] User created successfully");
150806
+ resolve({ success: true, userPub: user.is.pub });
150807
+ }
150808
+ else {
150809
+ console.log("❌ [CREATE] User creation failed");
150810
+ resolve({ success: false, error: "User creation failed" });
150811
+ }
150812
+ }, 2000); // Aspetta 2 secondi
150813
+ });
150814
+ }
150815
+ /**
150816
+ * Authenticates user after creation without waiting for acknowledgment
150817
+ */
150818
+ async authenticateNewUserFixed(username, password, pair) {
150819
+ return new Promise((resolve) => {
150820
+ // Validate inputs before authentication
150821
+ if (!username ||
150822
+ typeof username !== "string" ||
150823
+ username.trim().length === 0) {
150824
+ resolve({ success: false, error: "Invalid username provided" });
150825
+ return;
150826
+ }
150827
+ // Skip password validation when using pair authentication
150828
+ if (!pair &&
150829
+ (!password || typeof password !== "string" || password.length === 0)) {
150830
+ resolve({ success: false, error: "Invalid password provided" });
150831
+ return;
150832
+ }
150833
+ // Normalize username to match what was used in creation
150834
+ const normalizedUsername = username.trim().toLowerCase();
150835
+ if (normalizedUsername.length === 0) {
150836
+ resolve({
150837
+ success: false,
150838
+ error: "Username cannot be empty",
150839
+ });
150840
+ return;
150841
+ }
150842
+ console.log(`🔑 [AUTH] Authenticating user: ${normalizedUsername}`);
150843
+ // Autentica senza aspettare acknowledgment
150844
+ if (pair) {
150845
+ this.gun.user().auth(pair);
150846
+ }
150847
+ else {
150848
+ this.gun.user().auth(normalizedUsername, password);
150849
+ }
150850
+ // Aspetta che l'autenticazione si completi
150851
+ setTimeout(() => {
150852
+ const user = this.gun.user();
150853
+ if (user && user.is && user.is.pub) {
150854
+ console.log("✅ [AUTH] Authentication successful");
150855
+ resolve({ success: true, userPub: user.is.pub });
150856
+ }
150857
+ else {
150858
+ console.log("❌ [AUTH] Authentication failed");
150859
+ resolve({ success: false, error: "Authentication failed" });
150860
+ }
150861
+ }, 2000); // Aspetta 2 secondi
150862
+ });
150863
+ }
150750
150864
  async runPostAuthOnAuthResult(username, userPub, authResult) {
150751
150865
  console.log(`[POSTAUTH] Starting post-auth setup for user: ${username}, userPub: ${userPub}`);
150752
150866
  try {
@@ -150782,7 +150896,7 @@ class DataBase {
150782
150896
  }
150783
150897
  console.log(`[POSTAUTH] Normalized username: ${normalizedUsername}`);
150784
150898
  console.log(`[POSTAUTH] Checking if user exists: ${userPub}`);
150785
- const existingUser = await this.gun.get(userPub).then();
150899
+ const existingUser = this.gun.get(userPub);
150786
150900
  const isNewUser = !existingUser || !existingUser.alias;
150787
150901
  console.log(`[POSTAUTH] User is ${isNewUser ? "NEW" : "EXISTING"}: ${userPub}`);
150788
150902
  // Get user's encryption public key (epub) for comprehensive tracking
@@ -150801,8 +150915,10 @@ class DataBase {
150801
150915
  };
150802
150916
  }
150803
150917
  console.log(`[POSTAUTH] User tracking setup completed successfully for: ${normalizedUsername}`);
150804
- // Setup crypto identities for the user
150805
- if (this._cryptoIdentityManager && userSea) {
150918
+ // Setup crypto identities for the user (skip if SKIP_CRYPTO_GENERATION is set)
150919
+ if (this._cryptoIdentityManager &&
150920
+ userSea &&
150921
+ !process.env.SKIP_CRYPTO_GENERATION) {
150806
150922
  console.log(`[POSTAUTH] Setting up crypto identities for: ${normalizedUsername}`);
150807
150923
  try {
150808
150924
  const cryptoSetupResult = await this._cryptoIdentityManager.setupCryptoIdentities(normalizedUsername, userSea, false);
@@ -150820,7 +150936,12 @@ class DataBase {
150820
150936
  }
150821
150937
  }
150822
150938
  else {
150823
- console.log(`ℹ️ [POSTAUTH] Skipping crypto identities setup - manager not available or no SEA pair`);
150939
+ if (process.env.SKIP_CRYPTO_GENERATION) {
150940
+ console.log(`ℹ️ [POSTAUTH] Skipping crypto identities setup - SKIP_CRYPTO_GENERATION is set`);
150941
+ }
150942
+ else {
150943
+ console.log(`ℹ️ [POSTAUTH] Skipping crypto identities setup - manager not available or no SEA pair`);
150944
+ }
150824
150945
  }
150825
150946
  const result = {
150826
150947
  success: true,
@@ -150929,28 +151050,13 @@ class DataBase {
150929
151050
  userPub: userPub,
150930
151051
  createdAt: Date.now(),
150931
151052
  };
150932
- return new Promise((resolve) => {
150933
- // Add timeout to prevent hanging
150934
- const timeout = setTimeout(() => {
150935
- console.error(`Alias index creation timeout for ${username}`);
150936
- resolve(false);
150937
- }, 5000); // 5 second timeout
150938
- // Store alias mapping in a simple way
150939
- this.node
150940
- .get("aliases")
150941
- .get(username)
150942
- .put(aliasData, (ack) => {
150943
- clearTimeout(timeout); // Clear timeout since callback fired
150944
- if (ack && ack.err) {
150945
- console.error(`Error creating alias index: ${ack.err}`);
150946
- resolve(false);
150947
- }
150948
- else {
150949
- console.log(`✓ Alias index created for ${username}`);
150950
- resolve(true);
150951
- }
150952
- });
150953
- });
151053
+ console.log(`🔄 [ALIAS] Creating alias index for ${username}`);
151054
+ // Store alias mapping without waiting for acknowledgment
151055
+ this.node.get("aliases").get(username).put(aliasData);
151056
+ // Aspetta un momento per la scrittura
151057
+ await new Promise((resolve) => setTimeout(resolve, 1000));
151058
+ console.log(`✅ [ALIAS] Alias index created for ${username}`);
151059
+ return true;
150954
151060
  }
150955
151061
  catch (error) {
150956
151062
  console.error(`Error creating alias index: ${error}`);
@@ -150962,20 +151068,13 @@ class DataBase {
150962
151068
  */
150963
151069
  async createUsernameMapping(username, userPub) {
150964
151070
  try {
150965
- return new Promise((resolve) => {
150966
- this.node
150967
- .get("usernames")
150968
- .get(username)
150969
- .put(userPub, (ack) => {
150970
- if (ack && ack.err) {
150971
- console.error(`Error creating username mapping: ${ack.err}`);
150972
- resolve(false);
150973
- }
150974
- else {
150975
- resolve(true);
150976
- }
150977
- });
150978
- });
151071
+ console.log(`🔄 [USERNAME] Creating username mapping for ${username}`);
151072
+ // Store username mapping without waiting for acknowledgment
151073
+ this.node.get("usernames").get(username).put(userPub);
151074
+ // Aspetta un momento per la scrittura
151075
+ await new Promise((resolve) => setTimeout(resolve, 500));
151076
+ console.log(`✅ [USERNAME] Username mapping created for ${username}`);
151077
+ return true;
150979
151078
  }
150980
151079
  catch (error) {
150981
151080
  console.error(`Error creating username mapping: ${error}`);
@@ -150994,20 +151093,13 @@ class DataBase {
150994
151093
  registeredAt: Date.now().toString(),
150995
151094
  lastSeen: Date.now().toString(),
150996
151095
  };
150997
- return new Promise((resolve) => {
150998
- this.node
150999
- .get("users")
151000
- .get(userPub)
151001
- .put(userData, (ack) => {
151002
- if (ack && ack.err) {
151003
- console.error(`Error creating user registry: ${ack.err}`);
151004
- resolve(false);
151005
- }
151006
- else {
151007
- resolve(true);
151008
- }
151009
- });
151010
- });
151096
+ console.log(`🔄 [REGISTRY] Creating user registry for ${username}`);
151097
+ // Store user registry without waiting for acknowledgment
151098
+ this.node.get("users").get(userPub).put(userData);
151099
+ // Aspetta un momento per la scrittura
151100
+ await new Promise((resolve) => setTimeout(resolve, 500));
151101
+ console.log(`✅ [REGISTRY] User registry created for ${username}`);
151102
+ return true;
151011
151103
  }
151012
151104
  catch (error) {
151013
151105
  console.error(`Error creating user registry: ${error}`);
@@ -151019,18 +151111,13 @@ class DataBase {
151019
151111
  */
151020
151112
  async createReverseLookup(username, userPub) {
151021
151113
  try {
151022
- const ack = await this.node
151023
- .get("userAliases")
151024
- .get(userPub)
151025
- .put(username)
151026
- .then();
151027
- if (ack.err) {
151028
- console.error(`Error creating reverse lookup: ${ack.err}`);
151029
- return false;
151030
- }
151031
- else {
151032
- return true;
151033
- }
151114
+ console.log(`🔄 [REVERSE] Creating reverse lookup for ${username}`);
151115
+ // Store reverse lookup without waiting for acknowledgment
151116
+ this.node.get("userAliases").get(userPub).put(username);
151117
+ // Aspetta un momento per la scrittura
151118
+ await new Promise((resolve) => setTimeout(resolve, 500));
151119
+ console.log(`✅ [REVERSE] Reverse lookup created for ${username}`);
151120
+ return true;
151034
151121
  }
151035
151122
  catch (error) {
151036
151123
  console.error(`Error creating reverse lookup: ${error}`);
@@ -151042,20 +151129,13 @@ class DataBase {
151042
151129
  */
151043
151130
  async createEpubIndex(epub, userPub) {
151044
151131
  try {
151045
- return new Promise((resolve) => {
151046
- this.node
151047
- .get("epubKeys")
151048
- .get(epub)
151049
- .put(userPub, (ack) => {
151050
- if (ack && ack.err) {
151051
- console.error(`Error creating epub index: ${ack.err}`);
151052
- resolve(false);
151053
- }
151054
- else {
151055
- resolve(true);
151056
- }
151057
- });
151058
- });
151132
+ console.log(`🔄 [EPUB] Creating epub index for ${userPub}`);
151133
+ // Store epub index without waiting for acknowledgment
151134
+ this.node.get("epubKeys").get(epub).put(userPub);
151135
+ // Aspetta un momento per la scrittura
151136
+ await new Promise((resolve) => setTimeout(resolve, 500));
151137
+ console.log(`✅ [EPUB] Epub index created for ${userPub}`);
151138
+ return true;
151059
151139
  }
151060
151140
  catch (error) {
151061
151141
  console.error(`Error creating epub index: ${error}`);
@@ -151073,17 +151153,13 @@ class DataBase {
151073
151153
  registeredAt: Date.now(),
151074
151154
  lastSeen: Date.now(),
151075
151155
  };
151076
- return new Promise((resolve) => {
151077
- this.gun.get(userPub).put(userMetadata, (ack) => {
151078
- if (ack && ack.err) {
151079
- console.error(`Error creating user metadata: ${ack.err}`);
151080
- resolve(false);
151081
- }
151082
- else {
151083
- resolve(true);
151084
- }
151085
- });
151086
- });
151156
+ console.log(`🔄 [METADATA] Creating user metadata for ${username}`);
151157
+ // Store user metadata without waiting for acknowledgment
151158
+ this.gun.get(userPub).put(userMetadata);
151159
+ // Aspetta un momento per la scrittura
151160
+ await new Promise((resolve) => setTimeout(resolve, 500));
151161
+ console.log(`✅ [METADATA] User metadata created for ${username}`);
151162
+ return true;
151087
151163
  }
151088
151164
  catch (error) {
151089
151165
  console.error(`Error creating user metadata: ${error}`);
@@ -151103,7 +151179,7 @@ class DataBase {
151103
151179
  }
151104
151180
  // Method 1: Try GunDB standard alias lookup (~@alias)
151105
151181
  try {
151106
- const aliasData = await this.gun.get(`~@${normalizedAlias}`).then();
151182
+ const aliasData = this.gun.get(`~@${normalizedAlias}`);
151107
151183
  if (aliasData && aliasData["~pubKeyOfUser"]) {
151108
151184
  const userPub = aliasData["~pubKeyOfUser"]["#"] || aliasData["~pubKeyOfUser"];
151109
151185
  if (userPub) {
@@ -151119,10 +151195,15 @@ class DataBase {
151119
151195
  }
151120
151196
  // Method 2: Try username mapping (usernames/alias -> userPub)
151121
151197
  try {
151122
- const userPub = await this.node
151123
- .get("usernames")
151124
- .get(normalizedAlias)
151125
- .then();
151198
+ const userPubNode = this.node.get("usernames").get(normalizedAlias);
151199
+ // Use once to get the actual value
151200
+ const userPub = await new Promise((resolve) => {
151201
+ const timeout = setTimeout(() => resolve(null), 2000);
151202
+ userPubNode.once((data) => {
151203
+ clearTimeout(timeout);
151204
+ resolve(data);
151205
+ });
151206
+ });
151126
151207
  if (userPub) {
151127
151208
  const userData = await this.getUserDataByPub(userPub);
151128
151209
  if (userData) {
@@ -151152,7 +151233,7 @@ class DataBase {
151152
151233
  }
151153
151234
  // Method 1: Try user registry (users/userPub -> user data)
151154
151235
  try {
151155
- const userData = await this.node.get("users").get(userPub).then();
151236
+ const userData = this.node.get("users").get(userPub);
151156
151237
  if (userData && userData.username) {
151157
151238
  return {
151158
151239
  userPub: userData.userPub || userPub,
@@ -151168,7 +151249,7 @@ class DataBase {
151168
151249
  }
151169
151250
  // Method 2: Try user's own node
151170
151251
  try {
151171
- const userNodeData = await this.gun.get(userPub).then();
151252
+ const userNodeData = this.gun.get(userPub);
151172
151253
  if (userNodeData && userNodeData.username) {
151173
151254
  return {
151174
151255
  userPub: userPub,
@@ -151199,7 +151280,15 @@ class DataBase {
151199
151280
  if (!epub || typeof epub !== "string") {
151200
151281
  return null;
151201
151282
  }
151202
- const userPub = await this.node.get("epubKeys").get(epub).then();
151283
+ const userPubNode = this.node.get("epubKeys").get(epub);
151284
+ // Use once to get the actual value
151285
+ const userPub = await new Promise((resolve) => {
151286
+ const timeout = setTimeout(() => resolve(null), 2000);
151287
+ userPubNode.once((data) => {
151288
+ clearTimeout(timeout);
151289
+ resolve(data);
151290
+ });
151291
+ });
151203
151292
  return userPub || null;
151204
151293
  }
151205
151294
  catch (error) {
@@ -151217,7 +151306,15 @@ class DataBase {
151217
151306
  if (!userPub || typeof userPub !== "string") {
151218
151307
  return null;
151219
151308
  }
151220
- const alias = await this.node.get("userAliases").get(userPub).then();
151309
+ const aliasNode = this.node.get("userAliases").get(userPub);
151310
+ // Use once to get the actual value
151311
+ const alias = await new Promise((resolve) => {
151312
+ const timeout = setTimeout(() => resolve(null), 2000);
151313
+ aliasNode.once((data) => {
151314
+ clearTimeout(timeout);
151315
+ resolve(data);
151316
+ });
151317
+ });
151221
151318
  return alias || null;
151222
151319
  }
151223
151320
  catch (error) {
@@ -151256,19 +151353,14 @@ class DataBase {
151256
151353
  const timestamp = Date.now();
151257
151354
  // Update in user registry
151258
151355
  try {
151259
- await this.node
151260
- .get("users")
151261
- .get(userPub)
151262
- .get("lastSeen")
151263
- .put(timestamp)
151264
- .then();
151356
+ this.node.get("users").get(userPub).get("lastSeen").put(timestamp);
151265
151357
  }
151266
151358
  catch (error) {
151267
151359
  console.error(`Failed to update lastSeen in user registry:`, error);
151268
151360
  }
151269
151361
  // Update in user's own node
151270
151362
  try {
151271
- await this.gun.get(userPub).get("lastSeen").put(timestamp).then();
151363
+ this.gun.get(userPub).get("lastSeen").put(timestamp);
151272
151364
  }
151273
151365
  catch (error) {
151274
151366
  console.error(`Failed to update lastSeen in user node:`, error);
@@ -151279,33 +151371,134 @@ class DataBase {
151279
151371
  }
151280
151372
  }
151281
151373
  /**
151282
- * Performs authentication with Gun
151374
+ * Resets Gun.js authentication state to allow new auth operations
151283
151375
  */
151284
- async performAuthentication(username, password, pair) {
151376
+ resetAuthState() {
151377
+ try {
151378
+ const currentUser = this.gun.user();
151379
+ if (currentUser && currentUser._) {
151380
+ // Reset the authentication flag
151381
+ if (currentUser._.sea) {
151382
+ currentUser._.sea = null;
151383
+ }
151384
+ // Reset the ing flag that prevents concurrent operations
151385
+ if (currentUser._.ing) {
151386
+ currentUser._.ing = false;
151387
+ }
151388
+ // Force clear any pending authentication callbacks
151389
+ if (currentUser._.auth) {
151390
+ currentUser._.auth = null;
151391
+ }
151392
+ // Clear any pending operations
151393
+ if (currentUser._.act) {
151394
+ currentUser._.act = null;
151395
+ }
151396
+ // Clear any pending callbacks
151397
+ if (currentUser._.cb) {
151398
+ currentUser._.cb = null;
151399
+ }
151400
+ // Clear any pending retries
151401
+ if (currentUser._.retries) {
151402
+ currentUser._.retries = 0;
151403
+ }
151404
+ // Clear any pending timeouts
151405
+ if (currentUser._.timeout) {
151406
+ clearTimeout(currentUser._.timeout);
151407
+ currentUser._.timeout = null;
151408
+ }
151409
+ }
151410
+ // Also try to call leave() to ensure clean state
151411
+ try {
151412
+ currentUser.leave();
151413
+ }
151414
+ catch (leaveError) {
151415
+ // Ignore leave errors, just trying to clean up
151416
+ }
151417
+ // Force clear the user reference to ensure clean state
151418
+ this.user = null;
151419
+ console.log("Auth state reset completed");
151420
+ }
151421
+ catch (error) {
151422
+ console.warn("Error resetting auth state:", error);
151423
+ }
151424
+ }
151425
+ /**
151426
+ * Performs authentication with Gun with retry mechanism
151427
+ */
151428
+ async performAuthentication(username, password, pair, retryCount = 0, maxRetries = 3) {
151285
151429
  return new Promise((resolve) => {
151286
- if (pair) {
151287
- this.gun.user().auth(pair, (ack) => {
151288
- if (ack.err) {
151289
- console.error(`Login error for ${username}: ${ack.err}`);
151290
- resolve({ success: false, error: ack.err });
151291
- }
151292
- else {
151293
- resolve({ success: true, ack });
151430
+ // Check if there's already an authentication operation in progress
151431
+ const currentUser = this.gun.user();
151432
+ if (currentUser && currentUser._ && currentUser._.ing) {
151433
+ if (retryCount < maxRetries) {
151434
+ console.warn(`Authentication already in progress, retrying... (${retryCount + 1}/${maxRetries})`);
151435
+ this.resetAuthState();
151436
+ // For the first retry, try to create a fresh authentication context
151437
+ if (retryCount === 0) {
151438
+ this.createFreshAuthContext();
151294
151439
  }
151440
+ // Add exponential backoff delay with jitter
151441
+ const baseDelay = 200 * Math.pow(2, retryCount);
151442
+ const jitter = Math.random() * 200;
151443
+ const delay = Math.min(baseDelay + jitter, 3000);
151444
+ setTimeout(() => {
151445
+ this.performAuthentication(username, password, pair, retryCount + 1, maxRetries)
151446
+ .then(resolve)
151447
+ .catch((error) => resolve({ success: false, error: String(error) }));
151448
+ }, delay);
151449
+ return;
151450
+ }
151451
+ else {
151452
+ console.error("Max retries exceeded for authentication");
151453
+ this.resetAuthState();
151454
+ resolve({
151455
+ success: false,
151456
+ error: "Authentication failed after multiple retries",
151457
+ });
151458
+ return;
151459
+ }
151460
+ }
151461
+ this.performAuthenticationInternal(username, password, pair, resolve);
151462
+ });
151463
+ }
151464
+ /**
151465
+ * Internal authentication method with timeout
151466
+ */
151467
+ performAuthenticationInternal(username, password, pair, resolve) {
151468
+ let resolved = false;
151469
+ const timeout = 30000; // 15 second timeout for individual auth attempts
151470
+ const timeoutId = setTimeout(() => {
151471
+ if (!resolved) {
151472
+ resolved = true;
151473
+ console.error(`Authentication timeout for ${username} after ${timeout}ms`);
151474
+ this.resetAuthState();
151475
+ resolve({
151476
+ success: false,
151477
+ error: `Authentication timeout after ${timeout}ms`,
151295
151478
  });
151296
151479
  }
151480
+ }, timeout);
151481
+ const authCallback = (ack) => {
151482
+ if (resolved)
151483
+ return;
151484
+ resolved = true;
151485
+ clearTimeout(timeoutId);
151486
+ if (ack.err) {
151487
+ console.error(`Login error for ${username}: ${ack.err}`);
151488
+ // Reset auth state on error to prevent blocking future attempts
151489
+ this.resetAuthState();
151490
+ resolve({ success: false, error: ack.err });
151491
+ }
151297
151492
  else {
151298
- this.gun.user().auth(username, password, (ack) => {
151299
- if (ack.err) {
151300
- console.error(`Login error for ${username}: ${ack.err}`);
151301
- resolve({ success: false, error: ack.err });
151302
- }
151303
- else {
151304
- resolve({ success: true, ack });
151305
- }
151306
- });
151493
+ resolve({ success: true, ack });
151307
151494
  }
151308
- });
151495
+ };
151496
+ if (pair) {
151497
+ this.gun.user().auth(pair, authCallback);
151498
+ }
151499
+ else {
151500
+ this.gun.user().auth(username, password, authCallback);
151501
+ }
151309
151502
  }
151310
151503
  /**
151311
151504
  * Builds login result object
@@ -151337,18 +151530,34 @@ class DataBase {
151337
151530
  */
151338
151531
  async login(username, password, pair) {
151339
151532
  try {
151340
- const loginResult = await this.performAuthentication(username, password, pair);
151341
- if (!loginResult.success) {
151533
+ console.log(`🔑 [LOGIN] Attempting login for: ${username}`);
151534
+ // Pulisci lo stato utente esistente
151535
+ this.gun.user().leave();
151536
+ await new Promise((resolve) => setTimeout(resolve, 1000));
151537
+ // Autentica senza aspettare acknowledgment
151538
+ if (pair) {
151539
+ this.gun.user().auth(pair);
151540
+ }
151541
+ else {
151542
+ this.gun.user().auth(username, password);
151543
+ }
151544
+ // Aspetta che l'autenticazione si completi
151545
+ console.log("⏳ [LOGIN] Waiting for authentication to complete...");
151546
+ await new Promise((resolve) => setTimeout(resolve, 3000));
151547
+ // Controlla se l'autenticazione è riuscita
151548
+ const user = this.gun.user();
151549
+ const isAuthenticated = !!user.is;
151550
+ if (!isAuthenticated) {
151551
+ console.log("❌ [LOGIN] Authentication failed");
151342
151552
  return {
151343
151553
  success: false,
151344
151554
  error: `User '${username}' not found. Please check your username or register first.`,
151345
151555
  };
151346
151556
  }
151347
- // Add a small delay to ensure user state is properly set
151348
- await new Promise((resolve) => setTimeout(resolve, 100));
151349
- const userPub = this.gun.user().is?.pub;
151350
- let alias = this.gun.user().is?.alias;
151351
- let userPair = this.gun.user()?._?.sea;
151557
+ console.log("✅ [LOGIN] Authentication successful!");
151558
+ const userPub = user?.is?.pub;
151559
+ let alias = user?.is?.alias;
151560
+ let userPair = user?._?.sea;
151352
151561
  if (!alias) {
151353
151562
  alias = username;
151354
151563
  }
@@ -151358,7 +151567,7 @@ class DataBase {
151358
151567
  error: "Authentication failed: No user pub returned.",
151359
151568
  };
151360
151569
  }
151361
- // Pass the userPub to runPostAuthOnAuthResult
151570
+ // Esegui post-authentication tasks
151362
151571
  try {
151363
151572
  await this.runPostAuthOnAuthResult(alias, userPub, {
151364
151573
  success: true,
@@ -151519,14 +151728,20 @@ class DataBase {
151519
151728
  questions: JSON.stringify(securityQuestions),
151520
151729
  hint: encryptedHint,
151521
151730
  };
151522
- const ack = await this.node.get(userPub)
151523
- .get("security")
151524
- .put(securityPayload)
151525
- .then();
151526
- if (ack.err) {
151731
+ console.log(`💾 [HINT] Saving security data for user: ${username}, pub: ${userPub}`);
151732
+ console.log(`💾 [HINT] Security payload:`, {
151733
+ questions: securityPayload.questions,
151734
+ hintLength: securityPayload.hint?.length || 0,
151735
+ });
151736
+ // Save in PUBLIC space, not user space - accessible without login
151737
+ const ack = this.gun.get("security")
151738
+ .get(userPub)
151739
+ .put(securityPayload);
151740
+ if (ack && ack.err) {
151527
151741
  console.error("Error saving security data to public graph:", ack.err);
151528
151742
  throw new Error(ack.err);
151529
151743
  }
151744
+ console.log(`✅ [HINT] Security data saved successfully for ${username}`);
151530
151745
  return { success: true };
151531
151746
  }
151532
151747
  catch (error) {
@@ -151542,19 +151757,82 @@ class DataBase {
151542
151757
  */
151543
151758
  async forgotPassword(username, securityAnswers) {
151544
151759
  // Attempting password recovery for
151760
+ // Add global timeout for the entire operation
151761
+ return Promise.race([
151762
+ this._forgotPasswordInternal(username, securityAnswers),
151763
+ new Promise((resolve) => {
151764
+ setTimeout(() => {
151765
+ console.log(`⏰ [FORGOT] Global timeout for password recovery: ${username}`);
151766
+ resolve({ success: false, error: "Password recovery timeout" });
151767
+ }, 10000); // 10 second global timeout
151768
+ }),
151769
+ ]);
151770
+ }
151771
+ async _forgotPasswordInternal(username, securityAnswers) {
151545
151772
  try {
151546
151773
  // Find the user's data using direct lookup
151547
151774
  const normalizedUsername = username.trim().toLowerCase();
151548
- const userPub = (await this.node.get("usernames").get(normalizedUsername).then()) ||
151549
- null;
151775
+ // Try multiple lookup methods with fallback
151776
+ let userPub = null;
151777
+ // Method 1: Try username mapping in app scope
151778
+ try {
151779
+ userPub = await new Promise((resolve) => {
151780
+ const timeout = setTimeout(() => {
151781
+ console.log(`⏰ [FORGOT] Timeout looking up user in usernames: ${username}`);
151782
+ resolve(null);
151783
+ }, 2000);
151784
+ this.node
151785
+ .get("usernames")
151786
+ .get(normalizedUsername)
151787
+ .once((data) => {
151788
+ clearTimeout(timeout);
151789
+ console.log(`🔍 [FORGOT] Username lookup result for ${username}:`, data);
151790
+ resolve(data);
151791
+ });
151792
+ });
151793
+ }
151794
+ catch (error) {
151795
+ console.log(`❌ [FORGOT] Username lookup failed: ${error}`);
151796
+ }
151797
+ // Method 2: Try direct user lookup if username mapping fails
151550
151798
  if (!userPub) {
151799
+ console.log(`🔄 [FORGOT] Trying direct user lookup for: ${username}`);
151800
+ try {
151801
+ // Try to find user by searching in the users registry
151802
+ const usersNode = this.node.get("users");
151803
+ // This is a simplified approach - in a real implementation you'd need to iterate
151804
+ // For now, we'll try to get the userPub from the current user if available
151805
+ const currentUser = this.getCurrentUser();
151806
+ if (currentUser && currentUser.pub) {
151807
+ console.log(`🔍 [FORGOT] Using current user pub as fallback: ${currentUser.pub}`);
151808
+ userPub = currentUser.pub;
151809
+ }
151810
+ }
151811
+ catch (error) {
151812
+ console.log(`❌ [FORGOT] Direct user lookup failed: ${error}`);
151813
+ }
151814
+ }
151815
+ if (!userPub) {
151816
+ console.log(`❌ [FORGOT] User not found: ${username}`);
151551
151817
  return { success: false, error: "User not found" };
151552
151818
  }
151553
- // Access the user's security data directly from their public key node
151554
- const securityData = await this.node.get(userPub)
151555
- .get("security")
151556
- .then();
151819
+ // Access the user's security data from PUBLIC space (not user space)
151820
+ const securityDataNode = this.gun.get("security").get(userPub);
151821
+ console.log(`🔍 [FORGOT] Looking for security data for user: ${username}, pub: ${userPub}`);
151822
+ // Use once to get the actual value
151823
+ const securityData = await new Promise((resolve) => {
151824
+ const timeout = setTimeout(() => {
151825
+ console.log(`⏰ [FORGOT] Timeout waiting for security data for ${username} (3s)`);
151826
+ resolve(null);
151827
+ }, 3000); // Reduced timeout to 3 seconds
151828
+ securityDataNode.once((data) => {
151829
+ clearTimeout(timeout);
151830
+ console.log(`📊 [FORGOT] Security data received for ${username}:`, data);
151831
+ resolve(data);
151832
+ });
151833
+ });
151557
151834
  if (!securityData || !securityData.hint) {
151835
+ console.log(`❌ [FORGOT] No security data or hint found for ${username}`);
151558
151836
  return {
151559
151837
  success: false,
151560
151838
  error: "No password hint found",
@@ -151616,6 +151894,107 @@ class DataBase {
151616
151894
  return { success: false, error: String(error) };
151617
151895
  }
151618
151896
  }
151897
+ /**
151898
+ * Recovers password hint using security question answers and userPub directly
151899
+ * @param userPub User's public key
151900
+ * @param securityAnswers Array of answers to security questions
151901
+ * @returns Promise resolving with the password hint
151902
+ */
151903
+ async forgotPasswordByPub(userPub, securityAnswers) {
151904
+ // Add global timeout for the entire operation
151905
+ return Promise.race([
151906
+ this._forgotPasswordByPubInternal(userPub, securityAnswers),
151907
+ new Promise((resolve) => {
151908
+ setTimeout(() => {
151909
+ console.log(`⏰ [FORGOT] Global timeout for password recovery by pub: ${userPub}`);
151910
+ resolve({ success: false, error: "Password recovery timeout" });
151911
+ }, 10000); // 10 second global timeout
151912
+ }),
151913
+ ]);
151914
+ }
151915
+ async _forgotPasswordByPubInternal(userPub, securityAnswers) {
151916
+ try {
151917
+ if (!userPub || typeof userPub !== "string") {
151918
+ return { success: false, error: "Invalid userPub provided" };
151919
+ }
151920
+ // Access the user's security data from PUBLIC space (not user space)
151921
+ const securityDataNode = this.gun.get("security").get(userPub);
151922
+ console.log(`🔍 [FORGOT] Looking for security data for userPub: ${userPub}`);
151923
+ // Use once to get the actual value
151924
+ const securityData = await new Promise((resolve) => {
151925
+ const timeout = setTimeout(() => {
151926
+ console.log(`⏰ [FORGOT] Timeout waiting for security data for userPub: ${userPub} (3s)`);
151927
+ resolve(null);
151928
+ }, 3000);
151929
+ securityDataNode.once((data) => {
151930
+ clearTimeout(timeout);
151931
+ console.log(`📊 [FORGOT] Security data received for userPub: ${userPub}:`, data);
151932
+ resolve(data);
151933
+ });
151934
+ });
151935
+ if (!securityData || !securityData.hint) {
151936
+ console.log(`❌ [FORGOT] No security data or hint found for userPub: ${userPub}`);
151937
+ return {
151938
+ success: false,
151939
+ error: "No password hint found",
151940
+ };
151941
+ }
151942
+ // Generate hash from security answers
151943
+ const answersText = securityAnswers.join("|");
151944
+ let proofOfWork;
151945
+ try {
151946
+ // Use SEA directly if available
151947
+ if (sea_1.default && sea_1.default.work) {
151948
+ proofOfWork = await sea_1.default.work(answersText, null, null, {
151949
+ name: "SHA-256",
151950
+ });
151951
+ }
151952
+ else if (this.crypto && this.crypto.hashText) {
151953
+ proofOfWork = await this.crypto.hashText(answersText);
151954
+ }
151955
+ else {
151956
+ throw new Error("Cryptographic functions not available");
151957
+ }
151958
+ if (!proofOfWork) {
151959
+ throw new Error("Failed to generate hash");
151960
+ }
151961
+ }
151962
+ catch (hashError) {
151963
+ console.error("Error generating hash:", hashError);
151964
+ return { success: false, error: "Failed to generate security hash" };
151965
+ }
151966
+ // Decrypt the password hint with the proof of work
151967
+ let hint;
151968
+ try {
151969
+ if (sea_1.default && sea_1.default.decrypt) {
151970
+ hint = await sea_1.default.decrypt(securityData.hint, proofOfWork);
151971
+ }
151972
+ else if (this.crypto && this.crypto.decrypt) {
151973
+ hint = await this.crypto.decrypt(securityData.hint, proofOfWork);
151974
+ }
151975
+ else {
151976
+ throw new Error("Decryption functions not available");
151977
+ }
151978
+ }
151979
+ catch (decryptError) {
151980
+ return {
151981
+ success: false,
151982
+ error: "Incorrect answers to security questions",
151983
+ };
151984
+ }
151985
+ if (hint === undefined) {
151986
+ return {
151987
+ success: false,
151988
+ error: "Incorrect answers to security questions",
151989
+ };
151990
+ }
151991
+ return { success: true, hint: hint };
151992
+ }
151993
+ catch (error) {
151994
+ console.error("Error recovering password hint by pub:", error);
151995
+ return { success: false, error: String(error) };
151996
+ }
151997
+ }
151619
151998
  /**
151620
151999
  * Adds an event listener
151621
152000
  * @param event Event name
@@ -151760,16 +152139,223 @@ class DataBase {
151760
152139
  isAuthenticated() {
151761
152140
  return this.user?.is?.pub ? true : false;
151762
152141
  }
152142
+ /**
152143
+ * Check if an authentication operation is currently in progress
152144
+ */
152145
+ isAuthInProgress() {
152146
+ try {
152147
+ const currentUser = this.gun.user();
152148
+ return !!(currentUser && currentUser._ && currentUser._.ing);
152149
+ }
152150
+ catch (error) {
152151
+ console.warn("Error checking auth progress:", error);
152152
+ return false;
152153
+ }
152154
+ }
152155
+ /**
152156
+ * Force reset authentication state (useful for debugging or recovery)
152157
+ */
152158
+ forceResetAuthState() {
152159
+ this.resetAuthState();
152160
+ }
152161
+ /**
152162
+ * Aggressive cleanup for problematic users
152163
+ * This method performs a complete reset of all authentication state
152164
+ */
152165
+ aggressiveAuthCleanup() {
152166
+ try {
152167
+ console.log("🧹 Performing aggressive auth cleanup...");
152168
+ // Reset all auth state
152169
+ this.resetAuthState();
152170
+ // Clear all Gun.js internal state
152171
+ const currentUser = this.gun.user();
152172
+ if (currentUser && currentUser._) {
152173
+ // Clear all possible internal flags
152174
+ const internalState = currentUser._;
152175
+ Object.keys(internalState).forEach((key) => {
152176
+ if (typeof internalState[key] === "boolean") {
152177
+ internalState[key] = false;
152178
+ }
152179
+ else if (typeof internalState[key] === "object" &&
152180
+ internalState[key] !== null) {
152181
+ if (key === "sea" ||
152182
+ key === "auth" ||
152183
+ key === "act" ||
152184
+ key === "cb") {
152185
+ internalState[key] = null;
152186
+ }
152187
+ }
152188
+ });
152189
+ }
152190
+ // Force logout
152191
+ try {
152192
+ currentUser.leave();
152193
+ }
152194
+ catch (error) {
152195
+ // Ignore errors
152196
+ }
152197
+ // Clear user reference
152198
+ this.user = null;
152199
+ // Clear all session storage
152200
+ if (typeof sessionStorage !== "undefined") {
152201
+ try {
152202
+ const keys = Object.keys(sessionStorage);
152203
+ keys.forEach((key) => {
152204
+ if (key.includes("gun") ||
152205
+ key.includes("user") ||
152206
+ key.includes("auth")) {
152207
+ sessionStorage.removeItem(key);
152208
+ }
152209
+ });
152210
+ }
152211
+ catch (error) {
152212
+ // Ignore errors
152213
+ }
152214
+ }
152215
+ // Clear all local storage
152216
+ if (typeof localStorage !== "undefined") {
152217
+ try {
152218
+ const keys = Object.keys(localStorage);
152219
+ keys.forEach((key) => {
152220
+ if (key.includes("gun") ||
152221
+ key.includes("user") ||
152222
+ key.includes("auth")) {
152223
+ localStorage.removeItem(key);
152224
+ }
152225
+ });
152226
+ }
152227
+ catch (error) {
152228
+ // Ignore errors
152229
+ }
152230
+ }
152231
+ console.log("✓ Aggressive auth cleanup completed");
152232
+ }
152233
+ catch (error) {
152234
+ console.error("Error during aggressive cleanup:", error);
152235
+ }
152236
+ }
152237
+ /**
152238
+ * Creates a completely fresh authentication context
152239
+ * This is a more aggressive approach when normal reset doesn't work
152240
+ */
152241
+ createFreshAuthContext() {
152242
+ try {
152243
+ // Reset all auth state
152244
+ this.resetAuthState();
152245
+ // Create a completely new user instance
152246
+ const freshUser = this.gun.user();
152247
+ this.user = freshUser;
152248
+ // Clear any cached authentication data
152249
+ if (typeof sessionStorage !== "undefined") {
152250
+ try {
152251
+ sessionStorage.removeItem("gunSessionData");
152252
+ sessionStorage.removeItem("gunUserData");
152253
+ }
152254
+ catch (error) {
152255
+ console.warn("Error clearing session storage:", error);
152256
+ }
152257
+ }
152258
+ console.log("Fresh authentication context created");
152259
+ }
152260
+ catch (error) {
152261
+ console.error("Error creating fresh auth context:", error);
152262
+ }
152263
+ }
152264
+ /**
152265
+ * Setup cleanup handlers for memory leak prevention
152266
+ */
152267
+ setupCleanupHandlers() {
152268
+ // Handle process cleanup
152269
+ if (typeof process !== "undefined") {
152270
+ process.on("SIGINT", () => this.destroy());
152271
+ process.on("SIGTERM", () => this.destroy());
152272
+ process.on("exit", () => this.destroy());
152273
+ }
152274
+ }
152275
+ /**
152276
+ * Safe interval wrapper that tracks intervals for cleanup
152277
+ */
152278
+ safeInterval(callback, delay) {
152279
+ if (this._isDestroyed) {
152280
+ return setInterval(() => { }, 0);
152281
+ }
152282
+ const interval = setInterval(() => {
152283
+ if (!this._isDestroyed) {
152284
+ callback();
152285
+ }
152286
+ }, delay);
152287
+ this._activeIntervals.add(interval);
152288
+ return interval;
152289
+ }
152290
+ /**
152291
+ * Clear a specific timeout
152292
+ */
152293
+ clearSafeTimeout(timeout) {
152294
+ clearTimeout(timeout);
152295
+ this._activeTimeouts.delete(timeout);
152296
+ }
152297
+ /**
152298
+ * Clear a specific interval
152299
+ */
152300
+ clearSafeInterval(interval) {
152301
+ clearInterval(interval);
152302
+ this._activeIntervals.delete(interval);
152303
+ }
152304
+ /**
152305
+ * Destroy the database instance and clean up all resources
152306
+ */
152307
+ destroy() {
152308
+ if (this._isDestroyed) {
152309
+ return;
152310
+ }
152311
+ console.log("[DB] Destroying DataBase instance...");
152312
+ this._isDestroyed = true;
152313
+ // Clear all timeouts
152314
+ this._activeTimeouts.forEach((timeout) => {
152315
+ clearTimeout(timeout);
152316
+ });
152317
+ this._activeTimeouts.clear();
152318
+ // Clear all intervals
152319
+ this._activeIntervals.forEach((interval) => {
152320
+ clearInterval(interval);
152321
+ });
152322
+ this._activeIntervals.clear();
152323
+ // Clear event listeners
152324
+ this.eventEmitter.removeAllListeners();
152325
+ // Clear auth callbacks
152326
+ this.onAuthCallbacks.length = 0;
152327
+ // Clear Gun user
152328
+ if (this.user) {
152329
+ try {
152330
+ this.user.leave();
152331
+ }
152332
+ catch (error) {
152333
+ console.warn("Error during user leave:", error);
152334
+ }
152335
+ this.user = null;
152336
+ }
152337
+ // Clear Gun instance references
152338
+ if (this.gun) {
152339
+ try {
152340
+ // Clear any Gun event listeners if available
152341
+ if (typeof this.gun.off === "function") {
152342
+ this.gun.off();
152343
+ }
152344
+ }
152345
+ catch (error) {
152346
+ console.warn("Error clearing Gun listeners:", error);
152347
+ }
152348
+ }
152349
+ // Clear other references
152350
+ this._rxjs = undefined;
152351
+ this._cryptoIdentityManager = undefined;
152352
+ this.core = undefined;
152353
+ console.log("[DB] DataBase instance destroyed");
152354
+ }
151763
152355
  }
151764
152356
  exports.DataBase = DataBase;
151765
152357
  // Errors
151766
152358
  DataBase.Errors = GunErrors;
151767
- const createGun = (config) => {
151768
- const gunInstance = (0, gun_1.default)(config);
151769
- return gunInstance;
151770
- };
151771
- exports.createGun = createGun;
151772
- exports["default"] = gun_1.default;
151773
152359
 
151774
152360
 
151775
152361
  /***/ }),
@@ -152654,10 +153240,10 @@ Object.defineProperty(exports, "quickStart", ({ enumerable: true, get: function
152654
153240
  Object.defineProperty(exports, "createSimpleAPI", ({ enumerable: true, get: function () { return gundb_1.createSimpleAPI; } }));
152655
153241
  Object.defineProperty(exports, "AutoQuickStart", ({ enumerable: true, get: function () { return gundb_1.AutoQuickStart; } }));
152656
153242
  Object.defineProperty(exports, "autoQuickStart", ({ enumerable: true, get: function () { return gundb_1.autoQuickStart; } }));
152657
- const db_2 = __webpack_require__(/*! ./gundb/db */ "./src/gundb/db.ts");
152658
- Object.defineProperty(exports, "SEA", ({ enumerable: true, get: function () { return db_2.SEA; } }));
152659
- const db_3 = __importDefault(__webpack_require__(/*! ./gundb/db */ "./src/gundb/db.ts"));
152660
- exports.Gun = db_3.default;
153243
+ const gun_1 = __importDefault(__webpack_require__(/*! gun */ "./node_modules/gun/gun.js"));
153244
+ exports.Gun = gun_1.default;
153245
+ const sea_1 = __importDefault(__webpack_require__(/*! gun/sea */ "./node_modules/gun/sea.js"));
153246
+ exports.SEA = sea_1.default;
152661
153247
  __exportStar(__webpack_require__(/*! ./utils/errorHandler */ "./src/utils/errorHandler.ts"), exports);
152662
153248
  __exportStar(__webpack_require__(/*! ./plugins */ "./src/plugins/index.ts"), exports);
152663
153249
  __exportStar(__webpack_require__(/*! ./interfaces/shogun */ "./src/interfaces/shogun.ts"), exports);
@@ -153086,38 +153672,43 @@ class CoreInitializer {
153086
153672
  /**
153087
153673
  * Initialize Gun instance
153088
153674
  */
153089
- // Sì, è corretto.
153090
153675
  initializeGun(config) {
153091
153676
  try {
153092
- if (config.gunInstance) {
153093
- console.log("Using existing Gun instance:", config.gunInstance);
153094
- this.core._gun = config.gunInstance;
153677
+ if (!config.gunInstance) {
153678
+ throw new Error("Gun instance is required but was not provided");
153095
153679
  }
153096
- else if (config.gunOptions && config.gunInstance === undefined) {
153097
- console.log("Creating Gun instance with config:", config.gunOptions);
153098
- this.core._gun = (0, gundb_1.createGun)(config.gunOptions);
153680
+ // Validate Gun instance
153681
+ if (typeof config.gunInstance !== "object") {
153682
+ throw new Error(`Gun instance must be an object, received: ${typeof config.gunInstance}`);
153099
153683
  }
153100
- else if (config.gunInstance && config.gunOptions) {
153101
- throw new Error("Gun instance and gun options cannot be provided together");
153102
- // removed by dead control flow
153103
-
153684
+ if (typeof config.gunInstance.user !== "function") {
153685
+ throw new Error(`Gun instance is invalid: gun.user is not a function. Received gun.user type: ${typeof config.gunInstance.user}`);
153104
153686
  }
153687
+ if (typeof config.gunInstance.get !== "function") {
153688
+ throw new Error(`Gun instance is invalid: gun.get is not a function. Received gun.get type: ${typeof config.gunInstance.get}`);
153689
+ }
153690
+ if (typeof config.gunInstance.on !== "function") {
153691
+ throw new Error(`Gun instance is invalid: gun.on is not a function. Received gun.on type: ${typeof config.gunInstance.on}`);
153692
+ }
153693
+ console.log("Using provided Gun instance:", config.gunInstance);
153694
+ this.core._gun = config.gunInstance;
153105
153695
  }
153106
153696
  catch (error) {
153107
153697
  if (typeof console !== "undefined" && console.error) {
153108
- console.error("Error creating Gun instance:", error);
153698
+ console.error("Error validating Gun instance:", error);
153109
153699
  }
153110
- return false;
153700
+ throw new Error(`Failed to validate Gun instance: ${error}`);
153111
153701
  }
153112
153702
  try {
153113
- this.core.db = new gundb_1.DataBase(this.core._gun, config.gunOptions?.scope || "", this.core);
153703
+ this.core.db = new gundb_1.DataBase(this.core._gun, "shogun", // Default app scope
153704
+ this.core);
153114
153705
  return true;
153115
153706
  }
153116
153707
  catch (error) {
153117
153708
  if (typeof console !== "undefined" && console.error) {
153118
- console.error("Error initializing GunInstance:", error);
153709
+ console.error("Error initializing DataBase:", error);
153119
153710
  }
153120
- throw new Error(`Failed to initialize GunInstance: ${error}`);
153711
+ throw new Error(`Failed to initialize DataBase: ${error}`);
153121
153712
  }
153122
153713
  }
153123
153714
  /**
@@ -153286,8 +153877,9 @@ const errorHandler_1 = __webpack_require__(/*! ../utils/errorHandler */ "./src/u
153286
153877
  * Genera automaticamente tutte le identità crypto disponibili dopo l'autenticazione SEA
153287
153878
  */
153288
153879
  class CryptoIdentityManager {
153289
- constructor(core) {
153880
+ constructor(core, db) {
153290
153881
  this.core = core;
153882
+ this.db = db || core.db; // Use core.db if db not provided
153291
153883
  this.pgpManager = new pgp_1.PGPManager();
153292
153884
  this.mlsManager = new mls_1.MLSManager("default-user");
153293
153885
  this.sframeManager = new sframe_1.SFrameManager();
@@ -153374,6 +153966,11 @@ class CryptoIdentityManager {
153374
153966
  console.error(`❌ [${username}] SFrame key generation failed:`, error);
153375
153967
  }
153376
153968
  console.log(`✅ [CryptoIdentityManager] All crypto identities generated for: ${username}`);
153969
+ // Force garbage collection after generation
153970
+ if (typeof __webpack_require__.g !== "undefined" && __webpack_require__.g.gc) {
153971
+ __webpack_require__.g.gc();
153972
+ console.log(`🧹 [${username}] Forced garbage collection after identity generation`);
153973
+ }
153377
153974
  return {
153378
153975
  success: true,
153379
153976
  identities,
@@ -153409,41 +154006,76 @@ class CryptoIdentityManager {
153409
154006
  }
153410
154007
  // Salva su GunDB nel percorso privato dell'utente
153411
154008
  const saveResult = await new Promise((resolve, reject) => {
153412
- this.core.gun
153413
- .user()
153414
- .get("crypto-identities")
153415
- .put(encryptedIdentities, (ack) => {
153416
- if (ack.err) {
153417
- console.error(`❌ [${username}] Failed to save identities:`, ack.err);
153418
- reject(new Error(ack.err));
153419
- }
153420
- else {
153421
- console.log(`✅ [${username}] Crypto identities saved successfully`);
153422
- savedKeys.push("crypto-identities");
153423
- resolve(true);
153424
- }
153425
- });
154009
+ const timeout = setTimeout(() => {
154010
+ console.warn(`⚠️ [${username}] Save identities timeout after 5 seconds, continuing anyway`);
154011
+ savedKeys.push("crypto-identities");
154012
+ resolve(true); // Resolve anyway to not block the process
154013
+ }, 5000); // 5 second timeout
154014
+ try {
154015
+ this.db.gun
154016
+ .user()
154017
+ .get("crypto-identities")
154018
+ .put(encryptedIdentities, (ack) => {
154019
+ clearTimeout(timeout);
154020
+ if (ack && ack.err) {
154021
+ console.error(`❌ [${username}] Failed to save identities:`, ack.err);
154022
+ reject(new Error(ack.err));
154023
+ }
154024
+ else {
154025
+ console.log(`✅ [${username}] Crypto identities saved successfully`);
154026
+ savedKeys.push("crypto-identities");
154027
+ resolve(true);
154028
+ }
154029
+ });
154030
+ }
154031
+ catch (putError) {
154032
+ clearTimeout(timeout);
154033
+ console.error(`❌ [${username}] Error during put operation:`, putError);
154034
+ // Don't reject, just resolve to not block - Gun might save eventually
154035
+ savedKeys.push("crypto-identities");
154036
+ resolve(true);
154037
+ }
153426
154038
  });
153427
154039
  // Salva anche una copia di backup nel percorso pubblico (solo hash per verifica)
153428
154040
  const identitiesHash = await sea_1.default.work(identitiesJson, null, null, {
153429
154041
  name: "SHA-256",
153430
154042
  });
153431
154043
  await new Promise((resolve, reject) => {
153432
- this.core.gun
153433
- .user()
153434
- .get("crypto-identities-hash")
153435
- .put(identitiesHash, (ack) => {
153436
- if (ack.err) {
153437
- console.error(`❌ [${username}] Failed to save identities hash:`, ack.err);
153438
- reject(new Error(ack.err));
153439
- }
153440
- else {
153441
- console.log(`✅ [${username}] Crypto identities hash saved`);
153442
- savedKeys.push("crypto-identities-hash");
153443
- resolve(true);
153444
- }
153445
- });
154044
+ const timeout = setTimeout(() => {
154045
+ console.warn(`⚠️ [${username}] Save identities hash timeout after 5 seconds, continuing anyway`);
154046
+ savedKeys.push("crypto-identities-hash");
154047
+ resolve(true); // Resolve anyway to not block the process
154048
+ }, 5000); // 5 second timeout
154049
+ try {
154050
+ this.db.gun
154051
+ .user()
154052
+ .get("crypto-identities-hash")
154053
+ .put(identitiesHash, (ack) => {
154054
+ clearTimeout(timeout);
154055
+ if (ack && ack.err) {
154056
+ console.error(`❌ [${username}] Failed to save identities hash:`, ack.err);
154057
+ reject(new Error(ack.err));
154058
+ }
154059
+ else {
154060
+ console.log(`✅ [${username}] Crypto identities hash saved`);
154061
+ savedKeys.push("crypto-identities-hash");
154062
+ resolve(true);
154063
+ }
154064
+ });
154065
+ }
154066
+ catch (putError) {
154067
+ clearTimeout(timeout);
154068
+ console.error(`❌ [${username}] Error during hash put operation:`, putError);
154069
+ // Don't reject, just resolve to not block - Gun might save eventually
154070
+ savedKeys.push("crypto-identities-hash");
154071
+ resolve(true);
154072
+ }
153446
154073
  });
154074
+ // Force garbage collection after saving
154075
+ if (typeof __webpack_require__.g !== "undefined" && __webpack_require__.g.gc) {
154076
+ __webpack_require__.g.gc();
154077
+ console.log(`🧹 [${username}] Forced garbage collection after saving identities`);
154078
+ }
153447
154079
  return {
153448
154080
  success: true,
153449
154081
  savedKeys,
@@ -153470,7 +154102,7 @@ class CryptoIdentityManager {
153470
154102
  console.log(`🔍 [CryptoIdentityManager] Retrieving crypto identities for: ${username}`);
153471
154103
  // Recupera le identità criptate da GunDB
153472
154104
  const encryptedIdentities = await new Promise((resolve, reject) => {
153473
- this.core.gun
154105
+ this.db.gun
153474
154106
  .user()
153475
154107
  .get("crypto-identities")
153476
154108
  .once((data) => {
@@ -153522,7 +154154,7 @@ class CryptoIdentityManager {
153522
154154
  async hasStoredIdentities(username) {
153523
154155
  try {
153524
154156
  const hasIdentities = await new Promise((resolve) => {
153525
- this.core.gun
154157
+ this.db.gun
153526
154158
  .user()
153527
154159
  .get("crypto-identities")
153528
154160
  .once((data) => {
@@ -153609,7 +154241,13 @@ class CryptoIdentityManager {
153609
154241
  };
153610
154242
  }
153611
154243
  // Ottieni il SEA pair dell'utente corrente
153612
- const userInstance = this.core.gun.user();
154244
+ if (!this.db || !this.db.gun) {
154245
+ return {
154246
+ success: false,
154247
+ error: "Database not available",
154248
+ };
154249
+ }
154250
+ const userInstance = this.db.gun.user();
153613
154251
  const seaPair = userInstance?._?.sea;
153614
154252
  if (!seaPair) {
153615
154253
  return {
@@ -158640,7 +159278,10 @@ class ZkCredentials {
158640
159278
  const externalNullifier = BigInt(ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(credentialData.type)));
158641
159279
  // Generate ZK proof
158642
159280
  // Note: This requires circuit files to be available
158643
- const fullProof = await (0, proof_1.generateProof)(identity, group, signalBigInt, externalNullifier);
159281
+ const fullProof = await (0, proof_1.generateProof)(identity, group, signalBigInt, externalNullifier, {
159282
+ wasmFilePath: "./circuits/semaphore/20/semaphore.wasm",
159283
+ zkeyFilePath: "./circuits/semaphore/20/semaphore.zkey",
159284
+ });
158644
159285
  return {
158645
159286
  type: credentialData.type,
158646
159287
  claim: credentialData.claim,