@oxyhq/core 12.10.5 → 12.11.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 (130) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/boot/sessionColdBoot.js +142 -37
  3. package/dist/cjs/i18n/locales/ar-SA.json +13 -1
  4. package/dist/cjs/i18n/locales/ca-ES.json +13 -1
  5. package/dist/cjs/i18n/locales/de-DE.json +13 -1
  6. package/dist/cjs/i18n/locales/en-US.json +13 -4
  7. package/dist/cjs/i18n/locales/es-ES.json +13 -4
  8. package/dist/cjs/i18n/locales/fr-FR.json +13 -1
  9. package/dist/cjs/i18n/locales/it-IT.json +13 -1
  10. package/dist/cjs/i18n/locales/ja-JP.json +13 -1
  11. package/dist/cjs/i18n/locales/ko-KR.json +13 -1
  12. package/dist/cjs/i18n/locales/locales/ar-SA.json +13 -1
  13. package/dist/cjs/i18n/locales/locales/ca-ES.json +13 -1
  14. package/dist/cjs/i18n/locales/locales/de-DE.json +13 -1
  15. package/dist/cjs/i18n/locales/locales/en-US.json +13 -4
  16. package/dist/cjs/i18n/locales/locales/es-ES.json +13 -4
  17. package/dist/cjs/i18n/locales/locales/fr-FR.json +13 -1
  18. package/dist/cjs/i18n/locales/locales/it-IT.json +13 -1
  19. package/dist/cjs/i18n/locales/locales/ja-JP.json +13 -1
  20. package/dist/cjs/i18n/locales/locales/ko-KR.json +13 -1
  21. package/dist/cjs/i18n/locales/locales/pt-PT.json +13 -1
  22. package/dist/cjs/i18n/locales/locales/zh-CN.json +13 -1
  23. package/dist/cjs/i18n/locales/pt-PT.json +13 -1
  24. package/dist/cjs/i18n/locales/zh-CN.json +13 -1
  25. package/dist/cjs/index.js +31 -5
  26. package/dist/cjs/mixins/OxyServices.auth.js +257 -17
  27. package/dist/cjs/mixins/OxyServices.deviceBoot.js +54 -3
  28. package/dist/cjs/mixins/OxyServices.notifications.js +63 -0
  29. package/dist/cjs/mixins/index.js +5 -0
  30. package/dist/cjs/session/SessionClient.js +40 -4
  31. package/dist/cjs/session/accountDialogController.js +288 -41
  32. package/dist/cjs/session/hubSync.js +1 -1
  33. package/dist/cjs/session/identityPin.js +256 -0
  34. package/dist/cjs/session/identitySession.js +135 -0
  35. package/dist/cjs/session/projectSessionState.js +54 -15
  36. package/dist/cjs/session/refresh.js +73 -8
  37. package/dist/cjs/utils/commonsDelivery.js +59 -0
  38. package/dist/cjs/utils/oauthPkce.js +33 -3
  39. package/dist/esm/.tsbuildinfo +1 -1
  40. package/dist/esm/boot/sessionColdBoot.js +142 -37
  41. package/dist/esm/i18n/locales/ar-SA.json +13 -1
  42. package/dist/esm/i18n/locales/ca-ES.json +13 -1
  43. package/dist/esm/i18n/locales/de-DE.json +13 -1
  44. package/dist/esm/i18n/locales/en-US.json +13 -4
  45. package/dist/esm/i18n/locales/es-ES.json +13 -4
  46. package/dist/esm/i18n/locales/fr-FR.json +13 -1
  47. package/dist/esm/i18n/locales/it-IT.json +13 -1
  48. package/dist/esm/i18n/locales/ja-JP.json +13 -1
  49. package/dist/esm/i18n/locales/ko-KR.json +13 -1
  50. package/dist/esm/i18n/locales/locales/ar-SA.json +13 -1
  51. package/dist/esm/i18n/locales/locales/ca-ES.json +13 -1
  52. package/dist/esm/i18n/locales/locales/de-DE.json +13 -1
  53. package/dist/esm/i18n/locales/locales/en-US.json +13 -4
  54. package/dist/esm/i18n/locales/locales/es-ES.json +13 -4
  55. package/dist/esm/i18n/locales/locales/fr-FR.json +13 -1
  56. package/dist/esm/i18n/locales/locales/it-IT.json +13 -1
  57. package/dist/esm/i18n/locales/locales/ja-JP.json +13 -1
  58. package/dist/esm/i18n/locales/locales/ko-KR.json +13 -1
  59. package/dist/esm/i18n/locales/locales/pt-PT.json +13 -1
  60. package/dist/esm/i18n/locales/locales/zh-CN.json +13 -1
  61. package/dist/esm/i18n/locales/pt-PT.json +13 -1
  62. package/dist/esm/i18n/locales/zh-CN.json +13 -1
  63. package/dist/esm/index.js +14 -1
  64. package/dist/esm/mixins/OxyServices.auth.js +257 -17
  65. package/dist/esm/mixins/OxyServices.deviceBoot.js +52 -3
  66. package/dist/esm/mixins/OxyServices.notifications.js +60 -0
  67. package/dist/esm/mixins/index.js +5 -0
  68. package/dist/esm/session/SessionClient.js +40 -4
  69. package/dist/esm/session/accountDialogController.js +288 -41
  70. package/dist/esm/session/hubSync.js +1 -1
  71. package/dist/esm/session/identityPin.js +249 -0
  72. package/dist/esm/session/identitySession.js +131 -0
  73. package/dist/esm/session/projectSessionState.js +54 -15
  74. package/dist/esm/session/refresh.js +73 -8
  75. package/dist/esm/utils/commonsDelivery.js +54 -0
  76. package/dist/esm/utils/oauthPkce.js +31 -2
  77. package/dist/types/.tsbuildinfo +1 -1
  78. package/dist/types/boot/sessionColdBoot.d.ts +38 -1
  79. package/dist/types/index.d.ts +12 -4
  80. package/dist/types/mixins/OxyServices.auth.d.ts +262 -11
  81. package/dist/types/mixins/OxyServices.deviceBoot.d.ts +31 -1
  82. package/dist/types/mixins/OxyServices.notifications.d.ts +143 -0
  83. package/dist/types/mixins/index.d.ts +2 -1
  84. package/dist/types/session/SessionClient.d.ts +28 -0
  85. package/dist/types/session/accountDialogController.d.ts +187 -9
  86. package/dist/types/session/identityPin.d.ts +87 -0
  87. package/dist/types/session/identitySession.d.ts +105 -0
  88. package/dist/types/session/projectSessionState.d.ts +21 -19
  89. package/dist/types/session/refresh.d.ts +32 -1
  90. package/dist/types/utils/commonsDelivery.d.ts +105 -0
  91. package/dist/types/utils/oauthPkce.d.ts +21 -1
  92. package/package.json +2 -2
  93. package/src/boot/__tests__/sessionColdBoot.identity.test.ts +393 -0
  94. package/src/boot/sessionColdBoot.ts +183 -37
  95. package/src/i18n/locales/ar-SA.json +13 -1
  96. package/src/i18n/locales/ca-ES.json +13 -1
  97. package/src/i18n/locales/de-DE.json +13 -1
  98. package/src/i18n/locales/en-US.json +13 -4
  99. package/src/i18n/locales/es-ES.json +13 -4
  100. package/src/i18n/locales/fr-FR.json +13 -1
  101. package/src/i18n/locales/it-IT.json +13 -1
  102. package/src/i18n/locales/ja-JP.json +13 -1
  103. package/src/i18n/locales/ko-KR.json +13 -1
  104. package/src/i18n/locales/pt-PT.json +13 -1
  105. package/src/i18n/locales/zh-CN.json +13 -1
  106. package/src/index.ts +49 -0
  107. package/src/mixins/OxyServices.auth.ts +464 -24
  108. package/src/mixins/OxyServices.deviceBoot.ts +54 -2
  109. package/src/mixins/OxyServices.notifications.ts +142 -0
  110. package/src/mixins/__tests__/commonsSignIn.test.ts +754 -2
  111. package/src/mixins/__tests__/deviceTokenMintPinned.test.ts +113 -0
  112. package/src/mixins/__tests__/preSessionSkipAuth.test.ts +18 -0
  113. package/src/mixins/index.ts +6 -0
  114. package/src/session/SessionClient.ts +57 -4
  115. package/src/session/__tests__/SessionClient.identityPin.test.ts +175 -0
  116. package/src/session/__tests__/accountDialogController.test.ts +812 -1
  117. package/src/session/__tests__/hubSync.test.ts +51 -0
  118. package/src/session/__tests__/identityPin.test.ts +131 -0
  119. package/src/session/__tests__/identitySession.test.ts +194 -0
  120. package/src/session/__tests__/projectSessionState.test.ts +88 -0
  121. package/src/session/__tests__/refresh.identityPin.test.ts +306 -0
  122. package/src/session/accountDialogController.ts +435 -44
  123. package/src/session/hubSync.ts +1 -1
  124. package/src/session/identityPin.ts +310 -0
  125. package/src/session/identitySession.ts +206 -0
  126. package/src/session/projectSessionState.ts +61 -13
  127. package/src/session/refresh.ts +103 -9
  128. package/src/utils/__tests__/oauthPkce.test.ts +51 -0
  129. package/src/utils/commonsDelivery.ts +132 -0
  130. package/src/utils/oauthPkce.ts +56 -3
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectCommonsDelivery = selectCommonsDelivery;
4
+ exports.pushTargetsFromDelivery = pushTargetsFromDelivery;
5
+ exports.commonsDeliveryPlatform = commonsDeliveryPlatform;
6
+ const platform_1 = require("./platform");
7
+ /**
8
+ * Choose the ONE primary delivery route for a "Sign in with Oxy" request.
9
+ *
10
+ * Decision order (issue #691, "Automatic delivery selection"):
11
+ *
12
+ * 1. Mobile with a verified Commons link available → open Commons directly.
13
+ * No push is needed when the identity is already reachable on this device.
14
+ * 2. At least one eligible Commons installation was pushed to → await the push.
15
+ * 3. Otherwise → QR.
16
+ *
17
+ * A caller that already knows it is on step 1 does not need to call
18
+ * `deliverCommonsSignIn` at all; every other caller runs the delivery
19
+ * round-trip first and passes its `targets` in here.
20
+ *
21
+ * `pushTargets` is server-derived, so it is validated rather than trusted: a
22
+ * negative, fractional, non-finite, or otherwise malformed count is treated as
23
+ * "no targets" and degrades to QR instead of parking the user on a "check your
24
+ * phone" screen that nothing will ever wake.
25
+ */
26
+ function selectCommonsDelivery(facts) {
27
+ if (facts.platform === 'mobile' && facts.commonsAvailable) {
28
+ return 'open-commons';
29
+ }
30
+ if (Number.isInteger(facts.pushTargets) && facts.pushTargets >= 1) {
31
+ return 'await-push';
32
+ }
33
+ return 'qr';
34
+ }
35
+ /**
36
+ * Map a `deliverCommonsSignIn` result onto the `pushTargets` fact for
37
+ * {@link selectCommonsDelivery}. The server reports eligible install *count*
38
+ * separately from whether any push was accepted — a transport failure can leave
39
+ * `delivered: false` with `targets > 0`, which must NOT park the user on
40
+ * "check your phone".
41
+ */
42
+ function pushTargetsFromDelivery(result) {
43
+ return result.delivered ? result.targets : 0;
44
+ }
45
+ /**
46
+ * Classify the current runtime surface for delivery selection. Callers that
47
+ * cannot confidently detect the platform should not use this — pass
48
+ * `'unknown'` explicitly instead.
49
+ */
50
+ function commonsDeliveryPlatform() {
51
+ const os = (0, platform_1.getPlatformOS)();
52
+ if (os === 'ios' || os === 'android') {
53
+ return 'mobile';
54
+ }
55
+ if (os === 'web') {
56
+ return 'desktop';
57
+ }
58
+ return 'unknown';
59
+ }
@@ -17,12 +17,13 @@
17
17
  * React Native. No `require()`, so the ESM build stays bundler-clean.
18
18
  */
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY = exports.OXY_CROSS_ORIGIN_RESTORE_ATTEMPTED_KEY = exports.OXY_SILENT_OAUTH_ATTEMPTED_KEY = exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = exports.OXY_OAUTH_STATE_STORAGE_KEY = exports.DEFAULT_OAUTH_SCOPE = exports.OXY_AUTHORIZE_URL = void 0;
20
+ exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY = exports.OXY_CROSS_ORIGIN_RESTORE_ATTEMPTED_KEY = exports.OXY_SILENT_OAUTH_ATTEMPTED_KEY = exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = exports.OXY_OAUTH_STATE_STORAGE_KEY = exports.DEFAULT_OAUTH_SCOPE = exports.OXY_AUTHORIZE_URL = void 0;
21
21
  exports.computeCodeChallenge = computeCodeChallenge;
22
22
  exports.generatePkcePair = generatePkcePair;
23
23
  exports.generateOAuthState = generateOAuthState;
24
24
  exports.buildOAuthAuthorizeUrl = buildOAuthAuthorizeUrl;
25
25
  exports.normalizeOAuthRedirectUri = normalizeOAuthRedirectUri;
26
+ exports.canonicalizeOAuthRedirectUri = canonicalizeOAuthRedirectUri;
26
27
  exports.persistOAuthReturnPath = persistOAuthReturnPath;
27
28
  exports.consumeOAuthReturnPath = consumeOAuthReturnPath;
28
29
  exports.persistOAuthHandshake = persistOAuthHandshake;
@@ -147,12 +148,17 @@ function buildOAuthAuthorizeUrl(params) {
147
148
  if (params.prompt) {
148
149
  url.searchParams.set('prompt', params.prompt);
149
150
  }
151
+ if (params.responseMode) {
152
+ url.searchParams.set('response_mode', params.responseMode);
153
+ }
150
154
  return url.toString();
151
155
  }
152
156
  /** `sessionStorage` key for the OAuth CSRF `state` across an authorize redirect. */
153
157
  exports.OXY_OAUTH_STATE_STORAGE_KEY = 'oxy_oauth_state';
154
158
  /** `sessionStorage` key for the PKCE `code_verifier` across an authorize redirect. */
155
159
  exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = 'oxy_oauth_code_verifier';
160
+ /** `sessionStorage` key — the exact `redirect_uri` sent on the authorize request. */
161
+ exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = 'oxy.oauth_redirect_uri';
156
162
  /** `sessionStorage` key — at most one silent OAuth attempt per navigation. */
157
163
  exports.OXY_SILENT_OAUTH_ATTEMPTED_KEY = 'oxy.silent_oauth_attempted';
158
164
  /** `sessionStorage` key — blocks further cross-origin auto-restore in this tab. */
@@ -179,6 +185,25 @@ function normalizeOAuthRedirectUri(input) {
179
185
  return input;
180
186
  }
181
187
  }
188
+ /**
189
+ * Collapse `https://app.example/` → `https://app.example` for OAuth binding.
190
+ * Path-qualified redirect URIs are preserved — matches the API token exchange.
191
+ */
192
+ function canonicalizeOAuthRedirectUri(redirectUri) {
193
+ try {
194
+ const parsed = new URL(redirectUri);
195
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
196
+ return redirectUri;
197
+ }
198
+ if (parsed.pathname === '/' && !parsed.search && !parsed.hash) {
199
+ return parsed.origin;
200
+ }
201
+ return redirectUri;
202
+ }
203
+ catch {
204
+ return redirectUri;
205
+ }
206
+ }
182
207
  /**
183
208
  * Is this a safe same-origin path to restore into the address bar?
184
209
  *
@@ -244,13 +269,16 @@ function consumeOAuthReturnPath() {
244
269
  }
245
270
  }
246
271
  /** Persist the OAuth handshake for a full-page redirect return (web only). */
247
- function persistOAuthHandshake(state, codeVerifier) {
272
+ function persistOAuthHandshake(state, codeVerifier, redirectUri) {
248
273
  const store = globalThis.sessionStorage;
249
274
  try {
250
275
  if (!store)
251
276
  throw new Error('sessionStorage is unavailable');
252
277
  store.setItem(exports.OXY_OAUTH_STATE_STORAGE_KEY, state);
253
278
  store.setItem(exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY, codeVerifier);
279
+ if (redirectUri) {
280
+ store.setItem(exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY, canonicalizeOAuthRedirectUri(redirectUri));
281
+ }
254
282
  return true;
255
283
  }
256
284
  catch (error) {
@@ -267,7 +295,8 @@ function readOAuthHandshake() {
267
295
  const codeVerifier = store.getItem(exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY);
268
296
  if (!state || !codeVerifier)
269
297
  return null;
270
- return { state, codeVerifier };
298
+ const redirectUri = store.getItem(exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY) ?? undefined;
299
+ return redirectUri ? { state, codeVerifier, redirectUri } : { state, codeVerifier };
271
300
  }
272
301
  /** Drop persisted OAuth handshake keys after a successful or aborted return. */
273
302
  function clearOAuthHandshake() {
@@ -275,6 +304,7 @@ function clearOAuthHandshake() {
275
304
  try {
276
305
  store?.removeItem(exports.OXY_OAUTH_STATE_STORAGE_KEY);
277
306
  store?.removeItem(exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY);
307
+ store?.removeItem(exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY);
278
308
  // The return path belongs to this handshake. Leaving it behind would let a
279
309
  // later, unrelated navigation in the same tab be redirected by it.
280
310
  store?.removeItem(exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY);