edmaxlabs-core 2.4.9 → 2.5.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.
package/dist/index.d.cts CHANGED
@@ -53,23 +53,25 @@ declare class Credentials {
53
53
  toMap(): Record<string, any>;
54
54
  }
55
55
 
56
- type Listener<T = any> = (value: T) => void;
57
56
  declare class Authentication {
58
57
  static instance: Authentication | null;
59
- private eUser?;
60
- private client?;
61
- private app?;
58
+ private eUser;
59
+ private client;
60
+ private app;
62
61
  private eventListeners;
63
- private eventWaiters;
64
- private unsubscribers;
62
+ private isHandlingChange;
65
63
  constructor();
66
- private isSameCredentials;
67
- private restoreSession;
68
64
  static getInstance(): Authentication;
69
- emitValue<T>(key: string, value: T): void;
70
- onValue<T>(key: string, callback: Listener<T>): () => void;
65
+ private emitValue;
66
+ private onValue;
71
67
  currentUser(): Credentials | null;
72
68
  private saveCredentials;
69
+ private isSameCredentials;
70
+ private restoreSession;
71
+ /**
72
+ * Main method to listen to authentication state changes.
73
+ * This listener stays alive for the entire app lifetime.
74
+ */
73
75
  authState({ onChange, onSignOut, onDeleted, }: {
74
76
  onChange: (user: Credentials) => void;
75
77
  onSignOut?: () => void;
@@ -83,8 +85,8 @@ declare class Authentication {
83
85
  email: string;
84
86
  password: string;
85
87
  }) => Promise<Credentials | null>;
86
- deleteUser: () => Promise<void>;
87
88
  signOut: () => Promise<void>;
89
+ deleteUser: () => Promise<void>;
88
90
  rules: (path: string, context: Record<string, any>) => Promise<{
89
91
  success: boolean;
90
92
  allowed: any;
package/dist/index.d.ts CHANGED
@@ -53,23 +53,25 @@ declare class Credentials {
53
53
  toMap(): Record<string, any>;
54
54
  }
55
55
 
56
- type Listener<T = any> = (value: T) => void;
57
56
  declare class Authentication {
58
57
  static instance: Authentication | null;
59
- private eUser?;
60
- private client?;
61
- private app?;
58
+ private eUser;
59
+ private client;
60
+ private app;
62
61
  private eventListeners;
63
- private eventWaiters;
64
- private unsubscribers;
62
+ private isHandlingChange;
65
63
  constructor();
66
- private isSameCredentials;
67
- private restoreSession;
68
64
  static getInstance(): Authentication;
69
- emitValue<T>(key: string, value: T): void;
70
- onValue<T>(key: string, callback: Listener<T>): () => void;
65
+ private emitValue;
66
+ private onValue;
71
67
  currentUser(): Credentials | null;
72
68
  private saveCredentials;
69
+ private isSameCredentials;
70
+ private restoreSession;
71
+ /**
72
+ * Main method to listen to authentication state changes.
73
+ * This listener stays alive for the entire app lifetime.
74
+ */
73
75
  authState({ onChange, onSignOut, onDeleted, }: {
74
76
  onChange: (user: Credentials) => void;
75
77
  onSignOut?: () => void;
@@ -83,8 +85,8 @@ declare class Authentication {
83
85
  email: string;
84
86
  password: string;
85
87
  }) => Promise<Credentials | null>;
86
- deleteUser: () => Promise<void>;
87
88
  signOut: () => Promise<void>;
89
+ deleteUser: () => Promise<void>;
88
90
  rules: (path: string, context: Record<string, any>) => Promise<{
89
91
  success: boolean;
90
92
  allowed: any;
package/dist/index.mjs CHANGED
@@ -97,116 +97,91 @@ var HttpsRequest = class {
97
97
 
98
98
  // src/authentication/Authentication.ts
99
99
  var _Authentication = class _Authentication {
100
+ // Re-entrancy guard
100
101
  constructor() {
102
+ this.eUser = null;
103
+ this.client = null;
104
+ this.app = null;
105
+ // Dedicated lightweight instance for auth
101
106
  this.eventListeners = /* @__PURE__ */ new Map();
102
- this.eventWaiters = /* @__PURE__ */ new Map();
103
- this.unsubscribers = /* @__PURE__ */ new Set();
104
- this.isSameCredentials = (a, b) => {
105
- if (!a && !b)
106
- return true;
107
- if (!a || !b)
108
- return false;
109
- return JSON.stringify(a.toMap()) === JSON.stringify(b.toMap());
110
- };
107
+ this.isHandlingChange = false;
108
+ // ====================== AUTH METHODS ======================
111
109
  this.createUserWithEmailAndPassword = async ({
112
110
  email,
113
111
  password
114
112
  }) => {
115
- this.eUser = void 0;
116
113
  this.saveCredentials(null);
117
- const app = this.app?.getDatabase;
118
- const data = await app?.collection("users").query.where({
119
- key: "email",
120
- op: "===",
121
- value: email
122
- }).get();
123
- if (data.length > 0) {
114
+ const app = this.app.getDatabase;
115
+ const existing = await app.collection("users").query.where({ key: "email", op: "===", value: email }).get();
116
+ if (existing.length > 0) {
124
117
  throw new Error("Email Already In Use.");
125
118
  }
126
- const userRef = await app?.collection("users").add({
119
+ const userRef = await app.collection("users").add({
127
120
  email,
128
121
  password,
129
- token: this.client?.getConfig().token,
122
+ token: this.client.getConfig().token,
130
123
  logged: true,
131
124
  lastLogged: Date.now()
132
125
  });
133
- if (!userRef?.id || userRef?.id === "") {
134
- throw new Error("Something went wrong try Again.");
126
+ if (!userRef?.id) {
127
+ throw new Error("Something went wrong. Please try again.");
135
128
  }
136
- this.eUser = Credentials.fromMap(userRef);
137
- this.saveCredentials(this.eUser);
138
- return Credentials.fromMap(userRef.toMap());
129
+ const newCreds = Credentials.fromMap(userRef.toMap());
130
+ this.saveCredentials(newCreds);
131
+ return newCreds;
139
132
  };
140
133
  this.signInWithEmailAndPassword = async ({
141
134
  email,
142
135
  password
143
136
  }) => {
144
- const app = this.app?.getDatabase;
145
- const data = await app?.collection("users").query.where({
146
- key: "email",
147
- op: "===",
148
- value: email
149
- }).where({
150
- key: "password",
151
- op: "===",
152
- value: password
153
- }).get();
154
- if (data === void 0) {
155
- throw new Error("Auth Failed.");
156
- }
157
- if (data?.length === 0) {
137
+ const app = this.app.getDatabase;
138
+ const data = await app.collection("users").query.where({ key: "email", op: "===", value: email }).where({ key: "password", op: "===", value: password }).get();
139
+ if (!data || data.length === 0) {
158
140
  throw new Error("User Not Found.");
159
141
  }
160
- const _data = data[0];
161
- await app?.collection("users").doc(data[0].id).update({
142
+ const userDoc = data[0];
143
+ await app.collection("users").doc(userDoc.id).update({
162
144
  logged: true,
163
145
  lastLogged: Date.now()
164
146
  });
165
- this.eUser = Credentials.fromMap(_data);
166
- this.saveCredentials(this.eUser);
167
- return Credentials.fromMap(data[0].toMap());
147
+ const signedInUser = Credentials.fromMap(userDoc.toMap());
148
+ this.saveCredentials(signedInUser);
149
+ return signedInUser;
168
150
  };
169
- this.deleteUser = async () => {
170
- if (!this.eUser) {
171
- throw new Error("No User Signed in");
172
- }
173
- const app = this.app?.getDatabase;
174
- const userRef = await app?.collection("users").doc(this.eUser.uid).delete();
175
- if (userRef) {
176
- throw new Error("Something went wrong try Again.");
177
- }
178
- this.eUser = void 0;
151
+ this.signOut = async () => {
152
+ const current = this.currentUser();
153
+ if (!current)
154
+ return;
155
+ const app = this.app.getDatabase;
156
+ await app.collection("users").doc(current.uid).update({
157
+ logged: false,
158
+ lastLogged: Date.now()
159
+ });
179
160
  this.saveCredentials(null);
180
161
  };
181
- this.signOut = async () => {
182
- const app = this.app?.getDatabase;
183
- const luid = this.currentUser();
184
- this.eUser = void 0;
162
+ this.deleteUser = async () => {
163
+ if (!this.eUser)
164
+ throw new Error("No User Signed in");
165
+ const app = this.app.getDatabase;
166
+ await app.collection("users").doc(this.eUser.uid).delete();
185
167
  this.saveCredentials(null);
186
- if (luid)
187
- await app?.collection("users").doc(luid?.uid).update({
188
- logged: false,
189
- lastLogged: Date.now()
190
- });
191
- return;
192
168
  };
169
+ // Optional: Rules verification
193
170
  this.rules = async (path, context) => {
194
171
  const res = await new HttpsRequest({
195
172
  method: "POST" /* POST */,
196
- endpoint: this.client.getBaseUrl() + "/auth/rules/verify",
173
+ endpoint: `${this.client.getBaseUrl()}/auth/rules/verify`,
197
174
  headers: {
198
175
  authorization: this.client.getConfig().token,
199
176
  project: this.client.getConfig().project
200
177
  },
201
- body: {
202
- path,
203
- context
204
- }
178
+ body: { path, context }
205
179
  }).sendRequest();
206
180
  return res;
207
181
  };
208
- if (_Authentication.instance)
182
+ if (_Authentication.instance) {
209
183
  return _Authentication.instance;
184
+ }
210
185
  this.client = EdmaxLabs.instance;
211
186
  this.app = new EdmaxLabs({
212
187
  token: "auth",
@@ -215,26 +190,16 @@ var _Authentication = class _Authentication {
215
190
  _Authentication.instance = this;
216
191
  this.restoreSession();
217
192
  }
218
- restoreSession() {
219
- const saved = this.currentUser();
220
- if (saved) {
221
- this.eUser = saved;
222
- this.emitValue("creds", saved);
223
- }
224
- }
225
- // Better singleton
226
193
  static getInstance() {
227
194
  if (!_Authentication.instance) {
228
195
  _Authentication.instance = new _Authentication();
229
196
  }
230
197
  return _Authentication.instance;
231
198
  }
199
+ // ====================== EVENT SYSTEM ======================
232
200
  emitValue(key, value) {
233
201
  const listeners = this.eventListeners.get(key) || [];
234
- listeners.forEach((l) => l(value));
235
- const waiters = this.eventWaiters.get(key) || [];
236
- waiters.forEach((resolve) => resolve(value));
237
- this.eventWaiters.delete(key);
202
+ [...listeners].forEach((listener) => listener(value));
238
203
  }
239
204
  onValue(key, callback) {
240
205
  const listeners = this.eventListeners.get(key) || [];
@@ -245,6 +210,7 @@ var _Authentication = class _Authentication {
245
210
  this.eventListeners.set(key, filtered);
246
211
  };
247
212
  }
213
+ // ====================== CREDENTIALS ======================
248
214
  currentUser() {
249
215
  const data = localStorage.getItem("eauth");
250
216
  if (!data)
@@ -267,49 +233,71 @@ var _Authentication = class _Authentication {
267
233
  this.eUser = credentials;
268
234
  this.emitValue("creds", credentials);
269
235
  }
270
- // Main auth state listener - should be called ONCE at app root
236
+ isSameCredentials(a, b) {
237
+ if (!a && !b)
238
+ return true;
239
+ if (!a || !b)
240
+ return false;
241
+ return a.uid === b.uid && a.displayInfo.email === b.displayInfo.email && a.lastLogged === b.lastLogged;
242
+ }
243
+ restoreSession() {
244
+ const saved = this.currentUser();
245
+ if (saved) {
246
+ this.eUser = saved;
247
+ }
248
+ }
249
+ // ====================== MAIN AUTH STATE LISTENER ======================
250
+ /**
251
+ * Main method to listen to authentication state changes.
252
+ * This listener stays alive for the entire app lifetime.
253
+ */
271
254
  authState({
272
255
  onChange,
273
256
  onSignOut,
274
257
  onDeleted
275
258
  }) {
276
259
  let userDocUnsubscribe;
260
+ let credsUnsub;
277
261
  const handleCredsChange = (creds) => {
278
- if (userDocUnsubscribe) {
279
- userDocUnsubscribe();
280
- userDocUnsubscribe = void 0;
281
- }
262
+ if (this.isHandlingChange)
263
+ return;
264
+ this.isHandlingChange = true;
265
+ userDocUnsubscribe?.();
266
+ userDocUnsubscribe = void 0;
282
267
  if (!creds) {
283
268
  this.eUser = null;
284
269
  onSignOut?.();
270
+ this.isHandlingChange = false;
285
271
  return;
286
272
  }
287
- const userRef = this.app?.getDatabase.collection("users").doc(creds.uid);
288
- if (!userRef)
289
- return;
273
+ const userRef = this.app.getDatabase.collection("users").doc(creds.uid);
290
274
  userDocUnsubscribe = userRef.onSnapshot(
291
275
  (snapshot, change) => {
292
276
  if (change === "delete") {
293
277
  this.saveCredentials(null);
294
278
  onSignOut?.();
295
279
  onDeleted?.();
280
+ this.isHandlingChange = false;
296
281
  return;
297
282
  }
298
283
  if (change === "insert" || change === "update") {
299
- if (!snapshot)
284
+ if (!snapshot?.data) {
285
+ this.isHandlingChange = false;
300
286
  return;
287
+ }
301
288
  if (snapshot.data.logged === false || snapshot.data.logged === "false") {
302
289
  this.saveCredentials(null);
303
290
  onSignOut?.();
291
+ this.isHandlingChange = false;
304
292
  return;
305
293
  }
306
294
  const newCreds = Credentials.fromMap(snapshot.toMap());
307
295
  if (!this.isSameCredentials(this.eUser, newCreds)) {
308
- this.eUser = newCreds;
309
296
  this.saveCredentials(newCreds);
310
297
  onChange(newCreds);
311
298
  }
312
299
  }
300
+ this.isHandlingChange = false;
313
301
  }
314
302
  );
315
303
  };
@@ -318,10 +306,10 @@ var _Authentication = class _Authentication {
318
306
  this.eUser = initialUser;
319
307
  onChange(initialUser);
320
308
  }
309
+ credsUnsub = this.onValue("creds", handleCredsChange);
321
310
  handleCredsChange(initialUser);
322
- const credsUnsub = this.onValue("creds", handleCredsChange);
323
311
  return () => {
324
- credsUnsub();
312
+ credsUnsub?.();
325
313
  userDocUnsubscribe?.();
326
314
  };
327
315
  }