@oxyhq/core 3.4.1 → 3.4.2
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/AuthManager.js +91 -319
- package/dist/cjs/CrossDomainAuth.js +19 -106
- package/dist/cjs/HttpService.js +49 -73
- package/dist/cjs/OxyServices.base.js +2 -2
- package/dist/cjs/i18n/index.js +7 -1
- package/dist/cjs/i18n/locales/ar-SA.json +18 -2
- package/dist/cjs/i18n/locales/ca-ES.json +18 -2
- package/dist/cjs/i18n/locales/de-DE.json +18 -2
- package/dist/cjs/i18n/locales/en-US.json +16 -2
- package/dist/cjs/i18n/locales/es-ES.json +16 -2
- package/dist/cjs/i18n/locales/fr-FR.json +18 -2
- package/dist/cjs/i18n/locales/it-IT.json +18 -2
- package/dist/cjs/i18n/locales/ja-JP.json +18 -2
- package/dist/cjs/i18n/locales/ko-KR.json +18 -2
- package/dist/cjs/i18n/locales/locales/ar-SA.json +18 -2
- package/dist/cjs/i18n/locales/locales/ca-ES.json +18 -2
- package/dist/cjs/i18n/locales/locales/de-DE.json +18 -2
- package/dist/cjs/i18n/locales/locales/en-US.json +17 -3
- package/dist/cjs/i18n/locales/locales/es-ES.json +16 -2
- package/dist/cjs/i18n/locales/locales/fr-FR.json +18 -2
- package/dist/cjs/i18n/locales/locales/it-IT.json +18 -2
- package/dist/cjs/i18n/locales/locales/ja-JP.json +18 -2
- package/dist/cjs/i18n/locales/locales/ko-KR.json +18 -2
- package/dist/cjs/i18n/locales/locales/pt-PT.json +18 -2
- package/dist/cjs/i18n/locales/locales/zh-CN.json +18 -2
- package/dist/cjs/i18n/locales/pt-PT.json +18 -2
- package/dist/cjs/i18n/locales/zh-CN.json +18 -2
- package/dist/cjs/mixins/OxyServices.auth.js +20 -63
- package/dist/cjs/mixins/OxyServices.fedcm.js +10 -12
- package/dist/cjs/mixins/OxyServices.popup.js +50 -299
- package/dist/cjs/mixins/OxyServices.redirect.js +84 -348
- package/dist/cjs/mixins/OxyServices.silent.js +204 -0
- package/dist/cjs/mixins/OxyServices.sso.js +4 -5
- package/dist/cjs/mixins/OxyServices.utility.js +6 -15
- package/dist/cjs/mixins/index.js +5 -6
- package/dist/cjs/server/index.js +21 -0
- package/dist/cjs/server/rateLimit.js +77 -0
- package/dist/cjs/shared/utils/debugUtils.js +1 -1
- package/dist/cjs/utils/accountUtils.js +4 -4
- package/dist/cjs/utils/authHelpers.js +21 -15
- package/dist/cjs/utils/coldBoot.js +3 -3
- package/dist/cjs/utils/fapiAutoDetect.js +1 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/AuthManager.js +91 -319
- package/dist/esm/CrossDomainAuth.js +19 -106
- package/dist/esm/HttpService.js +49 -73
- package/dist/esm/OxyServices.base.js +2 -2
- package/dist/esm/i18n/index.js +7 -1
- package/dist/esm/i18n/locales/ar-SA.json +18 -2
- package/dist/esm/i18n/locales/ca-ES.json +18 -2
- package/dist/esm/i18n/locales/de-DE.json +18 -2
- package/dist/esm/i18n/locales/en-US.json +16 -2
- package/dist/esm/i18n/locales/es-ES.json +16 -2
- package/dist/esm/i18n/locales/fr-FR.json +18 -2
- package/dist/esm/i18n/locales/it-IT.json +18 -2
- package/dist/esm/i18n/locales/ja-JP.json +18 -2
- package/dist/esm/i18n/locales/ko-KR.json +18 -2
- package/dist/esm/i18n/locales/locales/ar-SA.json +18 -2
- package/dist/esm/i18n/locales/locales/ca-ES.json +18 -2
- package/dist/esm/i18n/locales/locales/de-DE.json +18 -2
- package/dist/esm/i18n/locales/locales/en-US.json +17 -3
- package/dist/esm/i18n/locales/locales/es-ES.json +16 -2
- package/dist/esm/i18n/locales/locales/fr-FR.json +18 -2
- package/dist/esm/i18n/locales/locales/it-IT.json +18 -2
- package/dist/esm/i18n/locales/locales/ja-JP.json +18 -2
- package/dist/esm/i18n/locales/locales/ko-KR.json +18 -2
- package/dist/esm/i18n/locales/locales/pt-PT.json +18 -2
- package/dist/esm/i18n/locales/locales/zh-CN.json +18 -2
- package/dist/esm/i18n/locales/pt-PT.json +18 -2
- package/dist/esm/i18n/locales/zh-CN.json +18 -2
- package/dist/esm/mixins/OxyServices.auth.js +20 -63
- package/dist/esm/mixins/OxyServices.fedcm.js +10 -12
- package/dist/esm/mixins/OxyServices.popup.js +52 -301
- package/dist/esm/mixins/OxyServices.redirect.js +84 -349
- package/dist/esm/mixins/OxyServices.silent.js +202 -0
- package/dist/esm/mixins/OxyServices.sso.js +4 -5
- package/dist/esm/mixins/OxyServices.utility.js +6 -15
- package/dist/esm/mixins/index.js +5 -6
- package/dist/esm/server/index.js +17 -0
- package/dist/esm/server/rateLimit.js +71 -0
- package/dist/esm/shared/utils/debugUtils.js +1 -1
- package/dist/esm/utils/accountUtils.js +4 -4
- package/dist/esm/utils/authHelpers.js +21 -15
- package/dist/esm/utils/coldBoot.js +3 -3
- package/dist/esm/utils/fapiAutoDetect.js +1 -1
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/AuthManager.d.ts +26 -53
- package/dist/types/AuthManagerTypes.d.ts +5 -9
- package/dist/types/CrossDomainAuth.d.ts +13 -52
- package/dist/types/HttpService.d.ts +9 -8
- package/dist/types/OxyServices.base.d.ts +1 -1
- package/dist/types/OxyServices.d.ts +4 -10
- package/dist/types/index.d.ts +1 -1
- package/dist/types/mixins/OxyServices.analytics.d.ts +1 -1
- package/dist/types/mixins/OxyServices.appData.d.ts +1 -1
- package/dist/types/mixins/OxyServices.applications.d.ts +1 -1
- package/dist/types/mixins/OxyServices.assets.d.ts +1 -1
- package/dist/types/mixins/OxyServices.auth.d.ts +10 -31
- package/dist/types/mixins/OxyServices.contacts.d.ts +1 -1
- package/dist/types/mixins/OxyServices.devices.d.ts +1 -1
- package/dist/types/mixins/OxyServices.features.d.ts +1 -1
- package/dist/types/mixins/OxyServices.fedcm.d.ts +5 -5
- package/dist/types/mixins/OxyServices.language.d.ts +1 -1
- package/dist/types/mixins/OxyServices.location.d.ts +1 -1
- package/dist/types/mixins/OxyServices.managedAccounts.d.ts +1 -1
- package/dist/types/mixins/OxyServices.payment.d.ts +1 -1
- package/dist/types/mixins/OxyServices.popup.d.ts +18 -120
- package/dist/types/mixins/OxyServices.privacy.d.ts +1 -1
- package/dist/types/mixins/OxyServices.redirect.d.ts +13 -174
- package/dist/types/mixins/OxyServices.reputation.d.ts +1 -1
- package/dist/types/mixins/OxyServices.security.d.ts +1 -1
- package/dist/types/mixins/OxyServices.silent.d.ts +131 -0
- package/dist/types/mixins/OxyServices.sso.d.ts +4 -5
- package/dist/types/mixins/OxyServices.topics.d.ts +1 -1
- package/dist/types/mixins/OxyServices.user.d.ts +1 -1
- package/dist/types/mixins/OxyServices.utility.d.ts +3 -8
- package/dist/types/mixins/OxyServices.workspaces.d.ts +1 -1
- package/dist/types/mixins/index.d.ts +3 -3
- package/dist/types/models/interfaces.d.ts +5 -16
- package/dist/types/models/session.d.ts +0 -2
- package/dist/types/server/index.d.ts +18 -0
- package/dist/types/server/rateLimit.d.ts +40 -0
- package/dist/types/shared/utils/debugUtils.d.ts +1 -1
- package/dist/types/utils/authHelpers.d.ts +4 -3
- package/dist/types/utils/coldBoot.d.ts +2 -2
- package/dist/types/utils/fapiAutoDetect.d.ts +1 -1
- package/package.json +24 -2
- package/src/AuthManager.ts +100 -370
- package/src/AuthManagerTypes.ts +5 -9
- package/src/CrossDomainAuth.ts +22 -129
- package/src/HttpService.ts +55 -73
- package/src/OxyServices.base.ts +2 -3
- package/src/OxyServices.ts +9 -11
- package/src/__tests__/authManager.cookiePath.test.ts +19 -17
- package/src/__tests__/authManager.security.test.ts +7 -3
- package/src/__tests__/crossDomainAuth.test.ts +26 -118
- package/src/i18n/index.ts +7 -1
- package/src/i18n/locales/ar-SA.json +18 -2
- package/src/i18n/locales/ca-ES.json +18 -2
- package/src/i18n/locales/de-DE.json +18 -2
- package/src/i18n/locales/en-US.json +17 -3
- package/src/i18n/locales/es-ES.json +16 -2
- package/src/i18n/locales/fr-FR.json +18 -2
- package/src/i18n/locales/it-IT.json +18 -2
- package/src/i18n/locales/ja-JP.json +18 -2
- package/src/i18n/locales/ko-KR.json +18 -2
- package/src/i18n/locales/pt-PT.json +18 -2
- package/src/i18n/locales/zh-CN.json +18 -2
- package/src/index.ts +1 -1
- package/src/mixins/OxyServices.auth.ts +23 -75
- package/src/mixins/OxyServices.fedcm.ts +10 -12
- package/src/mixins/OxyServices.redirect.ts +82 -371
- package/src/mixins/OxyServices.silent.ts +272 -0
- package/src/mixins/OxyServices.sso.ts +5 -6
- package/src/mixins/OxyServices.utility.ts +9 -22
- package/src/mixins/__tests__/appData.test.ts +1 -1
- package/src/mixins/__tests__/onTokensChanged.test.ts +1 -1
- package/src/mixins/__tests__/reputation.test.ts +1 -1
- package/src/mixins/__tests__/serviceAuth.test.ts +7 -5
- package/src/mixins/__tests__/silent.test.ts +102 -0
- package/src/mixins/__tests__/verifyChallenge.test.ts +9 -14
- package/src/mixins/index.ts +6 -8
- package/src/models/interfaces.ts +5 -16
- package/src/models/session.ts +1 -3
- package/src/server/index.ts +19 -0
- package/src/server/rateLimit.ts +170 -0
- package/src/shared/utils/debugUtils.ts +1 -1
- package/src/utils/accountUtils.ts +4 -4
- package/src/utils/authHelpers.ts +23 -15
- package/src/utils/coldBoot.ts +4 -4
- package/src/utils/fapiAutoDetect.ts +1 -1
- package/src/mixins/OxyServices.popup.ts +0 -631
- package/src/mixins/__tests__/popup.test.ts +0 -374
|
@@ -39,13 +39,18 @@ function buildAccessToken(claims: Record<string, unknown>): string {
|
|
|
39
39
|
return `${header}.${payload}.signature`;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
interface MockHttpService {
|
|
43
|
+
setTokens: jest.Mock;
|
|
44
|
+
setAuthRefreshHandler: jest.Mock;
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
interface MockServices {
|
|
43
48
|
refreshAllSessions: jest.Mock<Promise<RefreshAllResponse>, []>;
|
|
44
49
|
refreshTokenViaCookie: jest.Mock<Promise<RefreshCookieResponse | null>, [{ authuser?: number }]>;
|
|
45
50
|
logoutSessionByAuthuser: jest.Mock<Promise<void>, [number]>;
|
|
46
51
|
logoutAllSessionsViaCookie: jest.Mock<Promise<void>, []>;
|
|
47
52
|
getCurrentUser: jest.Mock<Promise<User>, []>;
|
|
48
|
-
httpService:
|
|
53
|
+
httpService: MockHttpService;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
function makeMockServices(): MockServices {
|
|
@@ -61,7 +66,7 @@ function makeMockServices(): MockServices {
|
|
|
61
66
|
avatar: 'avatar-1',
|
|
62
67
|
color: 'teal',
|
|
63
68
|
} as User)),
|
|
64
|
-
httpService: { setTokens: jest.fn(),
|
|
69
|
+
httpService: { setTokens: jest.fn(), setAuthRefreshHandler: jest.fn() },
|
|
65
70
|
};
|
|
66
71
|
}
|
|
67
72
|
|
|
@@ -71,7 +76,6 @@ function makeManager(services: MockServices, options: { crossTabSync?: boolean }
|
|
|
71
76
|
storage,
|
|
72
77
|
autoRefresh: false,
|
|
73
78
|
crossTabSync: options.crossTabSync ?? false,
|
|
74
|
-
cookieOnly: true,
|
|
75
79
|
});
|
|
76
80
|
}
|
|
77
81
|
|
|
@@ -1,41 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CrossDomainAuth orphan-popup cleanup regression tests.
|
|
3
|
-
*
|
|
4
|
-
* Locks in the security-review fix for issue #1: when a caller pre-opens a
|
|
5
|
-
* popup (the standard §6c pattern in WebOxyProvider / services useAuth) and
|
|
6
|
-
* then explicitly requests `signIn({ method: 'fedcm' })` or
|
|
7
|
-
* `signIn({ method: 'redirect' })`, the popup is unused — it must be closed
|
|
8
|
-
* so it doesn't linger as an orphaned blank window over the app UI.
|
|
9
|
-
*
|
|
10
|
-
* Equally important: the `'auto'` mode already handled this for the
|
|
11
|
-
* FedCM-wins path, but these tests pin the EXPLICIT-method behaviour so the
|
|
12
|
-
* gap (an early `return this.signInWithFedCM(options)` that skipped the
|
|
13
|
-
* cleanup) cannot regress.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
1
|
import { CrossDomainAuth } from '../CrossDomainAuth';
|
|
17
2
|
import type { OxyServices } from '../OxyServices';
|
|
18
3
|
import type { SessionLoginResponse } from '../models/session';
|
|
19
4
|
|
|
20
|
-
interface MockPopup {
|
|
21
|
-
closed: boolean;
|
|
22
|
-
close: jest.Mock;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function createMockPopup(): MockPopup {
|
|
26
|
-
return {
|
|
27
|
-
closed: false,
|
|
28
|
-
close: jest.fn(function (this: MockPopup) { this.closed = true; }),
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
5
|
interface MockServices {
|
|
33
6
|
signInWithFedCM: jest.Mock;
|
|
34
|
-
signInWithPopup: jest.Mock;
|
|
35
7
|
signInWithRedirect: jest.Mock;
|
|
36
8
|
silentSignInWithFedCM: jest.Mock;
|
|
37
9
|
isFedCMSupported: jest.Mock;
|
|
38
|
-
openBlankPopup: jest.Mock;
|
|
39
10
|
getCurrentUser: jest.Mock;
|
|
40
11
|
handleAuthCallback: jest.Mock;
|
|
41
12
|
restoreSession: jest.Mock;
|
|
@@ -55,11 +26,9 @@ function fakeSession(id: string): SessionLoginResponse {
|
|
|
55
26
|
function createMockServices(overrides: Partial<MockServices> = {}): MockServices {
|
|
56
27
|
return {
|
|
57
28
|
signInWithFedCM: jest.fn(async () => fakeSession('fedcm-sess')),
|
|
58
|
-
signInWithPopup: jest.fn(async () => fakeSession('popup-sess')),
|
|
59
29
|
signInWithRedirect: jest.fn(),
|
|
60
30
|
silentSignInWithFedCM: jest.fn(async () => null),
|
|
61
31
|
isFedCMSupported: jest.fn(() => true),
|
|
62
|
-
openBlankPopup: jest.fn(() => null),
|
|
63
32
|
getCurrentUser: jest.fn(),
|
|
64
33
|
handleAuthCallback: jest.fn(() => null),
|
|
65
34
|
restoreSession: jest.fn(() => false),
|
|
@@ -68,123 +37,62 @@ function createMockServices(overrides: Partial<MockServices> = {}): MockServices
|
|
|
68
37
|
};
|
|
69
38
|
}
|
|
70
39
|
|
|
71
|
-
describe('CrossDomainAuth
|
|
72
|
-
it('
|
|
73
|
-
const popup = createMockPopup();
|
|
40
|
+
describe('CrossDomainAuth', () => {
|
|
41
|
+
it('uses FedCM for an explicit FedCM sign-in', async () => {
|
|
74
42
|
const services = createMockServices();
|
|
75
43
|
const auth = new CrossDomainAuth(services as unknown as OxyServices);
|
|
76
44
|
|
|
77
|
-
const session = await auth.signIn({
|
|
78
|
-
method: 'fedcm',
|
|
79
|
-
popup: popup as unknown as Window,
|
|
80
|
-
});
|
|
45
|
+
const session = await auth.signIn({ method: 'fedcm' });
|
|
81
46
|
|
|
82
47
|
expect(session).toBeTruthy();
|
|
83
48
|
expect(services.signInWithFedCM).toHaveBeenCalledTimes(1);
|
|
84
|
-
expect(services.
|
|
85
|
-
expect(popup.close).toHaveBeenCalledTimes(1);
|
|
86
|
-
expect(popup.closed).toBe(true);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('closes the pre-opened popup even when explicit FedCM sign-in fails', async () => {
|
|
90
|
-
const popup = createMockPopup();
|
|
91
|
-
const services = createMockServices({
|
|
92
|
-
signInWithFedCM: jest.fn(async () => {
|
|
93
|
-
throw new Error('user cancelled FedCM');
|
|
94
|
-
}),
|
|
95
|
-
});
|
|
96
|
-
const auth = new CrossDomainAuth(services as unknown as OxyServices);
|
|
97
|
-
|
|
98
|
-
await expect(
|
|
99
|
-
auth.signIn({ method: 'fedcm', popup: popup as unknown as Window })
|
|
100
|
-
).rejects.toThrow(/user cancelled FedCM/);
|
|
101
|
-
|
|
102
|
-
expect(popup.close).toHaveBeenCalledTimes(1);
|
|
103
|
-
expect(popup.closed).toBe(true);
|
|
49
|
+
expect(services.signInWithRedirect).not.toHaveBeenCalled();
|
|
104
50
|
});
|
|
105
51
|
|
|
106
|
-
it('
|
|
107
|
-
const popup = createMockPopup();
|
|
52
|
+
it('initiates redirect and returns null for an explicit redirect sign-in', async () => {
|
|
108
53
|
const services = createMockServices();
|
|
109
54
|
const auth = new CrossDomainAuth(services as unknown as OxyServices);
|
|
110
55
|
|
|
111
|
-
const result = await auth.signIn({
|
|
112
|
-
method: 'redirect',
|
|
113
|
-
popup: popup as unknown as Window,
|
|
114
|
-
});
|
|
56
|
+
const result = await auth.signIn({ method: 'redirect', redirectUri: 'https://app.oxy.so' });
|
|
115
57
|
|
|
116
|
-
// Redirect resolves to null (page is navigating).
|
|
117
58
|
expect(result).toBeNull();
|
|
118
|
-
expect(services.signInWithRedirect).
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
expect(popup.closed).toBe(true);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('does NOT close the popup on explicit popup method (it is the active channel)', async () => {
|
|
126
|
-
const popup = createMockPopup();
|
|
127
|
-
const services = createMockServices();
|
|
128
|
-
const auth = new CrossDomainAuth(services as unknown as OxyServices);
|
|
129
|
-
|
|
130
|
-
await auth.signIn({ method: 'popup', popup: popup as unknown as Window });
|
|
131
|
-
|
|
132
|
-
expect(services.signInWithPopup).toHaveBeenCalledTimes(1);
|
|
133
|
-
// The popup is the active sign-in channel for this method — it must be
|
|
134
|
-
// left for the underlying `signInWithPopup` to manage (it cleans up via
|
|
135
|
-
// its own `waitForPopupAuth` cleanup path).
|
|
136
|
-
expect(popup.close).not.toHaveBeenCalled();
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('does not throw when no popup is supplied for explicit FedCM', async () => {
|
|
140
|
-
const services = createMockServices();
|
|
141
|
-
const auth = new CrossDomainAuth(services as unknown as OxyServices);
|
|
142
|
-
|
|
143
|
-
await expect(auth.signIn({ method: 'fedcm' })).resolves.toBeTruthy();
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it('does not call `close()` on an already-closed pre-opened popup', async () => {
|
|
147
|
-
const popup = createMockPopup();
|
|
148
|
-
popup.closed = true;
|
|
149
|
-
const services = createMockServices();
|
|
150
|
-
const auth = new CrossDomainAuth(services as unknown as OxyServices);
|
|
151
|
-
|
|
152
|
-
await auth.signIn({ method: 'fedcm', popup: popup as unknown as Window });
|
|
153
|
-
|
|
154
|
-
// Already-closed handle: skip the `close()` call entirely.
|
|
155
|
-
expect(popup.close).not.toHaveBeenCalled();
|
|
59
|
+
expect(services.signInWithRedirect).toHaveBeenCalledWith({
|
|
60
|
+
redirectUri: 'https://app.oxy.so',
|
|
61
|
+
mode: 'login',
|
|
62
|
+
});
|
|
156
63
|
});
|
|
157
|
-
});
|
|
158
64
|
|
|
159
|
-
|
|
160
|
-
it('closes the pre-opened popup when FedCM wins under auto mode', async () => {
|
|
161
|
-
const popup = createMockPopup();
|
|
65
|
+
it('uses FedCM first in auto mode when supported', async () => {
|
|
162
66
|
const services = createMockServices();
|
|
163
67
|
const auth = new CrossDomainAuth(services as unknown as OxyServices);
|
|
68
|
+
const selected: string[] = [];
|
|
164
69
|
|
|
165
|
-
await auth.signIn({
|
|
70
|
+
const session = await auth.signIn({
|
|
71
|
+
method: 'auto',
|
|
72
|
+
onMethodSelected: (method) => selected.push(method),
|
|
73
|
+
});
|
|
166
74
|
|
|
167
|
-
expect(
|
|
168
|
-
expect(
|
|
75
|
+
expect(session?.sessionId).toBe('fedcm-sess');
|
|
76
|
+
expect(selected).toEqual(['fedcm']);
|
|
77
|
+
expect(services.signInWithRedirect).not.toHaveBeenCalled();
|
|
169
78
|
});
|
|
170
79
|
|
|
171
|
-
it('
|
|
172
|
-
const popup = createMockPopup();
|
|
80
|
+
it('falls back to redirect in auto mode when FedCM fails', async () => {
|
|
173
81
|
const services = createMockServices({
|
|
174
82
|
signInWithFedCM: jest.fn(async () => { throw new Error('fedcm fail'); }),
|
|
175
|
-
signInWithPopup: jest.fn(async () => { throw new Error('popup fail'); }),
|
|
176
83
|
});
|
|
177
84
|
const auth = new CrossDomainAuth(services as unknown as OxyServices);
|
|
178
|
-
|
|
179
|
-
// Suppress the expected console.warn from the auto-mode fallback path.
|
|
85
|
+
const selected: string[] = [];
|
|
180
86
|
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
181
87
|
|
|
182
|
-
const result = await auth.signIn({
|
|
88
|
+
const result = await auth.signIn({
|
|
89
|
+
method: 'auto',
|
|
90
|
+
onMethodSelected: (method) => selected.push(method),
|
|
91
|
+
});
|
|
183
92
|
|
|
184
93
|
expect(result).toBeNull();
|
|
94
|
+
expect(selected).toEqual(['fedcm', 'redirect']);
|
|
185
95
|
expect(services.signInWithRedirect).toHaveBeenCalledTimes(1);
|
|
186
|
-
expect(popup.close).toHaveBeenCalledTimes(1);
|
|
187
|
-
expect(popup.closed).toBe(true);
|
|
188
96
|
|
|
189
97
|
warnSpy.mockRestore();
|
|
190
98
|
});
|
package/src/i18n/index.ts
CHANGED
|
@@ -47,7 +47,13 @@ export function translate(locale: string | undefined, key: string, vars?: Record
|
|
|
47
47
|
const lang = locale && DICTS[locale] ? locale : FALLBACK;
|
|
48
48
|
const dict = DICTS[lang] || DICTS[FALLBACK];
|
|
49
49
|
let val = getNested(dict, key);
|
|
50
|
-
|
|
50
|
+
// Per-key fallback to the English dictionary when a key is missing from the
|
|
51
|
+
// resolved (non-English) locale. Without this, a key present in en-US but not
|
|
52
|
+
// yet translated in e.g. es-ES would render the raw dotted key to users.
|
|
53
|
+
if (typeof val !== 'string' && lang !== FALLBACK) {
|
|
54
|
+
val = getNested(DICTS[FALLBACK], key);
|
|
55
|
+
}
|
|
56
|
+
if (typeof val !== 'string') return key; // last resort: echo the key when truly absent everywhere
|
|
51
57
|
if (vars) {
|
|
52
58
|
Object.keys(vars).forEach(k => {
|
|
53
59
|
const token = `{{${k}}}`;
|
|
@@ -103,7 +103,9 @@
|
|
|
103
103
|
"createAccount": "إنشاء حساب",
|
|
104
104
|
"signIn": "تسجيل الدخول",
|
|
105
105
|
"verify": "التحقق",
|
|
106
|
-
"resetPassword": "إعادة تعيين كلمة المرور"
|
|
106
|
+
"resetPassword": "إعادة تعيين كلمة المرور",
|
|
107
|
+
"signedOut": "تم تسجيل الخروج",
|
|
108
|
+
"close": "إغلاق"
|
|
107
109
|
},
|
|
108
110
|
"links": {
|
|
109
111
|
"recoverAccount": "استعادة حسابك",
|
|
@@ -115,7 +117,10 @@
|
|
|
115
117
|
"password": "كلمة المرور",
|
|
116
118
|
"confirmPassword": "تأكيد كلمة المرور"
|
|
117
119
|
},
|
|
118
|
-
"revoke": "Revoke"
|
|
120
|
+
"revoke": "Revoke",
|
|
121
|
+
"errors": {
|
|
122
|
+
"signOutAllFailed": "حدثت مشكلة أثناء تسجيل الخروج من جميع الحسابات. يرجى المحاولة مرة أخرى."
|
|
123
|
+
}
|
|
119
124
|
},
|
|
120
125
|
"notifications": {
|
|
121
126
|
"title": "Notifications",
|
|
@@ -198,5 +203,16 @@
|
|
|
198
203
|
"revoked": "Revoked access for {{name}}",
|
|
199
204
|
"revokeFailed": "Failed to revoke access"
|
|
200
205
|
}
|
|
206
|
+
},
|
|
207
|
+
"accountMenu": {
|
|
208
|
+
"label": "قائمة الحساب",
|
|
209
|
+
"manage": "إدارة حساب Oxy الخاص بك",
|
|
210
|
+
"addAnother": "إضافة حساب آخر",
|
|
211
|
+
"signOutAll": "تسجيل الخروج من جميع الحسابات",
|
|
212
|
+
"open": "قائمة الحساب",
|
|
213
|
+
"openHint": "يفتح قائمة الحساب",
|
|
214
|
+
"openWithUser": "قائمة حساب {{name}}",
|
|
215
|
+
"switching": "جارٍ تبديل الحساب…",
|
|
216
|
+
"signOutAccount": "تسجيل خروج {{name}}"
|
|
201
217
|
}
|
|
202
218
|
}
|
|
@@ -103,7 +103,9 @@
|
|
|
103
103
|
"createAccount": "Crear compte",
|
|
104
104
|
"signIn": "Iniciar sessió",
|
|
105
105
|
"verify": "Verificar",
|
|
106
|
-
"resetPassword": "Restablir contrasenya"
|
|
106
|
+
"resetPassword": "Restablir contrasenya",
|
|
107
|
+
"signedOut": "Sessió tancada",
|
|
108
|
+
"close": "Tanca"
|
|
107
109
|
},
|
|
108
110
|
"links": {
|
|
109
111
|
"recoverAccount": "Recuperar el teu compte",
|
|
@@ -115,7 +117,10 @@
|
|
|
115
117
|
"password": "Contrasenya",
|
|
116
118
|
"confirmPassword": "Confirmar contrasenya"
|
|
117
119
|
},
|
|
118
|
-
"revoke": "Revoke"
|
|
120
|
+
"revoke": "Revoke",
|
|
121
|
+
"errors": {
|
|
122
|
+
"signOutAllFailed": "Hi ha hagut un problema en tancar la sessió de tots els comptes. Torna-ho a provar."
|
|
123
|
+
}
|
|
119
124
|
},
|
|
120
125
|
"notifications": {
|
|
121
126
|
"title": "Notifications",
|
|
@@ -198,5 +203,16 @@
|
|
|
198
203
|
"revoked": "Revoked access for {{name}}",
|
|
199
204
|
"revokeFailed": "Failed to revoke access"
|
|
200
205
|
}
|
|
206
|
+
},
|
|
207
|
+
"accountMenu": {
|
|
208
|
+
"label": "Menú del compte",
|
|
209
|
+
"manage": "Gestiona el teu compte d'Oxy",
|
|
210
|
+
"addAnother": "Afegeix un altre compte",
|
|
211
|
+
"signOutAll": "Tanca la sessió de tots els comptes",
|
|
212
|
+
"open": "Menú del compte",
|
|
213
|
+
"openHint": "Obre el menú del compte",
|
|
214
|
+
"openWithUser": "Menú del compte de {{name}}",
|
|
215
|
+
"switching": "Canviant de compte…",
|
|
216
|
+
"signOutAccount": "Tanca la sessió de {{name}}"
|
|
201
217
|
}
|
|
202
218
|
}
|
|
@@ -103,7 +103,9 @@
|
|
|
103
103
|
"createAccount": "Konto erstellen",
|
|
104
104
|
"signIn": "Anmelden",
|
|
105
105
|
"verify": "Überprüfen",
|
|
106
|
-
"resetPassword": "Passwort zurücksetzen"
|
|
106
|
+
"resetPassword": "Passwort zurücksetzen",
|
|
107
|
+
"signedOut": "Abgemeldet",
|
|
108
|
+
"close": "Schließen"
|
|
107
109
|
},
|
|
108
110
|
"links": {
|
|
109
111
|
"recoverAccount": "Ihr Konto wiederherstellen",
|
|
@@ -115,7 +117,10 @@
|
|
|
115
117
|
"password": "Passwort",
|
|
116
118
|
"confirmPassword": "Passwort bestätigen"
|
|
117
119
|
},
|
|
118
|
-
"revoke": "Revoke"
|
|
120
|
+
"revoke": "Revoke",
|
|
121
|
+
"errors": {
|
|
122
|
+
"signOutAllFailed": "Beim Abmelden von allen Konten ist ein Problem aufgetreten. Bitte versuchen Sie es erneut."
|
|
123
|
+
}
|
|
119
124
|
},
|
|
120
125
|
"notifications": {
|
|
121
126
|
"title": "Notifications",
|
|
@@ -198,5 +203,16 @@
|
|
|
198
203
|
"revoked": "Revoked access for {{name}}",
|
|
199
204
|
"revokeFailed": "Failed to revoke access"
|
|
200
205
|
}
|
|
206
|
+
},
|
|
207
|
+
"accountMenu": {
|
|
208
|
+
"label": "Kontomenü",
|
|
209
|
+
"manage": "Ihr Oxy-Konto verwalten",
|
|
210
|
+
"addAnother": "Weiteres Konto hinzufügen",
|
|
211
|
+
"signOutAll": "Von allen Konten abmelden",
|
|
212
|
+
"open": "Kontomenü",
|
|
213
|
+
"openHint": "Öffnet das Kontomenü",
|
|
214
|
+
"openWithUser": "Kontomenü für {{name}}",
|
|
215
|
+
"switching": "Konto wird gewechselt…",
|
|
216
|
+
"signOutAccount": "{{name}} abmelden"
|
|
201
217
|
}
|
|
202
218
|
}
|
|
@@ -1038,7 +1038,8 @@
|
|
|
1038
1038
|
},
|
|
1039
1039
|
"common": {
|
|
1040
1040
|
"errors": {
|
|
1041
|
-
"signOutFailed": "There was a problem signing you out. Please try again."
|
|
1041
|
+
"signOutFailed": "There was a problem signing you out. Please try again.",
|
|
1042
|
+
"signOutAllFailed": "There was a problem signing out of all accounts. Please try again."
|
|
1042
1043
|
},
|
|
1043
1044
|
"confirms": {
|
|
1044
1045
|
"signOut": "Are you sure you want to sign out?",
|
|
@@ -1057,7 +1058,9 @@
|
|
|
1057
1058
|
"signIn": "Sign In",
|
|
1058
1059
|
"signOut": "Sign Out",
|
|
1059
1060
|
"verify": "Verify",
|
|
1060
|
-
"resetPassword": "Reset Password"
|
|
1061
|
+
"resetPassword": "Reset Password",
|
|
1062
|
+
"signedOut": "Signed out",
|
|
1063
|
+
"close": "Close"
|
|
1061
1064
|
},
|
|
1062
1065
|
"cancel": "Cancel",
|
|
1063
1066
|
"revoke": "Revoke",
|
|
@@ -1495,5 +1498,16 @@
|
|
|
1495
1498
|
"revoked": "Revoked access for {{name}}",
|
|
1496
1499
|
"revokeFailed": "Failed to revoke access"
|
|
1497
1500
|
}
|
|
1501
|
+
},
|
|
1502
|
+
"accountMenu": {
|
|
1503
|
+
"label": "Account menu",
|
|
1504
|
+
"manage": "Manage your Oxy Account",
|
|
1505
|
+
"addAnother": "Add another account",
|
|
1506
|
+
"signOutAll": "Sign out of all accounts",
|
|
1507
|
+
"open": "Account menu",
|
|
1508
|
+
"openHint": "Opens the account menu",
|
|
1509
|
+
"openWithUser": "Account menu for {{name}}",
|
|
1510
|
+
"switching": "Switching account…",
|
|
1511
|
+
"signOutAccount": "Sign out {{name}}"
|
|
1498
1512
|
}
|
|
1499
|
-
}
|
|
1513
|
+
}
|
|
@@ -281,7 +281,9 @@
|
|
|
281
281
|
"signIn": "Entrar",
|
|
282
282
|
"signOut": "Cerrar sesión",
|
|
283
283
|
"verify": "Verificar",
|
|
284
|
-
"resetPassword": "Restablecer contraseña"
|
|
284
|
+
"resetPassword": "Restablecer contraseña",
|
|
285
|
+
"signedOut": "Sesión cerrada",
|
|
286
|
+
"close": "Cerrar"
|
|
285
287
|
},
|
|
286
288
|
"cancel": "Cancelar",
|
|
287
289
|
"revoke": "Revocar",
|
|
@@ -302,7 +304,8 @@
|
|
|
302
304
|
"confirmPassword": "Confirmar contraseña"
|
|
303
305
|
},
|
|
304
306
|
"errors": {
|
|
305
|
-
"signOutFailed": "Hubo un problema al cerrar sesión. Inténtalo de nuevo."
|
|
307
|
+
"signOutFailed": "Hubo un problema al cerrar sesión. Inténtalo de nuevo.",
|
|
308
|
+
"signOutAllFailed": "Hubo un problema al cerrar sesión en todas las cuentas. Inténtalo de nuevo."
|
|
306
309
|
},
|
|
307
310
|
"confirms": {
|
|
308
311
|
"signOut": "¿Seguro que quieres cerrar sesión?",
|
|
@@ -1495,5 +1498,16 @@
|
|
|
1495
1498
|
"revoked": "Acceso revocado para {{name}}",
|
|
1496
1499
|
"revokeFailed": "No se ha podido revocar el acceso"
|
|
1497
1500
|
}
|
|
1501
|
+
},
|
|
1502
|
+
"accountMenu": {
|
|
1503
|
+
"label": "Menú de cuenta",
|
|
1504
|
+
"manage": "Gestiona tu cuenta de Oxy",
|
|
1505
|
+
"addAnother": "Añadir otra cuenta",
|
|
1506
|
+
"signOutAll": "Cerrar sesión en todas las cuentas",
|
|
1507
|
+
"open": "Menú de cuenta",
|
|
1508
|
+
"openHint": "Abre el menú de cuenta",
|
|
1509
|
+
"openWithUser": "Menú de cuenta de {{name}}",
|
|
1510
|
+
"switching": "Cambiando de cuenta…",
|
|
1511
|
+
"signOutAccount": "Cerrar sesión de {{name}}"
|
|
1498
1512
|
}
|
|
1499
1513
|
}
|
|
@@ -103,7 +103,9 @@
|
|
|
103
103
|
"createAccount": "Créer un compte",
|
|
104
104
|
"signIn": "Se connecter",
|
|
105
105
|
"verify": "Vérifier",
|
|
106
|
-
"resetPassword": "Réinitialiser le mot de passe"
|
|
106
|
+
"resetPassword": "Réinitialiser le mot de passe",
|
|
107
|
+
"signedOut": "Déconnecté",
|
|
108
|
+
"close": "Fermer"
|
|
107
109
|
},
|
|
108
110
|
"links": {
|
|
109
111
|
"recoverAccount": "Récupérer votre compte",
|
|
@@ -115,7 +117,10 @@
|
|
|
115
117
|
"password": "Mot de passe",
|
|
116
118
|
"confirmPassword": "Confirmer le mot de passe"
|
|
117
119
|
},
|
|
118
|
-
"revoke": "Revoke"
|
|
120
|
+
"revoke": "Revoke",
|
|
121
|
+
"errors": {
|
|
122
|
+
"signOutAllFailed": "Un problème est survenu lors de la déconnexion de tous les comptes. Veuillez réessayer."
|
|
123
|
+
}
|
|
119
124
|
},
|
|
120
125
|
"notifications": {
|
|
121
126
|
"title": "Notifications",
|
|
@@ -198,5 +203,16 @@
|
|
|
198
203
|
"revoked": "Revoked access for {{name}}",
|
|
199
204
|
"revokeFailed": "Failed to revoke access"
|
|
200
205
|
}
|
|
206
|
+
},
|
|
207
|
+
"accountMenu": {
|
|
208
|
+
"label": "Menu du compte",
|
|
209
|
+
"manage": "Gérer votre compte Oxy",
|
|
210
|
+
"addAnother": "Ajouter un autre compte",
|
|
211
|
+
"signOutAll": "Se déconnecter de tous les comptes",
|
|
212
|
+
"open": "Menu du compte",
|
|
213
|
+
"openHint": "Ouvre le menu du compte",
|
|
214
|
+
"openWithUser": "Menu du compte de {{name}}",
|
|
215
|
+
"switching": "Changement de compte…",
|
|
216
|
+
"signOutAccount": "Déconnecter {{name}}"
|
|
201
217
|
}
|
|
202
218
|
}
|
|
@@ -103,7 +103,9 @@
|
|
|
103
103
|
"createAccount": "Crea account",
|
|
104
104
|
"signIn": "Accedi",
|
|
105
105
|
"verify": "Verifica",
|
|
106
|
-
"resetPassword": "Reimposta password"
|
|
106
|
+
"resetPassword": "Reimposta password",
|
|
107
|
+
"signedOut": "Disconnesso",
|
|
108
|
+
"close": "Chiudi"
|
|
107
109
|
},
|
|
108
110
|
"links": {
|
|
109
111
|
"recoverAccount": "Recupera il tuo account",
|
|
@@ -115,7 +117,10 @@
|
|
|
115
117
|
"password": "Password",
|
|
116
118
|
"confirmPassword": "Conferma password"
|
|
117
119
|
},
|
|
118
|
-
"revoke": "Revoke"
|
|
120
|
+
"revoke": "Revoke",
|
|
121
|
+
"errors": {
|
|
122
|
+
"signOutAllFailed": "Si è verificato un problema durante la disconnessione da tutti gli account. Riprova."
|
|
123
|
+
}
|
|
119
124
|
},
|
|
120
125
|
"notifications": {
|
|
121
126
|
"title": "Notifications",
|
|
@@ -198,5 +203,16 @@
|
|
|
198
203
|
"revoked": "Revoked access for {{name}}",
|
|
199
204
|
"revokeFailed": "Failed to revoke access"
|
|
200
205
|
}
|
|
206
|
+
},
|
|
207
|
+
"accountMenu": {
|
|
208
|
+
"label": "Menu account",
|
|
209
|
+
"manage": "Gestisci il tuo account Oxy",
|
|
210
|
+
"addAnother": "Aggiungi un altro account",
|
|
211
|
+
"signOutAll": "Esci da tutti gli account",
|
|
212
|
+
"open": "Menu account",
|
|
213
|
+
"openHint": "Apre il menu dell'account",
|
|
214
|
+
"openWithUser": "Menu dell'account di {{name}}",
|
|
215
|
+
"switching": "Cambio account in corso…",
|
|
216
|
+
"signOutAccount": "Esci da {{name}}"
|
|
201
217
|
}
|
|
202
218
|
}
|
|
@@ -103,7 +103,9 @@
|
|
|
103
103
|
"createAccount": "アカウントを作成",
|
|
104
104
|
"signIn": "サインイン",
|
|
105
105
|
"verify": "確認",
|
|
106
|
-
"resetPassword": "パスワードをリセット"
|
|
106
|
+
"resetPassword": "パスワードをリセット",
|
|
107
|
+
"signedOut": "ログアウトしました",
|
|
108
|
+
"close": "閉じる"
|
|
107
109
|
},
|
|
108
110
|
"links": {
|
|
109
111
|
"recoverAccount": "アカウントを回復",
|
|
@@ -115,7 +117,10 @@
|
|
|
115
117
|
"password": "パスワード",
|
|
116
118
|
"confirmPassword": "パスワードを確認"
|
|
117
119
|
},
|
|
118
|
-
"revoke": "Revoke"
|
|
120
|
+
"revoke": "Revoke",
|
|
121
|
+
"errors": {
|
|
122
|
+
"signOutAllFailed": "すべてのアカウントからのログアウト中に問題が発生しました。もう一度お試しください。"
|
|
123
|
+
}
|
|
119
124
|
},
|
|
120
125
|
"notifications": {
|
|
121
126
|
"title": "Notifications",
|
|
@@ -198,5 +203,16 @@
|
|
|
198
203
|
"revoked": "Revoked access for {{name}}",
|
|
199
204
|
"revokeFailed": "Failed to revoke access"
|
|
200
205
|
}
|
|
206
|
+
},
|
|
207
|
+
"accountMenu": {
|
|
208
|
+
"label": "アカウントメニュー",
|
|
209
|
+
"manage": "Oxy アカウントを管理",
|
|
210
|
+
"addAnother": "別のアカウントを追加",
|
|
211
|
+
"signOutAll": "すべてのアカウントからログアウト",
|
|
212
|
+
"open": "アカウントメニュー",
|
|
213
|
+
"openHint": "アカウントメニューを開きます",
|
|
214
|
+
"openWithUser": "{{name}} のアカウントメニュー",
|
|
215
|
+
"switching": "アカウントを切り替えています…",
|
|
216
|
+
"signOutAccount": "{{name}} をログアウト"
|
|
201
217
|
}
|
|
202
218
|
}
|
|
@@ -103,7 +103,9 @@
|
|
|
103
103
|
"createAccount": "계정 만들기",
|
|
104
104
|
"signIn": "로그인",
|
|
105
105
|
"verify": "확인",
|
|
106
|
-
"resetPassword": "비밀번호 재설정"
|
|
106
|
+
"resetPassword": "비밀번호 재설정",
|
|
107
|
+
"signedOut": "로그아웃됨",
|
|
108
|
+
"close": "닫기"
|
|
107
109
|
},
|
|
108
110
|
"links": {
|
|
109
111
|
"recoverAccount": "계정 복구",
|
|
@@ -115,7 +117,10 @@
|
|
|
115
117
|
"password": "비밀번호",
|
|
116
118
|
"confirmPassword": "비밀번호 확인"
|
|
117
119
|
},
|
|
118
|
-
"revoke": "Revoke"
|
|
120
|
+
"revoke": "Revoke",
|
|
121
|
+
"errors": {
|
|
122
|
+
"signOutAllFailed": "모든 계정에서 로그아웃하는 중 문제가 발생했습니다. 다시 시도해 주세요."
|
|
123
|
+
}
|
|
119
124
|
},
|
|
120
125
|
"notifications": {
|
|
121
126
|
"title": "Notifications",
|
|
@@ -198,5 +203,16 @@
|
|
|
198
203
|
"revoked": "Revoked access for {{name}}",
|
|
199
204
|
"revokeFailed": "Failed to revoke access"
|
|
200
205
|
}
|
|
206
|
+
},
|
|
207
|
+
"accountMenu": {
|
|
208
|
+
"label": "계정 메뉴",
|
|
209
|
+
"manage": "Oxy 계정 관리",
|
|
210
|
+
"addAnother": "다른 계정 추가",
|
|
211
|
+
"signOutAll": "모든 계정에서 로그아웃",
|
|
212
|
+
"open": "계정 메뉴",
|
|
213
|
+
"openHint": "계정 메뉴를 엽니다",
|
|
214
|
+
"openWithUser": "{{name}}의 계정 메뉴",
|
|
215
|
+
"switching": "계정 전환 중…",
|
|
216
|
+
"signOutAccount": "{{name}} 로그아웃"
|
|
201
217
|
}
|
|
202
218
|
}
|
|
@@ -103,7 +103,9 @@
|
|
|
103
103
|
"createAccount": "Criar conta",
|
|
104
104
|
"signIn": "Iniciar sessão",
|
|
105
105
|
"verify": "Verificar",
|
|
106
|
-
"resetPassword": "Repor palavra-passe"
|
|
106
|
+
"resetPassword": "Repor palavra-passe",
|
|
107
|
+
"signedOut": "Sessão terminada",
|
|
108
|
+
"close": "Fechar"
|
|
107
109
|
},
|
|
108
110
|
"links": {
|
|
109
111
|
"recoverAccount": "Recuperar a sua conta",
|
|
@@ -115,7 +117,10 @@
|
|
|
115
117
|
"password": "Palavra-passe",
|
|
116
118
|
"confirmPassword": "Confirmar palavra-passe"
|
|
117
119
|
},
|
|
118
|
-
"revoke": "Revoke"
|
|
120
|
+
"revoke": "Revoke",
|
|
121
|
+
"errors": {
|
|
122
|
+
"signOutAllFailed": "Ocorreu um problema ao terminar sessão em todas as contas. Tente novamente."
|
|
123
|
+
}
|
|
119
124
|
},
|
|
120
125
|
"notifications": {
|
|
121
126
|
"title": "Notifications",
|
|
@@ -198,5 +203,16 @@
|
|
|
198
203
|
"revoked": "Revoked access for {{name}}",
|
|
199
204
|
"revokeFailed": "Failed to revoke access"
|
|
200
205
|
}
|
|
206
|
+
},
|
|
207
|
+
"accountMenu": {
|
|
208
|
+
"label": "Menu da conta",
|
|
209
|
+
"manage": "Gerir a sua conta Oxy",
|
|
210
|
+
"addAnother": "Adicionar outra conta",
|
|
211
|
+
"signOutAll": "Terminar sessão em todas as contas",
|
|
212
|
+
"open": "Menu da conta",
|
|
213
|
+
"openHint": "Abre o menu da conta",
|
|
214
|
+
"openWithUser": "Menu da conta de {{name}}",
|
|
215
|
+
"switching": "A mudar de conta…",
|
|
216
|
+
"signOutAccount": "Terminar sessão de {{name}}"
|
|
201
217
|
}
|
|
202
218
|
}
|