@oxyhq/core 1.11.23 → 2.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 (141) hide show
  1. package/README.md +5 -6
  2. package/dist/cjs/.tsbuildinfo +1 -1
  3. package/dist/cjs/AuthManager.js +678 -4
  4. package/dist/cjs/AuthManagerTypes.js +13 -0
  5. package/dist/cjs/CrossDomainAuth.js +45 -3
  6. package/dist/cjs/OxyServices.base.js +16 -0
  7. package/dist/cjs/i18n/locales/ar-SA.json +83 -0
  8. package/dist/cjs/i18n/locales/ca-ES.json +83 -0
  9. package/dist/cjs/i18n/locales/de-DE.json +83 -0
  10. package/dist/cjs/i18n/locales/en-US.json +83 -0
  11. package/dist/cjs/i18n/locales/es-ES.json +99 -4
  12. package/dist/cjs/i18n/locales/fr-FR.json +83 -0
  13. package/dist/cjs/i18n/locales/it-IT.json +83 -0
  14. package/dist/cjs/i18n/locales/ja-JP.json +83 -0
  15. package/dist/cjs/i18n/locales/ko-KR.json +83 -0
  16. package/dist/cjs/i18n/locales/locales/ar-SA.json +83 -1
  17. package/dist/cjs/i18n/locales/locales/ca-ES.json +83 -1
  18. package/dist/cjs/i18n/locales/locales/de-DE.json +83 -1
  19. package/dist/cjs/i18n/locales/locales/en-US.json +83 -0
  20. package/dist/cjs/i18n/locales/locales/es-ES.json +99 -4
  21. package/dist/cjs/i18n/locales/locales/fr-FR.json +83 -1
  22. package/dist/cjs/i18n/locales/locales/it-IT.json +83 -1
  23. package/dist/cjs/i18n/locales/locales/ja-JP.json +200 -117
  24. package/dist/cjs/i18n/locales/locales/ko-KR.json +83 -1
  25. package/dist/cjs/i18n/locales/locales/pt-PT.json +83 -1
  26. package/dist/cjs/i18n/locales/locales/zh-CN.json +83 -1
  27. package/dist/cjs/i18n/locales/pt-PT.json +83 -0
  28. package/dist/cjs/i18n/locales/zh-CN.json +83 -0
  29. package/dist/cjs/index.js +114 -57
  30. package/dist/cjs/mixins/OxyServices.auth.js +235 -0
  31. package/dist/cjs/mixins/OxyServices.fedcm.js +205 -73
  32. package/dist/cjs/mixins/OxyServices.popup.js +61 -1
  33. package/dist/cjs/mixins/OxyServices.user.js +18 -0
  34. package/dist/cjs/utils/accountUtils.js +64 -1
  35. package/dist/esm/.tsbuildinfo +1 -1
  36. package/dist/esm/AuthManager.js +678 -4
  37. package/dist/esm/AuthManagerTypes.js +12 -0
  38. package/dist/esm/CrossDomainAuth.js +45 -3
  39. package/dist/esm/OxyServices.base.js +16 -0
  40. package/dist/esm/i18n/locales/ar-SA.json +83 -0
  41. package/dist/esm/i18n/locales/ca-ES.json +83 -0
  42. package/dist/esm/i18n/locales/de-DE.json +83 -0
  43. package/dist/esm/i18n/locales/en-US.json +83 -0
  44. package/dist/esm/i18n/locales/es-ES.json +99 -4
  45. package/dist/esm/i18n/locales/fr-FR.json +83 -0
  46. package/dist/esm/i18n/locales/it-IT.json +83 -0
  47. package/dist/esm/i18n/locales/ja-JP.json +83 -0
  48. package/dist/esm/i18n/locales/ko-KR.json +83 -0
  49. package/dist/esm/i18n/locales/locales/ar-SA.json +83 -1
  50. package/dist/esm/i18n/locales/locales/ca-ES.json +83 -1
  51. package/dist/esm/i18n/locales/locales/de-DE.json +83 -1
  52. package/dist/esm/i18n/locales/locales/en-US.json +83 -0
  53. package/dist/esm/i18n/locales/locales/es-ES.json +99 -4
  54. package/dist/esm/i18n/locales/locales/fr-FR.json +83 -1
  55. package/dist/esm/i18n/locales/locales/it-IT.json +83 -1
  56. package/dist/esm/i18n/locales/locales/ja-JP.json +200 -117
  57. package/dist/esm/i18n/locales/locales/ko-KR.json +83 -1
  58. package/dist/esm/i18n/locales/locales/pt-PT.json +83 -1
  59. package/dist/esm/i18n/locales/locales/zh-CN.json +83 -1
  60. package/dist/esm/i18n/locales/pt-PT.json +83 -0
  61. package/dist/esm/i18n/locales/zh-CN.json +83 -0
  62. package/dist/esm/index.js +69 -26
  63. package/dist/esm/mixins/OxyServices.auth.js +235 -0
  64. package/dist/esm/mixins/OxyServices.fedcm.js +205 -73
  65. package/dist/esm/mixins/OxyServices.popup.js +61 -1
  66. package/dist/esm/mixins/OxyServices.user.js +18 -0
  67. package/dist/esm/utils/accountUtils.js +61 -0
  68. package/dist/types/.tsbuildinfo +1 -1
  69. package/dist/types/AuthManager.d.ts +243 -3
  70. package/dist/types/AuthManagerTypes.d.ts +68 -0
  71. package/dist/types/CrossDomainAuth.d.ts +23 -0
  72. package/dist/types/OxyServices.base.d.ts +14 -0
  73. package/dist/types/OxyServices.d.ts +16 -0
  74. package/dist/types/index.d.ts +28 -17
  75. package/dist/types/mixins/OxyServices.analytics.d.ts +1 -0
  76. package/dist/types/mixins/OxyServices.appData.d.ts +1 -0
  77. package/dist/types/mixins/OxyServices.assets.d.ts +4 -1
  78. package/dist/types/mixins/OxyServices.auth.d.ts +73 -1
  79. package/dist/types/mixins/OxyServices.contacts.d.ts +1 -0
  80. package/dist/types/mixins/OxyServices.developer.d.ts +1 -0
  81. package/dist/types/mixins/OxyServices.devices.d.ts +1 -0
  82. package/dist/types/mixins/OxyServices.features.d.ts +2 -5
  83. package/dist/types/mixins/OxyServices.fedcm.d.ts +53 -1
  84. package/dist/types/mixins/OxyServices.karma.d.ts +1 -0
  85. package/dist/types/mixins/OxyServices.language.d.ts +1 -0
  86. package/dist/types/mixins/OxyServices.location.d.ts +1 -0
  87. package/dist/types/mixins/OxyServices.managedAccounts.d.ts +1 -0
  88. package/dist/types/mixins/OxyServices.payment.d.ts +1 -0
  89. package/dist/types/mixins/OxyServices.popup.d.ts +40 -0
  90. package/dist/types/mixins/OxyServices.privacy.d.ts +1 -0
  91. package/dist/types/mixins/OxyServices.redirect.d.ts +1 -0
  92. package/dist/types/mixins/OxyServices.security.d.ts +1 -0
  93. package/dist/types/mixins/OxyServices.topics.d.ts +1 -0
  94. package/dist/types/mixins/OxyServices.user.d.ts +16 -1
  95. package/dist/types/mixins/OxyServices.utility.d.ts +1 -0
  96. package/dist/types/models/interfaces.d.ts +98 -0
  97. package/dist/types/models/session.d.ts +8 -0
  98. package/dist/types/utils/accountUtils.d.ts +33 -0
  99. package/package.json +9 -18
  100. package/src/AuthManager.ts +776 -7
  101. package/src/AuthManagerTypes.ts +72 -0
  102. package/src/CrossDomainAuth.ts +54 -3
  103. package/src/OxyServices.base.ts +17 -0
  104. package/src/OxyServices.ts +17 -0
  105. package/src/__tests__/authManager.cookiePath.test.ts +339 -0
  106. package/src/__tests__/authManager.security.test.ts +342 -0
  107. package/src/__tests__/crossDomainAuth.test.ts +191 -0
  108. package/src/i18n/locales/ar-SA.json +83 -1
  109. package/src/i18n/locales/ca-ES.json +83 -1
  110. package/src/i18n/locales/de-DE.json +83 -1
  111. package/src/i18n/locales/en-US.json +83 -0
  112. package/src/i18n/locales/es-ES.json +99 -4
  113. package/src/i18n/locales/fr-FR.json +83 -1
  114. package/src/i18n/locales/it-IT.json +83 -1
  115. package/src/i18n/locales/ja-JP.json +200 -117
  116. package/src/i18n/locales/ko-KR.json +83 -1
  117. package/src/i18n/locales/pt-PT.json +83 -1
  118. package/src/i18n/locales/zh-CN.json +83 -1
  119. package/src/index.ts +295 -112
  120. package/src/mixins/OxyServices.auth.ts +268 -1
  121. package/src/mixins/OxyServices.fedcm.ts +250 -78
  122. package/src/mixins/OxyServices.popup.ts +79 -1
  123. package/src/mixins/OxyServices.user.ts +33 -1
  124. package/src/mixins/__tests__/fedcm.test.ts +231 -0
  125. package/src/mixins/__tests__/popup.test.ts +307 -0
  126. package/src/mixins/__tests__/sessionBaseUrl.test.ts +61 -0
  127. package/src/models/interfaces.ts +116 -0
  128. package/src/models/session.ts +8 -0
  129. package/src/utils/accountUtils.ts +84 -0
  130. package/dist/cjs/crypto/index.js +0 -22
  131. package/dist/cjs/shared/index.js +0 -70
  132. package/dist/cjs/utils/index.js +0 -26
  133. package/dist/esm/crypto/index.js +0 -13
  134. package/dist/esm/shared/index.js +0 -31
  135. package/dist/esm/utils/index.js +0 -7
  136. package/dist/types/crypto/index.d.ts +0 -11
  137. package/dist/types/shared/index.d.ts +0 -28
  138. package/dist/types/utils/index.d.ts +0 -6
  139. package/src/crypto/index.ts +0 -30
  140. package/src/shared/index.ts +0 -82
  141. package/src/utils/index.ts +0 -21
@@ -81,7 +81,37 @@ function OxyServicesPopupAuthMixin(Base) {
81
81
  clientId: window.location.origin,
82
82
  redirectUri: `${this.resolveAuthUrl()}/auth/callback`,
83
83
  });
84
- const popup = this.openCenteredPopup(authUrl, 'Oxy Sign In', width, height);
84
+ // If the caller pre-opened a popup on the raw user gesture (recommended
85
+ // path — see `openBlankPopup` and `PopupAuthOptions.popup`), navigate it
86
+ // to the auth URL instead of issuing a fresh `window.open` (which would
87
+ // be blocked once any prior `await` has consumed the user activation).
88
+ let popup;
89
+ const preOpened = options.popup ?? null;
90
+ if (preOpened) {
91
+ if (preOpened.closed) {
92
+ // The pre-opened popup is gone — distinguish a user cancel (they
93
+ // closed the blank window before sign-in could navigate it) from a
94
+ // blocker rejection. Lumping these together as "Popup blocked" is
95
+ // misleading: the popup was NOT blocked, it was opened successfully
96
+ // and then dismissed.
97
+ throw new OxyServices_errors_1.OxyAuthenticationError('Sign-in window was closed before authentication could start.');
98
+ }
99
+ try {
100
+ preOpened.location.replace(authUrl);
101
+ }
102
+ catch (replaceError) {
103
+ // `location.replace` can throw in sandboxed / cross-origin-locked
104
+ // environments. Fall back to `href` assignment, which is more
105
+ // permissive. Logged at debug-level so consumers can correlate
106
+ // unusual sign-in behaviour without producing noise in normal flows.
107
+ debug.warn('location.replace failed, falling back to location.href', replaceError);
108
+ preOpened.location.href = authUrl;
109
+ }
110
+ popup = preOpened;
111
+ }
112
+ else {
113
+ popup = this.openCenteredPopup(authUrl, 'Oxy Sign In', width, height);
114
+ }
85
115
  if (!popup) {
86
116
  throw new OxyServices_errors_1.OxyAuthenticationError('Popup blocked. Please allow popups for this site and try again.');
87
117
  }
@@ -224,6 +254,36 @@ function OxyServicesPopupAuthMixin(Base) {
224
254
  document.body.removeChild(iframe);
225
255
  }
226
256
  }
257
+ /**
258
+ * Open a blank, centered popup window SYNCHRONOUSLY.
259
+ *
260
+ * Use this in a click (or other user-gesture) handler BEFORE any `await`
261
+ * to capture the transient user-activation. Pass the returned handle into
262
+ * `signInWithPopup({ popup })` once the async portion of the flow runs.
263
+ *
264
+ * Returns `null` if the browser's popup blocker rejected the open.
265
+ *
266
+ * @example
267
+ * ```typescript
268
+ * const onSignInClick = () => {
269
+ * const popup = oxyServices.openBlankPopup();
270
+ * (async () => {
271
+ * const silent = await oxyServices.silentSignInWithFedCM();
272
+ * if (silent) { popup?.close(); return; }
273
+ * await oxyServices.signInWithPopup({ popup });
274
+ * })();
275
+ * };
276
+ * ```
277
+ */
278
+ openBlankPopup(width, height) {
279
+ if (typeof window === 'undefined') {
280
+ return null;
281
+ }
282
+ const ctor = this.constructor;
283
+ const w = width ?? ctor.POPUP_WIDTH;
284
+ const h = height ?? ctor.POPUP_HEIGHT;
285
+ return this.openCenteredPopup('about:blank', 'Oxy Sign In', w, h);
286
+ }
227
287
  /**
228
288
  * Open a centered popup window
229
289
  *
@@ -218,6 +218,24 @@ function OxyServicesUserMixin(Base) {
218
218
  throw this.handleError(error);
219
219
  }
220
220
  }
221
+ /**
222
+ * Update the authenticated user's notification preferences.
223
+ *
224
+ * Thin wrapper over `updateProfile` that constrains the patch to known
225
+ * notification channels — same persistence path, same cache invalidation,
226
+ * but type-safe at the call site.
227
+ */
228
+ async updateNotificationPreferences(preferences) {
229
+ return this.updateProfile({ notificationPreferences: preferences });
230
+ }
231
+ /**
232
+ * Update the authenticated user's general preferences (language, theme,
233
+ * reduce-motion, timezone). Persisted on the User document via
234
+ * `PUT /users/me` — same cache-invalidation behaviour as `updateProfile`.
235
+ */
236
+ async updateUserPreferences(preferences) {
237
+ return this.updateProfile({ userPreferences: preferences });
238
+ }
221
239
  /**
222
240
  * Request account verification
223
241
  */
@@ -4,7 +4,7 @@
4
4
  * Used by both @oxyhq/services (React Native) and @oxyhq/auth (Web) account stores.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.createQuickAccount = exports.buildAccountsArray = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.formatPublicKeyHandle = void 0;
7
+ exports.getAccountColor = exports.mergeAccountsFromRefreshAll = exports.createQuickAccount = exports.buildAccountsArray = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.formatPublicKeyHandle = void 0;
8
8
  const i18n_1 = require("../i18n");
9
9
  /**
10
10
  * Truncate a long public key for display, e.g. `0x12345678…`.
@@ -116,3 +116,66 @@ const createQuickAccount = (sessionId, userData, existingAccount, getFileDownloa
116
116
  };
117
117
  };
118
118
  exports.createQuickAccount = createQuickAccount;
119
+ /**
120
+ * Merge a fresh `/auth/refresh-all` snapshot into an existing QuickAccount
121
+ * list, preserving any cached fields (`avatarUrl`) for slots that didn't
122
+ * change. The fresh response is canonical: the resulting list contains EXACTLY
123
+ * the slots present in `fresh`, sorted by `authuser` ascending. Stale stored
124
+ * accounts that no longer appear in `fresh` are dropped (the server already
125
+ * authoritatively cleared the corresponding cookie).
126
+ *
127
+ * @param stored Previously persisted QuickAccount list (any order).
128
+ * @param fresh Server's authoritative refresh-all response.
129
+ * @returns Canonical merged list, sorted by `authuser` asc.
130
+ */
131
+ const mergeAccountsFromRefreshAll = (stored, fresh) => {
132
+ const storedByAuthuser = new Map();
133
+ if (stored) {
134
+ for (const account of stored) {
135
+ if (typeof account.authuser === 'number') {
136
+ storedByAuthuser.set(account.authuser, account);
137
+ }
138
+ }
139
+ }
140
+ const merged = fresh.map((entry) => {
141
+ const previous = storedByAuthuser.get(entry.authuser);
142
+ // `entry.user` is null on the SDK legacy-fallback path; preserve any
143
+ // previously cached identity for that slot rather than overwriting
144
+ // it with blanks, and let the AuthManager's getCurrentUser() hydration
145
+ // refresh it on the next snapshot.
146
+ const wireUser = entry.user;
147
+ const username = wireUser?.username ?? previous?.username ?? '';
148
+ const displayName = (0, exports.getAccountDisplayName)({
149
+ name: wireUser?.name,
150
+ username,
151
+ });
152
+ const avatar = wireUser?.avatar ?? previous?.avatar ?? undefined;
153
+ const avatarUrl = previous && previous.avatar === avatar ? previous.avatarUrl : undefined;
154
+ return {
155
+ sessionId: entry.sessionId,
156
+ userId: wireUser?.id ?? previous?.userId,
157
+ username,
158
+ displayName,
159
+ avatar,
160
+ avatarUrl,
161
+ authuser: entry.authuser,
162
+ color: wireUser?.color ?? previous?.color ?? null,
163
+ };
164
+ });
165
+ merged.sort((a, b) => {
166
+ const aIdx = a.authuser ?? Number.POSITIVE_INFINITY;
167
+ const bIdx = b.authuser ?? Number.POSITIVE_INFINITY;
168
+ return aIdx - bIdx;
169
+ });
170
+ return merged;
171
+ };
172
+ exports.mergeAccountsFromRefreshAll = mergeAccountsFromRefreshAll;
173
+ /**
174
+ * Return the account's preferred Bloom color preset, or `null` if it has no
175
+ * preference. Centralises the `color ?? null` normalisation so consumers can
176
+ * drive per-account theming without duplicating the nullish-handling.
177
+ */
178
+ const getAccountColor = (account) => {
179
+ return account.color ?? null;
180
+ };
181
+ exports.getAccountColor = getAccountColor;