@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.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/boot/sessionColdBoot.js +142 -37
- package/dist/cjs/i18n/locales/ar-SA.json +13 -1
- package/dist/cjs/i18n/locales/ca-ES.json +13 -1
- package/dist/cjs/i18n/locales/de-DE.json +13 -1
- package/dist/cjs/i18n/locales/en-US.json +13 -4
- package/dist/cjs/i18n/locales/es-ES.json +13 -4
- package/dist/cjs/i18n/locales/fr-FR.json +13 -1
- package/dist/cjs/i18n/locales/it-IT.json +13 -1
- package/dist/cjs/i18n/locales/ja-JP.json +13 -1
- package/dist/cjs/i18n/locales/ko-KR.json +13 -1
- package/dist/cjs/i18n/locales/locales/ar-SA.json +13 -1
- package/dist/cjs/i18n/locales/locales/ca-ES.json +13 -1
- package/dist/cjs/i18n/locales/locales/de-DE.json +13 -1
- package/dist/cjs/i18n/locales/locales/en-US.json +13 -4
- package/dist/cjs/i18n/locales/locales/es-ES.json +13 -4
- package/dist/cjs/i18n/locales/locales/fr-FR.json +13 -1
- package/dist/cjs/i18n/locales/locales/it-IT.json +13 -1
- package/dist/cjs/i18n/locales/locales/ja-JP.json +13 -1
- package/dist/cjs/i18n/locales/locales/ko-KR.json +13 -1
- package/dist/cjs/i18n/locales/locales/pt-PT.json +13 -1
- package/dist/cjs/i18n/locales/locales/zh-CN.json +13 -1
- package/dist/cjs/i18n/locales/pt-PT.json +13 -1
- package/dist/cjs/i18n/locales/zh-CN.json +13 -1
- package/dist/cjs/index.js +31 -5
- package/dist/cjs/mixins/OxyServices.auth.js +257 -17
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +54 -3
- package/dist/cjs/mixins/OxyServices.notifications.js +63 -0
- package/dist/cjs/mixins/index.js +5 -0
- package/dist/cjs/session/SessionClient.js +40 -4
- package/dist/cjs/session/accountDialogController.js +288 -41
- package/dist/cjs/session/hubSync.js +1 -1
- package/dist/cjs/session/identityPin.js +256 -0
- package/dist/cjs/session/identitySession.js +135 -0
- package/dist/cjs/session/projectSessionState.js +54 -15
- package/dist/cjs/session/refresh.js +73 -8
- package/dist/cjs/utils/commonsDelivery.js +59 -0
- package/dist/cjs/utils/oauthPkce.js +33 -3
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/boot/sessionColdBoot.js +142 -37
- package/dist/esm/i18n/locales/ar-SA.json +13 -1
- package/dist/esm/i18n/locales/ca-ES.json +13 -1
- package/dist/esm/i18n/locales/de-DE.json +13 -1
- package/dist/esm/i18n/locales/en-US.json +13 -4
- package/dist/esm/i18n/locales/es-ES.json +13 -4
- package/dist/esm/i18n/locales/fr-FR.json +13 -1
- package/dist/esm/i18n/locales/it-IT.json +13 -1
- package/dist/esm/i18n/locales/ja-JP.json +13 -1
- package/dist/esm/i18n/locales/ko-KR.json +13 -1
- package/dist/esm/i18n/locales/locales/ar-SA.json +13 -1
- package/dist/esm/i18n/locales/locales/ca-ES.json +13 -1
- package/dist/esm/i18n/locales/locales/de-DE.json +13 -1
- package/dist/esm/i18n/locales/locales/en-US.json +13 -4
- package/dist/esm/i18n/locales/locales/es-ES.json +13 -4
- package/dist/esm/i18n/locales/locales/fr-FR.json +13 -1
- package/dist/esm/i18n/locales/locales/it-IT.json +13 -1
- package/dist/esm/i18n/locales/locales/ja-JP.json +13 -1
- package/dist/esm/i18n/locales/locales/ko-KR.json +13 -1
- package/dist/esm/i18n/locales/locales/pt-PT.json +13 -1
- package/dist/esm/i18n/locales/locales/zh-CN.json +13 -1
- package/dist/esm/i18n/locales/pt-PT.json +13 -1
- package/dist/esm/i18n/locales/zh-CN.json +13 -1
- package/dist/esm/index.js +14 -1
- package/dist/esm/mixins/OxyServices.auth.js +257 -17
- package/dist/esm/mixins/OxyServices.deviceBoot.js +52 -3
- package/dist/esm/mixins/OxyServices.notifications.js +60 -0
- package/dist/esm/mixins/index.js +5 -0
- package/dist/esm/session/SessionClient.js +40 -4
- package/dist/esm/session/accountDialogController.js +288 -41
- package/dist/esm/session/hubSync.js +1 -1
- package/dist/esm/session/identityPin.js +249 -0
- package/dist/esm/session/identitySession.js +131 -0
- package/dist/esm/session/projectSessionState.js +54 -15
- package/dist/esm/session/refresh.js +73 -8
- package/dist/esm/utils/commonsDelivery.js +54 -0
- package/dist/esm/utils/oauthPkce.js +31 -2
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/boot/sessionColdBoot.d.ts +38 -1
- package/dist/types/index.d.ts +12 -4
- package/dist/types/mixins/OxyServices.auth.d.ts +262 -11
- package/dist/types/mixins/OxyServices.deviceBoot.d.ts +31 -1
- package/dist/types/mixins/OxyServices.notifications.d.ts +143 -0
- package/dist/types/mixins/index.d.ts +2 -1
- package/dist/types/session/SessionClient.d.ts +28 -0
- package/dist/types/session/accountDialogController.d.ts +187 -9
- package/dist/types/session/identityPin.d.ts +87 -0
- package/dist/types/session/identitySession.d.ts +105 -0
- package/dist/types/session/projectSessionState.d.ts +21 -19
- package/dist/types/session/refresh.d.ts +32 -1
- package/dist/types/utils/commonsDelivery.d.ts +105 -0
- package/dist/types/utils/oauthPkce.d.ts +21 -1
- package/package.json +2 -2
- package/src/boot/__tests__/sessionColdBoot.identity.test.ts +393 -0
- package/src/boot/sessionColdBoot.ts +183 -37
- package/src/i18n/locales/ar-SA.json +13 -1
- package/src/i18n/locales/ca-ES.json +13 -1
- package/src/i18n/locales/de-DE.json +13 -1
- package/src/i18n/locales/en-US.json +13 -4
- package/src/i18n/locales/es-ES.json +13 -4
- package/src/i18n/locales/fr-FR.json +13 -1
- package/src/i18n/locales/it-IT.json +13 -1
- package/src/i18n/locales/ja-JP.json +13 -1
- package/src/i18n/locales/ko-KR.json +13 -1
- package/src/i18n/locales/pt-PT.json +13 -1
- package/src/i18n/locales/zh-CN.json +13 -1
- package/src/index.ts +49 -0
- package/src/mixins/OxyServices.auth.ts +464 -24
- package/src/mixins/OxyServices.deviceBoot.ts +54 -2
- package/src/mixins/OxyServices.notifications.ts +142 -0
- package/src/mixins/__tests__/commonsSignIn.test.ts +754 -2
- package/src/mixins/__tests__/deviceTokenMintPinned.test.ts +113 -0
- package/src/mixins/__tests__/preSessionSkipAuth.test.ts +18 -0
- package/src/mixins/index.ts +6 -0
- package/src/session/SessionClient.ts +57 -4
- package/src/session/__tests__/SessionClient.identityPin.test.ts +175 -0
- package/src/session/__tests__/accountDialogController.test.ts +812 -1
- package/src/session/__tests__/hubSync.test.ts +51 -0
- package/src/session/__tests__/identityPin.test.ts +131 -0
- package/src/session/__tests__/identitySession.test.ts +194 -0
- package/src/session/__tests__/projectSessionState.test.ts +88 -0
- package/src/session/__tests__/refresh.identityPin.test.ts +306 -0
- package/src/session/accountDialogController.ts +435 -44
- package/src/session/hubSync.ts +1 -1
- package/src/session/identityPin.ts +310 -0
- package/src/session/identitySession.ts +206 -0
- package/src/session/projectSessionState.ts +61 -13
- package/src/session/refresh.ts +103 -9
- package/src/utils/__tests__/oauthPkce.test.ts +51 -0
- package/src/utils/commonsDelivery.ts +132 -0
- package/src/utils/oauthPkce.ts +56 -3
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getPlatformOS } from './platform.js';
|
|
2
|
+
/**
|
|
3
|
+
* Choose the ONE primary delivery route for a "Sign in with Oxy" request.
|
|
4
|
+
*
|
|
5
|
+
* Decision order (issue #691, "Automatic delivery selection"):
|
|
6
|
+
*
|
|
7
|
+
* 1. Mobile with a verified Commons link available → open Commons directly.
|
|
8
|
+
* No push is needed when the identity is already reachable on this device.
|
|
9
|
+
* 2. At least one eligible Commons installation was pushed to → await the push.
|
|
10
|
+
* 3. Otherwise → QR.
|
|
11
|
+
*
|
|
12
|
+
* A caller that already knows it is on step 1 does not need to call
|
|
13
|
+
* `deliverCommonsSignIn` at all; every other caller runs the delivery
|
|
14
|
+
* round-trip first and passes its `targets` in here.
|
|
15
|
+
*
|
|
16
|
+
* `pushTargets` is server-derived, so it is validated rather than trusted: a
|
|
17
|
+
* negative, fractional, non-finite, or otherwise malformed count is treated as
|
|
18
|
+
* "no targets" and degrades to QR instead of parking the user on a "check your
|
|
19
|
+
* phone" screen that nothing will ever wake.
|
|
20
|
+
*/
|
|
21
|
+
export function selectCommonsDelivery(facts) {
|
|
22
|
+
if (facts.platform === 'mobile' && facts.commonsAvailable) {
|
|
23
|
+
return 'open-commons';
|
|
24
|
+
}
|
|
25
|
+
if (Number.isInteger(facts.pushTargets) && facts.pushTargets >= 1) {
|
|
26
|
+
return 'await-push';
|
|
27
|
+
}
|
|
28
|
+
return 'qr';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Map a `deliverCommonsSignIn` result onto the `pushTargets` fact for
|
|
32
|
+
* {@link selectCommonsDelivery}. The server reports eligible install *count*
|
|
33
|
+
* separately from whether any push was accepted — a transport failure can leave
|
|
34
|
+
* `delivered: false` with `targets > 0`, which must NOT park the user on
|
|
35
|
+
* "check your phone".
|
|
36
|
+
*/
|
|
37
|
+
export function pushTargetsFromDelivery(result) {
|
|
38
|
+
return result.delivered ? result.targets : 0;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Classify the current runtime surface for delivery selection. Callers that
|
|
42
|
+
* cannot confidently detect the platform should not use this — pass
|
|
43
|
+
* `'unknown'` explicitly instead.
|
|
44
|
+
*/
|
|
45
|
+
export function commonsDeliveryPlatform() {
|
|
46
|
+
const os = getPlatformOS();
|
|
47
|
+
if (os === 'ios' || os === 'android') {
|
|
48
|
+
return 'mobile';
|
|
49
|
+
}
|
|
50
|
+
if (os === 'web') {
|
|
51
|
+
return 'desktop';
|
|
52
|
+
}
|
|
53
|
+
return 'unknown';
|
|
54
|
+
}
|
|
@@ -134,12 +134,17 @@ export function buildOAuthAuthorizeUrl(params) {
|
|
|
134
134
|
if (params.prompt) {
|
|
135
135
|
url.searchParams.set('prompt', params.prompt);
|
|
136
136
|
}
|
|
137
|
+
if (params.responseMode) {
|
|
138
|
+
url.searchParams.set('response_mode', params.responseMode);
|
|
139
|
+
}
|
|
137
140
|
return url.toString();
|
|
138
141
|
}
|
|
139
142
|
/** `sessionStorage` key for the OAuth CSRF `state` across an authorize redirect. */
|
|
140
143
|
export const OXY_OAUTH_STATE_STORAGE_KEY = 'oxy_oauth_state';
|
|
141
144
|
/** `sessionStorage` key for the PKCE `code_verifier` across an authorize redirect. */
|
|
142
145
|
export const OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = 'oxy_oauth_code_verifier';
|
|
146
|
+
/** `sessionStorage` key — the exact `redirect_uri` sent on the authorize request. */
|
|
147
|
+
export const OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = 'oxy.oauth_redirect_uri';
|
|
143
148
|
/** `sessionStorage` key — at most one silent OAuth attempt per navigation. */
|
|
144
149
|
export const OXY_SILENT_OAUTH_ATTEMPTED_KEY = 'oxy.silent_oauth_attempted';
|
|
145
150
|
/** `sessionStorage` key — blocks further cross-origin auto-restore in this tab. */
|
|
@@ -166,6 +171,25 @@ export function normalizeOAuthRedirectUri(input) {
|
|
|
166
171
|
return input;
|
|
167
172
|
}
|
|
168
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Collapse `https://app.example/` → `https://app.example` for OAuth binding.
|
|
176
|
+
* Path-qualified redirect URIs are preserved — matches the API token exchange.
|
|
177
|
+
*/
|
|
178
|
+
export function canonicalizeOAuthRedirectUri(redirectUri) {
|
|
179
|
+
try {
|
|
180
|
+
const parsed = new URL(redirectUri);
|
|
181
|
+
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
182
|
+
return redirectUri;
|
|
183
|
+
}
|
|
184
|
+
if (parsed.pathname === '/' && !parsed.search && !parsed.hash) {
|
|
185
|
+
return parsed.origin;
|
|
186
|
+
}
|
|
187
|
+
return redirectUri;
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return redirectUri;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
169
193
|
/**
|
|
170
194
|
* Is this a safe same-origin path to restore into the address bar?
|
|
171
195
|
*
|
|
@@ -231,13 +255,16 @@ export function consumeOAuthReturnPath() {
|
|
|
231
255
|
}
|
|
232
256
|
}
|
|
233
257
|
/** Persist the OAuth handshake for a full-page redirect return (web only). */
|
|
234
|
-
export function persistOAuthHandshake(state, codeVerifier) {
|
|
258
|
+
export function persistOAuthHandshake(state, codeVerifier, redirectUri) {
|
|
235
259
|
const store = globalThis.sessionStorage;
|
|
236
260
|
try {
|
|
237
261
|
if (!store)
|
|
238
262
|
throw new Error('sessionStorage is unavailable');
|
|
239
263
|
store.setItem(OXY_OAUTH_STATE_STORAGE_KEY, state);
|
|
240
264
|
store.setItem(OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY, codeVerifier);
|
|
265
|
+
if (redirectUri) {
|
|
266
|
+
store.setItem(OXY_OAUTH_REDIRECT_URI_STORAGE_KEY, canonicalizeOAuthRedirectUri(redirectUri));
|
|
267
|
+
}
|
|
241
268
|
return true;
|
|
242
269
|
}
|
|
243
270
|
catch (error) {
|
|
@@ -254,7 +281,8 @@ export function readOAuthHandshake() {
|
|
|
254
281
|
const codeVerifier = store.getItem(OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY);
|
|
255
282
|
if (!state || !codeVerifier)
|
|
256
283
|
return null;
|
|
257
|
-
|
|
284
|
+
const redirectUri = store.getItem(OXY_OAUTH_REDIRECT_URI_STORAGE_KEY) ?? undefined;
|
|
285
|
+
return redirectUri ? { state, codeVerifier, redirectUri } : { state, codeVerifier };
|
|
258
286
|
}
|
|
259
287
|
/** Drop persisted OAuth handshake keys after a successful or aborted return. */
|
|
260
288
|
export function clearOAuthHandshake() {
|
|
@@ -262,6 +290,7 @@ export function clearOAuthHandshake() {
|
|
|
262
290
|
try {
|
|
263
291
|
store?.removeItem(OXY_OAUTH_STATE_STORAGE_KEY);
|
|
264
292
|
store?.removeItem(OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY);
|
|
293
|
+
store?.removeItem(OXY_OAUTH_REDIRECT_URI_STORAGE_KEY);
|
|
265
294
|
// The return path belongs to this handshake. Leaving it behind would let a
|
|
266
295
|
// later, unrelated navigation in the same tab be redirected by it.
|
|
267
296
|
store?.removeItem(OXY_OAUTH_RETURN_PATH_STORAGE_KEY);
|