@entropy-softworks/ui 2026.8.34 → 2026.8.36

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 (45) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/lib/components/auth/PasswordStrengthMeter.d.ts +9 -0
  3. package/lib/components/auth/PasswordStrengthMeter.d.ts.map +1 -1
  4. package/lib/components/auth/PasswordStrengthMeter.jsx +10 -4
  5. package/lib/components/auth/PasswordStrengthMeter.jsx.map +1 -1
  6. package/lib/components/profile/SecurityTab.d.ts +5 -1
  7. package/lib/components/profile/SecurityTab.d.ts.map +1 -1
  8. package/lib/components/profile/SecurityTab.jsx.map +1 -1
  9. package/lib/components/segmented-toggle.d.ts +9 -0
  10. package/lib/components/segmented-toggle.d.ts.map +1 -1
  11. package/lib/components/segmented-toggle.jsx +4 -0
  12. package/lib/components/segmented-toggle.jsx.map +1 -1
  13. package/lib/components/social-connections.d.ts +22 -5
  14. package/lib/components/social-connections.d.ts.map +1 -1
  15. package/lib/components/social-connections.jsx +37 -11
  16. package/lib/components/social-connections.jsx.map +1 -1
  17. package/lib/context/AppConfigContext.d.ts +27 -0
  18. package/lib/context/AppConfigContext.d.ts.map +1 -1
  19. package/lib/context/AppConfigContext.jsx.map +1 -1
  20. package/lib/demos/extension-popup.d.ts +212 -0
  21. package/lib/demos/extension-popup.d.ts.map +1 -0
  22. package/lib/demos/extension-popup.jsx +1172 -0
  23. package/lib/demos/extension-popup.jsx.map +1 -0
  24. package/lib/demos/index.d.ts +11 -0
  25. package/lib/demos/index.d.ts.map +1 -0
  26. package/lib/demos/index.js +14 -0
  27. package/lib/demos/index.js.map +1 -0
  28. package/lib/screens/auth/AuthScreen.d.ts +75 -1
  29. package/lib/screens/auth/AuthScreen.d.ts.map +1 -1
  30. package/lib/screens/auth/AuthScreen.jsx +356 -122
  31. package/lib/screens/auth/AuthScreen.jsx.map +1 -1
  32. package/lib/services/auth.service.d.ts +41 -1
  33. package/lib/services/auth.service.d.ts.map +1 -1
  34. package/lib/services/auth.service.js +53 -7
  35. package/lib/services/auth.service.js.map +1 -1
  36. package/package.json +7 -1
  37. package/src/components/auth/PasswordStrengthMeter.tsx +25 -3
  38. package/src/components/profile/SecurityTab.tsx +11 -1
  39. package/src/components/segmented-toggle.tsx +13 -0
  40. package/src/components/social-connections.tsx +66 -20
  41. package/src/context/AppConfigContext.tsx +27 -0
  42. package/src/demos/extension-popup.tsx +2051 -0
  43. package/src/demos/index.ts +38 -0
  44. package/src/screens/auth/AuthScreen.tsx +701 -312
  45. package/src/services/auth.service.ts +62 -8
@@ -273,18 +273,54 @@ class AuthService {
273
273
  }
274
274
  }
275
275
 
276
+ /**
277
+ * The signed-in user, from local state if it is there and from the server if
278
+ * it is not.
279
+ *
280
+ * The server fallback is the whole point. On web `loadPersistedUser` returns
281
+ * a module-level variable, which is null in every freshly loaded document —
282
+ * so this used to answer "nobody" on each page load and refresh while the
283
+ * session cookie was perfectly valid. `useAuth.checkAuth` reads that as a
284
+ * session it cannot resolve and calls `logout()`, which POSTs
285
+ * `/auth/logout` and destroys the session server-side. The user is signed
286
+ * out by the act of loading the page.
287
+ *
288
+ * Observed on Access on 2026-08-22: the portal and the admin console are
289
+ * separate SPAs on one origin, so every navigation between them is a fresh
290
+ * document and therefore a guaranteed logout — which presents as an infinite
291
+ * sign-in loop. Its audit log recorded the logouts nobody asked for.
292
+ *
293
+ * Native was affected too, if less visibly: `isAuthenticated` there is
294
+ * satisfied by a token in SecureStore, so a token that outlived its cached
295
+ * user record produced the same spurious logout.
296
+ *
297
+ * It does NOT route through `isAuthenticated`. That method's web branch falls
298
+ * back to calling this one, so going the other way would recurse until the
299
+ * stack gave out on exactly the signed-out path this is meant to make cheap.
300
+ */
276
301
  static async getCurrentUser(): Promise<User | null> {
277
- return loadPersistedUser();
302
+ const persisted = await loadPersistedUser();
303
+ if (persisted) {
304
+ return persisted;
305
+ }
306
+ return AuthService.fetchMe(false);
278
307
  }
279
308
 
280
- static async refreshUserData(): Promise<User | null> {
309
+ /**
310
+ * `GET /auth/me`, persisting whatever comes back.
311
+ *
312
+ * `logoutOn401` is a parameter rather than a fixed behaviour because the two
313
+ * callers need opposite things from the same request. A *refresh* of a
314
+ * session believed live that returns 401 means the session died and local
315
+ * state should be cleared. A *lookup* that returns 401 means there was no
316
+ * session to begin with — the ordinary state of a signed-out visitor — and
317
+ * tearing down on that would fire a logout on every anonymous page load.
318
+ */
319
+ private static async fetchMe(logoutOn401: boolean): Promise<User | null> {
281
320
  try {
282
- if (!(await this.isAuthenticated())) {
283
- return null;
284
- }
285
321
  const response = await apiFetch("/auth/me", { method: "GET" });
286
322
  if (!response.ok) {
287
- if (response.status === 401) {
323
+ if (logoutOn401 && response.status === 401) {
288
324
  await this.logout();
289
325
  }
290
326
  return null;
@@ -297,6 +333,13 @@ class AuthService {
297
333
  }
298
334
  }
299
335
 
336
+ static async refreshUserData(): Promise<User | null> {
337
+ if (!(await this.isAuthenticated())) {
338
+ return null;
339
+ }
340
+ return AuthService.fetchMe(true);
341
+ }
342
+
300
343
  /**
301
344
  * Web: HttpOnly cookies aren't readable from JS. We use the
302
345
  * presence of the (non-HttpOnly) `csrf_token` cookie — set by the
@@ -339,7 +382,14 @@ class AuthService {
339
382
  static async changePassword(
340
383
  currentPassword: string,
341
384
  newPassword: string,
342
- reWrappedKey?: { symmetric_key_enc: string; pbkdf2_salt: string }
385
+ reWrappedKey?: {
386
+ symmetric_key_enc: string;
387
+ kdf: string;
388
+ kdf_salt: string;
389
+ kdf_iterations: number;
390
+ kdf_memory_kib?: number;
391
+ kdf_lanes?: number;
392
+ }
343
393
  ): Promise<void> {
344
394
  const body: Record<string, unknown> = {
345
395
  current_password: currentPassword.normalize("NFC"),
@@ -347,7 +397,11 @@ class AuthService {
347
397
  };
348
398
  if (reWrappedKey) {
349
399
  body.symmetric_key_enc = reWrappedKey.symmetric_key_enc;
350
- body.pbkdf2_salt = reWrappedKey.pbkdf2_salt;
400
+ body.kdf = reWrappedKey.kdf;
401
+ body.kdf_salt = reWrappedKey.kdf_salt;
402
+ body.kdf_iterations = reWrappedKey.kdf_iterations;
403
+ body.kdf_memory_kib = reWrappedKey.kdf_memory_kib;
404
+ body.kdf_lanes = reWrappedKey.kdf_lanes;
351
405
  }
352
406
  const response = await apiFetch("/auth/password", {
353
407
  method: "PUT",