@oxyhq/core 12.9.0 → 12.10.1
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/HttpService.js +22 -12
- package/dist/cjs/crypto/keyManager.js +89 -0
- package/dist/cjs/i18n/locales/ar-SA.json +4 -0
- package/dist/cjs/i18n/locales/ca-ES.json +4 -0
- package/dist/cjs/i18n/locales/de-DE.json +4 -0
- package/dist/cjs/i18n/locales/en-US.json +69 -3
- package/dist/cjs/i18n/locales/es-ES.json +68 -2
- package/dist/cjs/i18n/locales/fr-FR.json +4 -0
- package/dist/cjs/i18n/locales/it-IT.json +4 -0
- package/dist/cjs/i18n/locales/ja-JP.json +4 -0
- package/dist/cjs/i18n/locales/ko-KR.json +4 -0
- package/dist/cjs/i18n/locales/locales/ar-SA.json +4 -0
- package/dist/cjs/i18n/locales/locales/ca-ES.json +4 -0
- package/dist/cjs/i18n/locales/locales/de-DE.json +4 -0
- package/dist/cjs/i18n/locales/locales/en-US.json +69 -3
- package/dist/cjs/i18n/locales/locales/es-ES.json +68 -2
- package/dist/cjs/i18n/locales/locales/fr-FR.json +4 -0
- package/dist/cjs/i18n/locales/locales/it-IT.json +4 -0
- package/dist/cjs/i18n/locales/locales/ja-JP.json +4 -0
- package/dist/cjs/i18n/locales/locales/ko-KR.json +4 -0
- package/dist/cjs/i18n/locales/locales/pt-PT.json +4 -0
- package/dist/cjs/i18n/locales/locales/zh-CN.json +4 -0
- package/dist/cjs/i18n/locales/pt-PT.json +4 -0
- package/dist/cjs/i18n/locales/zh-CN.json +4 -0
- package/dist/cjs/index.js +7 -4
- package/dist/cjs/mixins/OxyServices.auth.js +51 -20
- package/dist/cjs/mixins/OxyServices.connectedApps.js +6 -1
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +9 -2
- package/dist/cjs/mixins/OxyServices.identityBackup.js +11 -0
- package/dist/cjs/mixins/OxyServices.user.js +6 -0
- package/dist/cjs/session/accountDialogController.js +7 -5
- package/dist/cjs/utils/commonsApproval.js +31 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/HttpService.js +22 -12
- package/dist/esm/crypto/keyManager.js +89 -0
- package/dist/esm/i18n/locales/ar-SA.json +4 -0
- package/dist/esm/i18n/locales/ca-ES.json +4 -0
- package/dist/esm/i18n/locales/de-DE.json +4 -0
- package/dist/esm/i18n/locales/en-US.json +69 -3
- package/dist/esm/i18n/locales/es-ES.json +68 -2
- package/dist/esm/i18n/locales/fr-FR.json +4 -0
- package/dist/esm/i18n/locales/it-IT.json +4 -0
- package/dist/esm/i18n/locales/ja-JP.json +4 -0
- package/dist/esm/i18n/locales/ko-KR.json +4 -0
- package/dist/esm/i18n/locales/locales/ar-SA.json +4 -0
- package/dist/esm/i18n/locales/locales/ca-ES.json +4 -0
- package/dist/esm/i18n/locales/locales/de-DE.json +4 -0
- package/dist/esm/i18n/locales/locales/en-US.json +69 -3
- package/dist/esm/i18n/locales/locales/es-ES.json +68 -2
- package/dist/esm/i18n/locales/locales/fr-FR.json +4 -0
- package/dist/esm/i18n/locales/locales/it-IT.json +4 -0
- package/dist/esm/i18n/locales/locales/ja-JP.json +4 -0
- package/dist/esm/i18n/locales/locales/ko-KR.json +4 -0
- package/dist/esm/i18n/locales/locales/pt-PT.json +4 -0
- package/dist/esm/i18n/locales/locales/zh-CN.json +4 -0
- package/dist/esm/i18n/locales/pt-PT.json +4 -0
- package/dist/esm/i18n/locales/zh-CN.json +4 -0
- package/dist/esm/index.js +2 -1
- package/dist/esm/mixins/OxyServices.auth.js +48 -19
- package/dist/esm/mixins/OxyServices.connectedApps.js +6 -1
- package/dist/esm/mixins/OxyServices.deviceBoot.js +9 -2
- package/dist/esm/mixins/OxyServices.identityBackup.js +11 -0
- package/dist/esm/mixins/OxyServices.user.js +6 -0
- package/dist/esm/session/accountDialogController.js +7 -5
- package/dist/esm/utils/commonsApproval.js +27 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/HttpService.d.ts +14 -0
- package/dist/types/crypto/keyManager.d.ts +33 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/mixins/OxyServices.auth.d.ts +4 -4
- package/dist/types/session/accountDialogController.d.ts +7 -2
- package/dist/types/utils/commonsApproval.d.ts +13 -0
- package/package.json +3 -3
- package/src/HttpService.ts +37 -14
- package/src/__tests__/httpServiceAuthSelfAwait.test.ts +108 -0
- package/src/__tests__/httpServiceQueueDeadlock.test.ts +128 -0
- package/src/crypto/__tests__/keyManager.recoveryMnemonic.test.ts +138 -0
- package/src/crypto/keyManager.ts +99 -0
- package/src/i18n/locales/ar-SA.json +4 -0
- package/src/i18n/locales/ca-ES.json +4 -0
- package/src/i18n/locales/de-DE.json +4 -0
- package/src/i18n/locales/en-US.json +69 -3
- package/src/i18n/locales/es-ES.json +68 -2
- package/src/i18n/locales/fr-FR.json +4 -0
- package/src/i18n/locales/it-IT.json +4 -0
- package/src/i18n/locales/ja-JP.json +4 -0
- package/src/i18n/locales/ko-KR.json +4 -0
- package/src/i18n/locales/pt-PT.json +4 -0
- package/src/i18n/locales/zh-CN.json +4 -0
- package/src/index.ts +7 -1
- package/src/mixins/OxyServices.auth.ts +48 -24
- package/src/mixins/OxyServices.connectedApps.ts +6 -1
- package/src/mixins/OxyServices.deviceBoot.ts +7 -2
- package/src/mixins/OxyServices.identityBackup.ts +13 -0
- package/src/mixins/OxyServices.user.ts +6 -0
- package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +4 -2
- package/src/mixins/__tests__/commonsSignIn.test.ts +4 -4
- package/src/mixins/__tests__/identityBackup.test.ts +57 -0
- package/src/mixins/__tests__/preSessionSkipAuth.test.ts +152 -0
- package/src/mixins/__tests__/privacyCacheInvalidation.test.ts +6 -0
- package/src/mixins/__tests__/webauthnAuth.test.ts +6 -6
- package/src/session/__tests__/accountDialogController.test.ts +3 -3
- package/src/session/accountDialogController.ts +7 -6
- package/src/utils/__tests__/commonsApproval.test.ts +60 -0
- package/src/utils/commonsApproval.ts +39 -0
|
@@ -163,7 +163,7 @@ describe('AccountDialogController — initial + views', () => {
|
|
|
163
163
|
expect(snap.commonsAvailability).toBe('unknown');
|
|
164
164
|
});
|
|
165
165
|
|
|
166
|
-
it('setView / add
|
|
166
|
+
it('setView / add move between views and notify subscribers', () => {
|
|
167
167
|
const { controller } = makeHarness();
|
|
168
168
|
const seen: string[] = [];
|
|
169
169
|
controller.subscribe((s) => seen.push(s.view));
|
|
@@ -172,7 +172,7 @@ describe('AccountDialogController — initial + views', () => {
|
|
|
172
172
|
expect(controller.getSnapshot().view).toBe('add');
|
|
173
173
|
controller.setView('signin');
|
|
174
174
|
expect(controller.getSnapshot().view).toBe('signin');
|
|
175
|
-
controller.
|
|
175
|
+
controller.setView('accounts');
|
|
176
176
|
expect(controller.getSnapshot().view).toBe('accounts');
|
|
177
177
|
|
|
178
178
|
expect(seen).toEqual(['add', 'signin', 'accounts']);
|
|
@@ -185,7 +185,7 @@ describe('AccountDialogController — initial + views', () => {
|
|
|
185
185
|
|
|
186
186
|
controller.startSignup();
|
|
187
187
|
expect(controller.getSnapshot().view).toBe('signup');
|
|
188
|
-
controller.
|
|
188
|
+
controller.setView('accounts');
|
|
189
189
|
expect(controller.getSnapshot().view).toBe('accounts');
|
|
190
190
|
|
|
191
191
|
expect(seen).toEqual(['signup', 'accounts']);
|
|
@@ -35,6 +35,13 @@
|
|
|
35
35
|
* password, social login, and 2FA were removed ecosystem-wide. Account
|
|
36
36
|
* creation (`signup` view) is the same two identity backends: a passkey
|
|
37
37
|
* ceremony on web, or a Commons-created identity.
|
|
38
|
+
*
|
|
39
|
+
* The controller owns NO surface PRESENTATION: whether the account dialog is
|
|
40
|
+
* mounted, visible, or dismissed is the job of the shared surface stack
|
|
41
|
+
* (`@oxyhq/services` presents the `AccountDialog` surface into `@oxyhq/bloom`'s
|
|
42
|
+
* stack). This is a headless state machine only — it exposes `setView` /
|
|
43
|
+
* `add` / `startSignup` (the view axis) and `cancelSignIn` (device-flow
|
|
44
|
+
* teardown), never an `open` / `close` / `visible`.
|
|
38
45
|
*/
|
|
39
46
|
|
|
40
47
|
import type { OxyServices } from '../OxyServices';
|
|
@@ -462,12 +469,6 @@ export class AccountDialogController {
|
|
|
462
469
|
this.emit();
|
|
463
470
|
}
|
|
464
471
|
|
|
465
|
-
/** Return to the account list and cancel any in-flight sign-in flow. */
|
|
466
|
-
close(): void {
|
|
467
|
-
this.cancelSignIn();
|
|
468
|
-
this.setView('accounts');
|
|
469
|
-
}
|
|
470
|
-
|
|
471
472
|
/** Switch to the "add account" view (the sign-in entry chooser). */
|
|
472
473
|
add(): void {
|
|
473
474
|
this.setView('add');
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCommonsApprovalBlockingReason,
|
|
3
|
+
parseCommonsApprovalExpiresAt,
|
|
4
|
+
} from '../commonsApproval';
|
|
5
|
+
|
|
6
|
+
describe('commonsApproval validation', () => {
|
|
7
|
+
const application = {
|
|
8
|
+
id: 'app1',
|
|
9
|
+
name: 'Mention',
|
|
10
|
+
type: 'first_party' as const,
|
|
11
|
+
isOfficial: true,
|
|
12
|
+
isInternal: false,
|
|
13
|
+
scopes: ['profile'],
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
it('blocks when the application is missing', () => {
|
|
17
|
+
expect(
|
|
18
|
+
getCommonsApprovalBlockingReason({
|
|
19
|
+
application: null,
|
|
20
|
+
status: 'pending',
|
|
21
|
+
expiresAt: Date.now() + 60_000,
|
|
22
|
+
}),
|
|
23
|
+
).toMatch(/could not be resolved/i);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('blocks non-pending sessions', () => {
|
|
27
|
+
expect(
|
|
28
|
+
getCommonsApprovalBlockingReason({
|
|
29
|
+
application,
|
|
30
|
+
status: 'expired',
|
|
31
|
+
expiresAt: Date.now() + 60_000,
|
|
32
|
+
}),
|
|
33
|
+
).toMatch(/invalid, already used, or expired/i);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('blocks expired pending sessions (ISO expiresAt)', () => {
|
|
37
|
+
expect(
|
|
38
|
+
getCommonsApprovalBlockingReason({
|
|
39
|
+
application,
|
|
40
|
+
status: 'pending',
|
|
41
|
+
expiresAt: new Date(Date.now() - 60_000).toISOString(),
|
|
42
|
+
}),
|
|
43
|
+
).toMatch(/expired/i);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('allows a pending, unexpired session', () => {
|
|
47
|
+
expect(
|
|
48
|
+
getCommonsApprovalBlockingReason({
|
|
49
|
+
application,
|
|
50
|
+
status: 'pending',
|
|
51
|
+
expiresAt: Date.now() + 60_000,
|
|
52
|
+
}),
|
|
53
|
+
).toBeNull();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('parses ISO expiresAt strings', () => {
|
|
57
|
+
const iso = '2026-07-19T12:00:00.000Z';
|
|
58
|
+
expect(parseCommonsApprovalExpiresAt(iso)).toBe(Date.parse(iso));
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PublicApplication } from '../mixins/OxyServices.connectedApps';
|
|
2
|
+
|
|
3
|
+
export interface CommonsApprovalValidationInput {
|
|
4
|
+
application: PublicApplication | null;
|
|
5
|
+
status: string;
|
|
6
|
+
expiresAt: number | string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns a user-facing blocking reason when an approval payload must not be
|
|
11
|
+
* shown as actionable, or `null` when the request is still pending and valid.
|
|
12
|
+
*/
|
|
13
|
+
export function getCommonsApprovalBlockingReason(
|
|
14
|
+
info: CommonsApprovalValidationInput,
|
|
15
|
+
): string | null {
|
|
16
|
+
if (!info.application?.id) {
|
|
17
|
+
return 'The requesting application could not be resolved.';
|
|
18
|
+
}
|
|
19
|
+
if (info.status !== 'pending') {
|
|
20
|
+
return 'This sign-in request is invalid, already used, or expired.';
|
|
21
|
+
}
|
|
22
|
+
const expiresAtMs = parseCommonsApprovalExpiresAt(info.expiresAt);
|
|
23
|
+
if (expiresAtMs !== null && expiresAtMs < Date.now()) {
|
|
24
|
+
return 'This sign-in request has expired. Ask for a new QR code.';
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Normalize API `expiresAt` (number or ISO string) to epoch ms. */
|
|
30
|
+
export function parseCommonsApprovalExpiresAt(
|
|
31
|
+
expiresAt: CommonsApprovalValidationInput['expiresAt'],
|
|
32
|
+
): number | null {
|
|
33
|
+
if (typeof expiresAt === 'number' && Number.isFinite(expiresAt)) return expiresAt;
|
|
34
|
+
if (typeof expiresAt === 'string') {
|
|
35
|
+
const ms = Date.parse(expiresAt);
|
|
36
|
+
return Number.isFinite(ms) ? ms : null;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|