@oxy.so/core 4.5.0-oxy-one.1 → 4.5.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/README.md +1 -1
- package/dist/cjs/HttpService.js +63 -19
- package/dist/cjs/api/accounts.js +10 -3
- package/dist/cjs/api/agency.js +3 -1
- package/dist/cjs/api/apps.js +15 -4
- package/dist/cjs/api/assets.js +39 -11
- package/dist/cjs/api/auth.js +28 -8
- package/dist/cjs/api/billing.js +24 -7
- package/dist/cjs/api/civic.js +14 -4
- package/dist/cjs/api/follows.js +9 -2
- package/dist/cjs/api/identity.js +31 -9
- package/dist/cjs/api/nodes.js +3 -1
- package/dist/cjs/api/privacy.js +8 -2
- package/dist/cjs/api/session.js +15 -4
- package/dist/cjs/api/store.js +15 -5
- package/dist/cjs/api/topics.js +10 -3
- package/dist/cjs/api/users.js +16 -4
- package/dist/cjs/boot/sessionColdBoot.js +40 -13
- package/dist/cjs/constants/version.js +6 -6
- package/dist/cjs/crypto/identityMarker.js +3 -1
- package/dist/cjs/crypto/identityProof.js +6 -1
- package/dist/cjs/crypto/keyManager.js +87 -32
- package/dist/cjs/crypto/recoveryPhrase.js +2 -2
- package/dist/cjs/crypto/signatureService.js +3 -4
- package/dist/cjs/i18n/index.js +16 -3
- package/dist/cjs/i18n/locales/ar-SA.js +366 -366
- package/dist/cjs/i18n/locales/ca-ES.js +366 -366
- package/dist/cjs/i18n/locales/de-DE.js +366 -366
- package/dist/cjs/i18n/locales/en-US.js +1994 -1994
- package/dist/cjs/i18n/locales/es-ES.js +1994 -1994
- package/dist/cjs/i18n/locales/fr-FR.js +366 -366
- package/dist/cjs/i18n/locales/it-IT.js +366 -366
- package/dist/cjs/i18n/locales/ja-JP.js +366 -366
- package/dist/cjs/i18n/locales/ko-KR.js +366 -366
- package/dist/cjs/i18n/locales/pt-PT.js +366 -366
- package/dist/cjs/i18n/locales/zh-CN.js +366 -366
- package/dist/cjs/inference/OxyInferenceClient.js +12 -18
- package/dist/cjs/models/interfaces.js +11 -11
- package/dist/cjs/server/OxyServer.js +86 -28
- package/dist/cjs/server/agentAccount.js +6 -2
- package/dist/cjs/server/aliaMachineCredential.js +39 -14
- package/dist/cjs/server/auth.js +5 -4
- package/dist/cjs/server/capabilityTicket.js +5 -5
- package/dist/cjs/server/index.js +2 -1
- package/dist/cjs/server/liveCapabilityTicket.js +4 -1
- package/dist/cjs/server/middleware.js +61 -42
- package/dist/cjs/server/namespaces.js +28 -7
- package/dist/cjs/server/requesterAssertion.js +36 -30
- package/dist/cjs/server/serviceTokenLifetime.js +7 -4
- package/dist/cjs/server/traffic.js +53 -14
- package/dist/cjs/server/trafficNodeHttp.js +33 -8
- package/dist/cjs/server/workloadIdentity.client.js +4 -0
- package/dist/cjs/server/workloadIdentity.js +28 -1
- package/dist/cjs/session/SessionClient.js +54 -17
- package/dist/cjs/session/accountDelegationAccess.js +4 -6
- package/dist/cjs/session/accountDialogController.js +1 -1
- package/dist/cjs/session/authStateStore.js +18 -9
- package/dist/cjs/session/identityPin.js +6 -2
- package/dist/cjs/session/refresh.js +81 -23
- package/dist/cjs/session/sharedDeviceCredential.js +28 -15
- package/dist/cjs/shared/utils/errorUtils.js +1 -1
- package/dist/cjs/shared/utils/networkUtils.js +1 -1
- package/dist/cjs/shared/utils/themeUtils.js +1 -1
- package/dist/cjs/utils/accountCacheSweep.js +3 -1
- package/dist/cjs/utils/accountUtils.js +1 -3
- package/dist/cjs/utils/asyncUtils.js +1 -1
- package/dist/cjs/utils/authHelpers.js +2 -1
- package/dist/cjs/utils/avatarUtils.js +4 -2
- package/dist/cjs/utils/cache.js +1 -1
- package/dist/cjs/utils/cacheKey.js +3 -1
- package/dist/cjs/utils/deviceManager.js +4 -4
- package/dist/cjs/utils/errorUtils.js +6 -4
- package/dist/cjs/utils/languageUtils.js +404 -57
- package/dist/cjs/utils/profileLinks.js +1 -3
- package/dist/cjs/utils/requestUtils.js +7 -1
- package/dist/cjs/utils/userIdentity.js +1 -1
- package/dist/cjs/utils/validationUtils.js +5 -6
- package/dist/esm/HttpService.js +64 -20
- package/dist/esm/api/accounts.js +11 -4
- package/dist/esm/api/agency.js +3 -1
- package/dist/esm/api/apps.js +15 -4
- package/dist/esm/api/assets.js +39 -11
- package/dist/esm/api/auth.js +28 -8
- package/dist/esm/api/billing.js +25 -8
- package/dist/esm/api/civic.js +14 -4
- package/dist/esm/api/follows.js +9 -2
- package/dist/esm/api/identity.js +31 -9
- package/dist/esm/api/nodes.js +3 -1
- package/dist/esm/api/privacy.js +8 -2
- package/dist/esm/api/session.js +15 -4
- package/dist/esm/api/store.js +15 -5
- package/dist/esm/api/topics.js +10 -3
- package/dist/esm/api/users.js +16 -4
- package/dist/esm/boot/sessionColdBoot.js +41 -14
- package/dist/esm/constants/version.js +6 -6
- package/dist/esm/crypto/identityMarker.js +3 -1
- package/dist/esm/crypto/identityProof.js +6 -1
- package/dist/esm/crypto/internal.js +1 -1
- package/dist/esm/crypto/keyManager.js +87 -32
- package/dist/esm/crypto/recoveryPhrase.js +2 -2
- package/dist/esm/crypto/signatureService.js +3 -4
- package/dist/esm/i18n/index.js +16 -3
- package/dist/esm/i18n/locales/ar-SA.js +366 -366
- package/dist/esm/i18n/locales/ca-ES.js +366 -366
- package/dist/esm/i18n/locales/de-DE.js +366 -366
- package/dist/esm/i18n/locales/en-US.js +1994 -1994
- package/dist/esm/i18n/locales/es-ES.js +1994 -1994
- package/dist/esm/i18n/locales/fr-FR.js +366 -366
- package/dist/esm/i18n/locales/it-IT.js +366 -366
- package/dist/esm/i18n/locales/ja-JP.js +366 -366
- package/dist/esm/i18n/locales/ko-KR.js +366 -366
- package/dist/esm/i18n/locales/pt-PT.js +366 -366
- package/dist/esm/i18n/locales/zh-CN.js +366 -366
- package/dist/esm/index.js +1 -1
- package/dist/esm/inference/OxyInferenceClient.js +13 -19
- package/dist/esm/models/interfaces.js +11 -11
- package/dist/esm/server/OxyServer.js +87 -29
- package/dist/esm/server/agentAccount.js +6 -2
- package/dist/esm/server/aliaMachineCredential.js +39 -14
- package/dist/esm/server/auth.js +6 -5
- package/dist/esm/server/capabilityTicket.js +6 -6
- package/dist/esm/server/index.js +5 -5
- package/dist/esm/server/liveCapabilityTicket.js +6 -3
- package/dist/esm/server/middleware.js +62 -43
- package/dist/esm/server/namespaces.js +31 -10
- package/dist/esm/server/requesterAssertion.js +36 -30
- package/dist/esm/server/serviceTokenLifetime.js +7 -4
- package/dist/esm/server/traffic.js +55 -16
- package/dist/esm/server/trafficNodeHttp.js +34 -9
- package/dist/esm/server/userInvalidation.js +1 -1
- package/dist/esm/server/workloadIdentity.client.js +3 -0
- package/dist/esm/server/workloadIdentity.js +27 -1
- package/dist/esm/session/SessionClient.js +54 -17
- package/dist/esm/session/accountDelegationAccess.js +5 -7
- package/dist/esm/session/accountDialogController.js +1 -1
- package/dist/esm/session/authStateStore.js +18 -9
- package/dist/esm/session/identityPin.js +6 -2
- package/dist/esm/session/refresh.js +82 -24
- package/dist/esm/session/sharedDeviceCredential.js +28 -15
- package/dist/esm/shared/utils/errorUtils.js +1 -1
- package/dist/esm/shared/utils/networkUtils.js +1 -1
- package/dist/esm/shared/utils/themeUtils.js +1 -1
- package/dist/esm/utils/accountCacheSweep.js +3 -1
- package/dist/esm/utils/accountUtils.js +1 -3
- package/dist/esm/utils/asyncUtils.js +1 -1
- package/dist/esm/utils/authHelpers.js +2 -1
- package/dist/esm/utils/avatarUtils.js +4 -2
- package/dist/esm/utils/cache.js +1 -1
- package/dist/esm/utils/cacheKey.js +3 -1
- package/dist/esm/utils/deviceManager.js +4 -4
- package/dist/esm/utils/errorUtils.js +6 -4
- package/dist/esm/utils/languageUtils.js +404 -57
- package/dist/esm/utils/profileLinks.js +1 -3
- package/dist/esm/utils/requestUtils.js +7 -1
- package/dist/esm/utils/userIdentity.js +1 -1
- package/dist/esm/utils/validationUtils.js +5 -6
- package/dist/types/HttpService.d.ts +1 -1
- package/dist/types/api/accounts.d.ts +1 -1
- package/dist/types/api/apps.d.ts +4 -4
- package/dist/types/crypto/internal.d.ts +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/server/index.d.ts +6 -6
- package/dist/types/server/workloadIdentity.client.d.ts +5 -1
- package/dist/types/server/workloadIdentity.d.ts +26 -0
- package/dist/types/session/accountDelegationAccess.d.ts +1 -1
- package/dist/types/session/index.d.ts +1 -1
- package/dist/types/utils/userIdentity.d.ts +1 -1
- package/dist/types/utils/validationUtils.d.ts +4 -5
- package/package.json +2 -3
- package/src/HttpService.ts +183 -53
- package/src/OxyServices.errors.ts +7 -3
- package/src/OxyServices.ts +6 -2
- package/src/api/accounts.ts +76 -26
- package/src/api/agency.ts +24 -9
- package/src/api/appData.ts +12 -2
- package/src/api/apps.ts +81 -31
- package/src/api/assets.ts +113 -43
- package/src/api/auth.ts +145 -77
- package/src/api/billing.ts +112 -65
- package/src/api/civic.ts +61 -19
- package/src/api/contacts.ts +4 -1
- package/src/api/devices.ts +54 -21
- package/src/api/follows.ts +88 -31
- package/src/api/identity.ts +101 -33
- package/src/api/linkedAccounts.ts +26 -8
- package/src/api/nodes.ts +18 -6
- package/src/api/notifications.ts +26 -6
- package/src/api/privacy.ts +42 -8
- package/src/api/reputation.ts +18 -7
- package/src/api/session.ts +23 -5
- package/src/api/store.ts +81 -31
- package/src/api/topics.ts +18 -6
- package/src/api/users.ts +98 -35
- package/src/boot/sessionColdBoot.ts +60 -19
- package/src/civic/payloads.ts +1 -4
- package/src/client/context.ts +6 -1
- package/src/constants/version.ts +7 -6
- package/src/crypto/aead.ts +1 -5
- package/src/crypto/ecdh.ts +1 -4
- package/src/crypto/identityDerivations.ts +5 -1
- package/src/crypto/identityMarker.ts +3 -1
- package/src/crypto/identityProof.ts +6 -1
- package/src/crypto/index.ts +11 -11
- package/src/crypto/internal.ts +6 -1
- package/src/crypto/keyManager.ts +348 -98
- package/src/crypto/recoveryPhrase.ts +14 -9
- package/src/crypto/registrationPow.ts +1 -1
- package/src/crypto/signatureService.ts +14 -6
- package/src/i18n/accountCategoryLabels.ts +1 -4
- package/src/i18n/accountRoleLabels.ts +1 -4
- package/src/i18n/index.ts +25 -7
- package/src/i18n/locales/ar-SA.ts +375 -366
- package/src/i18n/locales/ca-ES.ts +382 -366
- package/src/i18n/locales/de-DE.ts +387 -366
- package/src/i18n/locales/en-US.ts +2034 -1994
- package/src/i18n/locales/es-ES.ts +2043 -1994
- package/src/i18n/locales/fr-FR.ts +387 -366
- package/src/i18n/locales/it-IT.ts +380 -366
- package/src/i18n/locales/ja-JP.ts +380 -366
- package/src/i18n/locales/ko-KR.ts +377 -366
- package/src/i18n/locales/pt-PT.ts +383 -366
- package/src/i18n/locales/zh-CN.ts +373 -366
- package/src/i18n/trustTierLabels.ts +1 -4
- package/src/index.ts +371 -349
- package/src/inference/OxyInferenceClient.ts +784 -780
- package/src/models/interfaces.ts +30 -27
- package/src/server/OxyServer.ts +227 -68
- package/src/server/agentAccount.ts +8 -2
- package/src/server/aliaMachineCredential.ts +57 -16
- package/src/server/auth.ts +9 -5
- package/src/server/capabilityTicket.ts +30 -21
- package/src/server/index.ts +29 -6
- package/src/server/liveCapabilityTicket.ts +31 -9
- package/src/server/middleware.ts +212 -121
- package/src/server/namespaces.ts +247 -94
- package/src/server/rateLimit.ts +2 -4
- package/src/server/requesterAssertion.ts +93 -54
- package/src/server/serviceTokenLifetime.ts +9 -4
- package/src/server/traffic.ts +117 -23
- package/src/server/trafficNodeHttp.ts +61 -14
- package/src/server/userInvalidation.ts +1 -4
- package/src/server/workloadIdentity.client.ts +12 -1
- package/src/server/workloadIdentity.ts +52 -5
- package/src/session/SessionClient.ts +170 -49
- package/src/session/accountDelegationAccess.ts +24 -31
- package/src/session/accountDialogController.ts +59 -14
- package/src/session/accountSwitchTargets.ts +10 -15
- package/src/session/authStateStore.ts +121 -81
- package/src/session/deviceDirectory.ts +1 -3
- package/src/session/identityPin.ts +10 -11
- package/src/session/identitySession.ts +3 -1
- package/src/session/index.ts +87 -82
- package/src/session/refresh.ts +138 -44
- package/src/session/sessionClientHost.ts +1 -3
- package/src/session/sharedDeviceCredential.ts +35 -14
- package/src/session/socketLoader.ts +9 -2
- package/src/shared/utils/errorUtils.ts +5 -2
- package/src/shared/utils/networkUtils.ts +5 -8
- package/src/shared/utils/themeUtils.ts +2 -6
- package/src/types/buffer.d.ts +66 -21
- package/src/types/expo-secure-store.d.ts +5 -1
- package/src/utils/accountCacheSweep.ts +4 -5
- package/src/utils/accountUtils.ts +107 -108
- package/src/utils/apiUtils.ts +3 -3
- package/src/utils/asyncUtils.ts +2 -2
- package/src/utils/authHelpers.ts +10 -5
- package/src/utils/avatarUtils.ts +11 -6
- package/src/utils/cache.ts +9 -10
- package/src/utils/cacheKey.ts +5 -1
- package/src/utils/coldBoot.ts +1 -3
- package/src/utils/commonsDelivery.ts +1 -4
- package/src/utils/deviceManager.ts +15 -14
- package/src/utils/errorUtils.ts +68 -86
- package/src/utils/languageUtils.ts +407 -58
- package/src/utils/oauthPkce.ts +1 -4
- package/src/utils/platform.ts +0 -1
- package/src/utils/profileLinks.ts +2 -5
- package/src/utils/requestUtils.ts +18 -14
- package/src/utils/sessionUtils.ts +34 -33
- package/src/utils/userHandle.ts +3 -1
- package/src/utils/userIdentity.ts +1 -1
- package/src/utils/validationUtils.ts +11 -9
package/src/api/privacy.ts
CHANGED
|
@@ -27,9 +27,17 @@ export class PrivacyApi {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/** Update privacy settings (default: the signed-in user's). */
|
|
30
|
-
async updateSettings(
|
|
30
|
+
async updateSettings(
|
|
31
|
+
settings: Partial<PrivacySettings>,
|
|
32
|
+
userId?: string,
|
|
33
|
+
): Promise<PrivacySettings> {
|
|
31
34
|
const id = await this.resolveUserId(userId);
|
|
32
|
-
const res = await this.ctx.request<PrivacySettings>(
|
|
35
|
+
const res = await this.ctx.request<PrivacySettings>(
|
|
36
|
+
'PATCH',
|
|
37
|
+
`/privacy/${id}/privacy`,
|
|
38
|
+
settings,
|
|
39
|
+
{ cache: false },
|
|
40
|
+
);
|
|
33
41
|
// Privacy settings ride the user DTO, so every identity read goes stale too.
|
|
34
42
|
evictOxyIdentityCache(this.ctx.http, id);
|
|
35
43
|
this.ctx.oxy.cache.delete(`GET:/privacy/${id}/privacy`);
|
|
@@ -40,13 +48,21 @@ export class PrivacyApi {
|
|
|
40
48
|
|
|
41
49
|
/** The signed-in user's blocked users. */
|
|
42
50
|
async blocked(): Promise<BlockedUser[]> {
|
|
43
|
-
return this.ctx.request<BlockedUser[]>('GET', '/privacy/blocked', undefined, {
|
|
51
|
+
return this.ctx.request<BlockedUser[]>('GET', '/privacy/blocked', undefined, {
|
|
52
|
+
cache: true,
|
|
53
|
+
cacheTTL: LIST_TTL,
|
|
54
|
+
});
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
/** Block a user. */
|
|
47
58
|
async block(userId: string): Promise<{ message: string }> {
|
|
48
59
|
requireId(userId);
|
|
49
|
-
const res = await this.ctx.request<{ message: string }>(
|
|
60
|
+
const res = await this.ctx.request<{ message: string }>(
|
|
61
|
+
'POST',
|
|
62
|
+
`/privacy/blocked/${userId}`,
|
|
63
|
+
undefined,
|
|
64
|
+
{ cache: false },
|
|
65
|
+
);
|
|
50
66
|
this.invalidate('GET:/privacy/blocked');
|
|
51
67
|
return res;
|
|
52
68
|
}
|
|
@@ -54,7 +70,12 @@ export class PrivacyApi {
|
|
|
54
70
|
/** Unblock a user. */
|
|
55
71
|
async unblock(userId: string): Promise<{ message: string }> {
|
|
56
72
|
requireId(userId);
|
|
57
|
-
const res = await this.ctx.request<{ message: string }>(
|
|
73
|
+
const res = await this.ctx.request<{ message: string }>(
|
|
74
|
+
'DELETE',
|
|
75
|
+
`/privacy/blocked/${userId}`,
|
|
76
|
+
undefined,
|
|
77
|
+
{ cache: false },
|
|
78
|
+
);
|
|
58
79
|
this.invalidate('GET:/privacy/blocked');
|
|
59
80
|
return res;
|
|
60
81
|
}
|
|
@@ -73,13 +94,21 @@ export class PrivacyApi {
|
|
|
73
94
|
|
|
74
95
|
/** The signed-in user's restricted users. */
|
|
75
96
|
async restricted(): Promise<RestrictedUser[]> {
|
|
76
|
-
return this.ctx.request<RestrictedUser[]>('GET', '/privacy/restricted', undefined, {
|
|
97
|
+
return this.ctx.request<RestrictedUser[]>('GET', '/privacy/restricted', undefined, {
|
|
98
|
+
cache: true,
|
|
99
|
+
cacheTTL: LIST_TTL,
|
|
100
|
+
});
|
|
77
101
|
}
|
|
78
102
|
|
|
79
103
|
/** Restrict a user: limit their interactions without blocking them. */
|
|
80
104
|
async restrict(userId: string): Promise<{ message: string }> {
|
|
81
105
|
requireId(userId);
|
|
82
|
-
const res = await this.ctx.request<{ message: string }>(
|
|
106
|
+
const res = await this.ctx.request<{ message: string }>(
|
|
107
|
+
'POST',
|
|
108
|
+
`/privacy/restricted/${userId}`,
|
|
109
|
+
undefined,
|
|
110
|
+
{ cache: false },
|
|
111
|
+
);
|
|
83
112
|
this.invalidate('GET:/privacy/restricted');
|
|
84
113
|
return res;
|
|
85
114
|
}
|
|
@@ -87,7 +116,12 @@ export class PrivacyApi {
|
|
|
87
116
|
/** Lift a restriction. */
|
|
88
117
|
async unrestrict(userId: string): Promise<{ message: string }> {
|
|
89
118
|
requireId(userId);
|
|
90
|
-
const res = await this.ctx.request<{ message: string }>(
|
|
119
|
+
const res = await this.ctx.request<{ message: string }>(
|
|
120
|
+
'DELETE',
|
|
121
|
+
`/privacy/restricted/${userId}`,
|
|
122
|
+
undefined,
|
|
123
|
+
{ cache: false },
|
|
124
|
+
);
|
|
91
125
|
this.invalidate('GET:/privacy/restricted');
|
|
92
126
|
return res;
|
|
93
127
|
}
|
package/src/api/reputation.ts
CHANGED
|
@@ -53,7 +53,9 @@ export class ReputationApi {
|
|
|
53
53
|
const mine = !userId;
|
|
54
54
|
const id = userId || this.ctx.oxy.session.userId;
|
|
55
55
|
if (!id) {
|
|
56
|
-
throw new OxyAuthenticationError(
|
|
56
|
+
throw new OxyAuthenticationError(
|
|
57
|
+
'Reading your own reputation balance requires a signed-in user',
|
|
58
|
+
);
|
|
57
59
|
}
|
|
58
60
|
const balance = await this.ctx.request<ReputationBalanceView>(
|
|
59
61
|
'GET',
|
|
@@ -82,10 +84,15 @@ export class ReputationApi {
|
|
|
82
84
|
|
|
83
85
|
/** The enabled rules: what earns and what costs reputation. */
|
|
84
86
|
async rules(): Promise<ReputationRule[]> {
|
|
85
|
-
const res = await this.ctx.request<{ rules?: ReputationRule[] }>(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
const res = await this.ctx.request<{ rules?: ReputationRule[] }>(
|
|
88
|
+
'GET',
|
|
89
|
+
'/reputation/rules',
|
|
90
|
+
undefined,
|
|
91
|
+
{
|
|
92
|
+
cache: true,
|
|
93
|
+
cacheTTL: EXTRA_LONG,
|
|
94
|
+
},
|
|
95
|
+
);
|
|
89
96
|
return res.rules ?? [];
|
|
90
97
|
}
|
|
91
98
|
|
|
@@ -109,7 +116,10 @@ export class ReputationApi {
|
|
|
109
116
|
* user's). Auth required.
|
|
110
117
|
* @param context - The weight axis (server default: `default`).
|
|
111
118
|
*/
|
|
112
|
-
async influence(
|
|
119
|
+
async influence(
|
|
120
|
+
userId?: string,
|
|
121
|
+
context?: ReputationInfluenceContext,
|
|
122
|
+
): Promise<ReputationInfluenceResult> {
|
|
113
123
|
const id = this.resolveUserId(userId);
|
|
114
124
|
return this.ctx.request<ReputationInfluenceResult>(
|
|
115
125
|
'GET',
|
|
@@ -121,7 +131,8 @@ export class ReputationApi {
|
|
|
121
131
|
|
|
122
132
|
protected resolveUserId(userId?: string): string {
|
|
123
133
|
const id = userId || this.ctx.oxy.session.userId;
|
|
124
|
-
if (!id)
|
|
134
|
+
if (!id)
|
|
135
|
+
throw new OxyAuthenticationError('A user id is required (none given and not signed in)');
|
|
125
136
|
return id;
|
|
126
137
|
}
|
|
127
138
|
}
|
package/src/api/session.ts
CHANGED
|
@@ -140,7 +140,13 @@ export class SessionApi {
|
|
|
140
140
|
if (!provider) return null;
|
|
141
141
|
try {
|
|
142
142
|
const proof = await provider();
|
|
143
|
-
if (
|
|
143
|
+
if (
|
|
144
|
+
proof &&
|
|
145
|
+
typeof proof.deviceId === 'string' &&
|
|
146
|
+
proof.deviceId &&
|
|
147
|
+
typeof proof.deviceSecret === 'string' &&
|
|
148
|
+
proof.deviceSecret
|
|
149
|
+
) {
|
|
144
150
|
return { deviceId: proof.deviceId, deviceSecret: proof.deviceSecret };
|
|
145
151
|
}
|
|
146
152
|
return null;
|
|
@@ -155,7 +161,10 @@ export class SessionApi {
|
|
|
155
161
|
async validateToken(): Promise<boolean> {
|
|
156
162
|
if (!this.isAuthenticated) return false;
|
|
157
163
|
try {
|
|
158
|
-
const res = await this.ctx.request<{ valid: boolean }>('GET', '/auth/validate', undefined, {
|
|
164
|
+
const res = await this.ctx.request<{ valid: boolean }>('GET', '/auth/validate', undefined, {
|
|
165
|
+
cache: false,
|
|
166
|
+
retry: false,
|
|
167
|
+
});
|
|
159
168
|
return res.valid === true;
|
|
160
169
|
} catch {
|
|
161
170
|
return false;
|
|
@@ -171,7 +180,12 @@ export class SessionApi {
|
|
|
171
180
|
if (options.deviceFingerprint) params.deviceFingerprint = options.deviceFingerprint;
|
|
172
181
|
if (options.useHeaderValidation) params.useHeaderValidation = 'true';
|
|
173
182
|
try {
|
|
174
|
-
const validation = await this.ctx.request<SessionValidation>(
|
|
183
|
+
const validation = await this.ctx.request<SessionValidation>(
|
|
184
|
+
'GET',
|
|
185
|
+
`/session/validate/${sessionId}`,
|
|
186
|
+
params,
|
|
187
|
+
{ cache: false },
|
|
188
|
+
);
|
|
175
189
|
return { ...validation, user: normalizeUserIdentity(validation.user) };
|
|
176
190
|
} catch (error) {
|
|
177
191
|
// The session is gone: drop any user cached for it (#196).
|
|
@@ -182,12 +196,16 @@ export class SessionApi {
|
|
|
182
196
|
|
|
183
197
|
/** The sessions that belong with `sessionId` (same account set). */
|
|
184
198
|
async list(sessionId: string): Promise<ClientSession[]> {
|
|
185
|
-
return this.ctx.request<ClientSession[]>('GET', `/session/sessions/${sessionId}`, undefined, {
|
|
199
|
+
return this.ctx.request<ClientSession[]>('GET', `/session/sessions/${sessionId}`, undefined, {
|
|
200
|
+
cache: false,
|
|
201
|
+
});
|
|
186
202
|
}
|
|
187
203
|
|
|
188
204
|
/** Sign out `sessionId`, or — with `targetSessionId` — one of the sessions beside it. */
|
|
189
205
|
async logout(sessionId: string, targetSessionId?: string): Promise<void> {
|
|
190
|
-
const url = targetSessionId
|
|
206
|
+
const url = targetSessionId
|
|
207
|
+
? `/session/logout/${sessionId}/${targetSessionId}`
|
|
208
|
+
: `/session/logout/${sessionId}`;
|
|
191
209
|
await this.ctx.request('POST', url, undefined, { cache: false });
|
|
192
210
|
}
|
|
193
211
|
|
package/src/api/store.ts
CHANGED
|
@@ -227,7 +227,6 @@ function queryOf<T extends object>(params: T): string {
|
|
|
227
227
|
return rendered ? `?${rendered}` : '';
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
|
|
231
230
|
/** `oxy.store.reviews` — what people say about an app, and the caller's own review. */
|
|
232
231
|
export class StoreReviewsApi {
|
|
233
232
|
constructor(private readonly ctx: OxyContext) {}
|
|
@@ -245,9 +244,14 @@ export class StoreReviewsApi {
|
|
|
245
244
|
|
|
246
245
|
/** The caller's own review of an app, or `null` if they have not written one. */
|
|
247
246
|
async mine(slug: string): Promise<StoreOwnReview | null> {
|
|
248
|
-
const res = await this.ctx.request<{ data: StoreOwnReview | null }>(
|
|
249
|
-
|
|
250
|
-
|
|
247
|
+
const res = await this.ctx.request<{ data: StoreOwnReview | null }>(
|
|
248
|
+
'GET',
|
|
249
|
+
reviewPath(slug),
|
|
250
|
+
undefined,
|
|
251
|
+
{
|
|
252
|
+
cache: false,
|
|
253
|
+
},
|
|
254
|
+
);
|
|
251
255
|
return res.data ?? null;
|
|
252
256
|
}
|
|
253
257
|
|
|
@@ -259,7 +263,9 @@ export class StoreReviewsApi {
|
|
|
259
263
|
* hidden when its author edits it.
|
|
260
264
|
*/
|
|
261
265
|
async write(slug: string, input: WriteStoreReviewInput): Promise<StoreOwnReview> {
|
|
262
|
-
const res = await this.ctx.request<{ data: StoreOwnReview }>('PUT', reviewPath(slug), input, {
|
|
266
|
+
const res = await this.ctx.request<{ data: StoreOwnReview }>('PUT', reviewPath(slug), input, {
|
|
267
|
+
cache: false,
|
|
268
|
+
});
|
|
263
269
|
return res.data;
|
|
264
270
|
}
|
|
265
271
|
|
|
@@ -275,7 +281,9 @@ export class ListingScreenshotsApi {
|
|
|
275
281
|
|
|
276
282
|
/** Every picture on the listing, in the author's order. */
|
|
277
283
|
async list(applicationId: string): Promise<StoreScreenshot[]> {
|
|
278
|
-
return this.ctx.request<StoreScreenshot[]>('GET', screenshotsPath(applicationId), undefined, {
|
|
284
|
+
return this.ctx.request<StoreScreenshot[]>('GET', screenshotsPath(applicationId), undefined, {
|
|
285
|
+
cache: false,
|
|
286
|
+
});
|
|
279
287
|
}
|
|
280
288
|
|
|
281
289
|
/**
|
|
@@ -286,11 +294,17 @@ export class ListingScreenshotsApi {
|
|
|
286
294
|
* one the caller is entitled to.
|
|
287
295
|
*/
|
|
288
296
|
async add(applicationId: string, input: AddScreenshotInput): Promise<StoreScreenshot> {
|
|
289
|
-
return this.ctx.request<StoreScreenshot>('POST', screenshotsPath(applicationId), input, {
|
|
297
|
+
return this.ctx.request<StoreScreenshot>('POST', screenshotsPath(applicationId), input, {
|
|
298
|
+
cache: false,
|
|
299
|
+
});
|
|
290
300
|
}
|
|
291
301
|
|
|
292
302
|
/** Edit a picture's caption or the frame it was taken in. Order is `reorder`. */
|
|
293
|
-
async update(
|
|
303
|
+
async update(
|
|
304
|
+
applicationId: string,
|
|
305
|
+
screenshotId: string,
|
|
306
|
+
input: UpdateScreenshotInput,
|
|
307
|
+
): Promise<StoreScreenshot> {
|
|
294
308
|
return this.ctx.request<StoreScreenshot>(
|
|
295
309
|
'PATCH',
|
|
296
310
|
`${screenshotsPath(applicationId)}/${enc(screenshotId)}`,
|
|
@@ -301,9 +315,14 @@ export class ListingScreenshotsApi {
|
|
|
301
315
|
|
|
302
316
|
/** Remove a picture. The uploaded file stays — it may be in use elsewhere. */
|
|
303
317
|
async delete(applicationId: string, screenshotId: string): Promise<void> {
|
|
304
|
-
await this.ctx.request<void>(
|
|
305
|
-
|
|
306
|
-
|
|
318
|
+
await this.ctx.request<void>(
|
|
319
|
+
'DELETE',
|
|
320
|
+
`${screenshotsPath(applicationId)}/${enc(screenshotId)}`,
|
|
321
|
+
undefined,
|
|
322
|
+
{
|
|
323
|
+
cache: false,
|
|
324
|
+
},
|
|
325
|
+
);
|
|
307
326
|
}
|
|
308
327
|
|
|
309
328
|
/**
|
|
@@ -314,9 +333,14 @@ export class ListingScreenshotsApi {
|
|
|
314
333
|
* pictures it omits at their old positions, interleaved with the new ones.
|
|
315
334
|
*/
|
|
316
335
|
async reorder(applicationId: string, screenshotIds: string[]): Promise<StoreScreenshot[]> {
|
|
317
|
-
return this.ctx.request<StoreScreenshot[]>(
|
|
318
|
-
|
|
319
|
-
|
|
336
|
+
return this.ctx.request<StoreScreenshot[]>(
|
|
337
|
+
'PUT',
|
|
338
|
+
`${screenshotsPath(applicationId)}/order`,
|
|
339
|
+
{ screenshotIds },
|
|
340
|
+
{
|
|
341
|
+
cache: false,
|
|
342
|
+
},
|
|
343
|
+
);
|
|
320
344
|
}
|
|
321
345
|
}
|
|
322
346
|
|
|
@@ -331,7 +355,9 @@ export class StoreListingApi {
|
|
|
331
355
|
|
|
332
356
|
/** The application's store page in whatever state, or `null` if it has none. */
|
|
333
357
|
async get(applicationId: string): Promise<PublisherListing | null> {
|
|
334
|
-
return this.ctx.request<PublisherListing | null>('GET', listingPath(applicationId), undefined, {
|
|
358
|
+
return this.ctx.request<PublisherListing | null>('GET', listingPath(applicationId), undefined, {
|
|
359
|
+
cache: false,
|
|
360
|
+
});
|
|
335
361
|
}
|
|
336
362
|
|
|
337
363
|
/**
|
|
@@ -341,14 +367,21 @@ export class StoreListingApi {
|
|
|
341
367
|
* it live, and fixing a rejected one does not re-submit it.
|
|
342
368
|
*/
|
|
343
369
|
async write(applicationId: string, input: WriteListingInput): Promise<PublisherListing> {
|
|
344
|
-
return this.ctx.request<PublisherListing>('PUT', listingPath(applicationId), input, {
|
|
370
|
+
return this.ctx.request<PublisherListing>('PUT', listingPath(applicationId), input, {
|
|
371
|
+
cache: false,
|
|
372
|
+
});
|
|
345
373
|
}
|
|
346
374
|
|
|
347
375
|
/** Hand the page to the store for review. From a draft, or a rejected page once fixed. */
|
|
348
376
|
async submit(applicationId: string): Promise<PublisherListing> {
|
|
349
|
-
return this.ctx.request<PublisherListing>(
|
|
350
|
-
|
|
351
|
-
|
|
377
|
+
return this.ctx.request<PublisherListing>(
|
|
378
|
+
'POST',
|
|
379
|
+
`${listingPath(applicationId)}/submit`,
|
|
380
|
+
undefined,
|
|
381
|
+
{
|
|
382
|
+
cache: false,
|
|
383
|
+
},
|
|
384
|
+
);
|
|
352
385
|
}
|
|
353
386
|
|
|
354
387
|
/**
|
|
@@ -359,9 +392,14 @@ export class StoreListingApi {
|
|
|
359
392
|
* them.
|
|
360
393
|
*/
|
|
361
394
|
async unpublish(applicationId: string): Promise<PublisherListing> {
|
|
362
|
-
return this.ctx.request<PublisherListing>(
|
|
363
|
-
|
|
364
|
-
|
|
395
|
+
return this.ctx.request<PublisherListing>(
|
|
396
|
+
'POST',
|
|
397
|
+
`${listingPath(applicationId)}/unpublish`,
|
|
398
|
+
undefined,
|
|
399
|
+
{
|
|
400
|
+
cache: false,
|
|
401
|
+
},
|
|
402
|
+
);
|
|
365
403
|
}
|
|
366
404
|
}
|
|
367
405
|
|
|
@@ -380,10 +418,15 @@ export class StoreApi {
|
|
|
380
418
|
|
|
381
419
|
/** The shelves, in the order the store curates them. */
|
|
382
420
|
async categories(): Promise<StoreCategory[]> {
|
|
383
|
-
const res = await this.ctx.request<{ data: StoreCategory[] }>(
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
421
|
+
const res = await this.ctx.request<{ data: StoreCategory[] }>(
|
|
422
|
+
'GET',
|
|
423
|
+
'/store/categories',
|
|
424
|
+
undefined,
|
|
425
|
+
{
|
|
426
|
+
cache: true,
|
|
427
|
+
cacheTTL: MEDIUM_TTL,
|
|
428
|
+
},
|
|
429
|
+
);
|
|
387
430
|
return res.data ?? [];
|
|
388
431
|
}
|
|
389
432
|
|
|
@@ -395,7 +438,9 @@ export class StoreApi {
|
|
|
395
438
|
*
|
|
396
439
|
* @param options - `category` is a category slug; `limit` defaults to 24.
|
|
397
440
|
*/
|
|
398
|
-
async apps(
|
|
441
|
+
async apps(
|
|
442
|
+
options: StorePageOptions & { category?: string } = {},
|
|
443
|
+
): Promise<StorePage<StoreListingSummary>> {
|
|
399
444
|
const res = await this.ctx.request<PaginatedResponse<StoreListingSummary>>(
|
|
400
445
|
'GET',
|
|
401
446
|
`/store/apps${queryOf(options)}`,
|
|
@@ -414,10 +459,15 @@ export class StoreApi {
|
|
|
414
459
|
* @param slug - The listing's public slug, not an application id.
|
|
415
460
|
*/
|
|
416
461
|
async app(slug: string): Promise<StoreListingDetail> {
|
|
417
|
-
const res = await this.ctx.request<{ data: StoreListingDetail }>(
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
462
|
+
const res = await this.ctx.request<{ data: StoreListingDetail }>(
|
|
463
|
+
'GET',
|
|
464
|
+
`/store/apps/${enc(slug)}`,
|
|
465
|
+
undefined,
|
|
466
|
+
{
|
|
467
|
+
cache: true,
|
|
468
|
+
cacheTTL: SHORT_TTL,
|
|
469
|
+
},
|
|
470
|
+
);
|
|
421
471
|
return res.data;
|
|
422
472
|
}
|
|
423
473
|
}
|
package/src/api/topics.ts
CHANGED
|
@@ -43,13 +43,18 @@ export class TopicsApi {
|
|
|
43
43
|
async search(query: string, limit?: number): Promise<TopicData[]> {
|
|
44
44
|
const params: Record<string, string | number> = { q: query };
|
|
45
45
|
if (limit) params.limit = limit;
|
|
46
|
-
const res = await this.ctx.request<{ topics?: TopicData[] }>('GET', '/topics/search', params, {
|
|
46
|
+
const res = await this.ctx.request<{ topics?: TopicData[] }>('GET', '/topics/search', params, {
|
|
47
|
+
cache: false,
|
|
48
|
+
});
|
|
47
49
|
return res.topics ?? [];
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/** One topic by slug. */
|
|
51
53
|
async get(slug: string): Promise<TopicData> {
|
|
52
|
-
return this.ctx.request<TopicData>('GET', `/topics/${slug}`, undefined, {
|
|
54
|
+
return this.ctx.request<TopicData>('GET', `/topics/${slug}`, undefined, {
|
|
55
|
+
cache: true,
|
|
56
|
+
cacheTTL: LONG,
|
|
57
|
+
});
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
/** The top-level categories, optionally translated. */
|
|
@@ -65,9 +70,14 @@ export class TopicsApi {
|
|
|
65
70
|
|
|
66
71
|
/** Resolve names to topics, creating the missing ones. Staff or service only. */
|
|
67
72
|
async resolveNames(names: Array<{ name: string; type: string }>): Promise<TopicData[]> {
|
|
68
|
-
const res = await this.ctx.request<{ topics?: Record<string, TopicData> }>(
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
const res = await this.ctx.request<{ topics?: Record<string, TopicData> }>(
|
|
74
|
+
'POST',
|
|
75
|
+
'/topics/resolve',
|
|
76
|
+
{ names },
|
|
77
|
+
{
|
|
78
|
+
cache: false,
|
|
79
|
+
},
|
|
80
|
+
);
|
|
71
81
|
return Object.values(res.topics ?? {});
|
|
72
82
|
}
|
|
73
83
|
|
|
@@ -76,7 +86,9 @@ export class TopicsApi {
|
|
|
76
86
|
slug: string,
|
|
77
87
|
data: { description?: string; translations?: Record<string, TopicTranslation> },
|
|
78
88
|
): Promise<TopicData> {
|
|
79
|
-
const topic = await this.ctx.request<TopicData>('PATCH', `/topics/${slug}`, data, {
|
|
89
|
+
const topic = await this.ctx.request<TopicData>('PATCH', `/topics/${slug}`, data, {
|
|
90
|
+
cache: false,
|
|
91
|
+
});
|
|
80
92
|
this.ctx.oxy.cache.delete(`GET:/topics/${slug}`);
|
|
81
93
|
return topic;
|
|
82
94
|
}
|
package/src/api/users.ts
CHANGED
|
@@ -103,7 +103,12 @@ export class UsersApi {
|
|
|
103
103
|
try {
|
|
104
104
|
const users = service
|
|
105
105
|
? await service.request<User[]>('POST', '/users/by-ids', { ids: chunk })
|
|
106
|
-
: await this.ctx.request<User[]>(
|
|
106
|
+
: await this.ctx.request<User[]>(
|
|
107
|
+
'POST',
|
|
108
|
+
'/users/by-ids',
|
|
109
|
+
{ ids: chunk },
|
|
110
|
+
{ cache: false },
|
|
111
|
+
);
|
|
107
112
|
return Array.isArray(users) ? users.map((user) => normalizeUserIdentity(user)) : [];
|
|
108
113
|
} catch (error: unknown) {
|
|
109
114
|
logger.warn('users.getMany: chunk failed, continuing with remaining chunks', {
|
|
@@ -121,27 +126,40 @@ export class UsersApi {
|
|
|
121
126
|
}
|
|
122
127
|
|
|
123
128
|
/** The signed-in user. Cached 1 minute. */
|
|
124
|
-
async me(options?: {cache?: boolean}): Promise<User> {
|
|
125
|
-
const user = await this.ctx.request<User>('GET', '/users/me', undefined, {
|
|
129
|
+
async me(options?: { cache?: boolean }): Promise<User> {
|
|
130
|
+
const user = await this.ctx.request<User>('GET', '/users/me', undefined, {
|
|
131
|
+
cache: options?.cache ?? true,
|
|
132
|
+
cacheTTL: ME_TTL,
|
|
133
|
+
});
|
|
126
134
|
return normalizeUserIdentity(user);
|
|
127
135
|
}
|
|
128
136
|
|
|
129
137
|
/** A profile by username. Cached 5 minutes; `{ cache: false }` as in `get`. */
|
|
130
138
|
async byUsername(username: string, options?: { cache?: boolean }): Promise<User> {
|
|
131
|
-
const user = await this.ctx.request<User>(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
139
|
+
const user = await this.ctx.request<User>(
|
|
140
|
+
'GET',
|
|
141
|
+
`/profiles/username/${encodeURIComponent(username)}`,
|
|
142
|
+
undefined,
|
|
143
|
+
{
|
|
144
|
+
cache: options?.cache ?? true,
|
|
145
|
+
cacheTTL: PROFILE_TTL,
|
|
146
|
+
},
|
|
147
|
+
);
|
|
135
148
|
return normalizeUserIdentity(user);
|
|
136
149
|
}
|
|
137
150
|
|
|
138
151
|
/** The user owning a public key. Public (pre-session): sends no bearer. */
|
|
139
152
|
async byPublicKey(publicKey: string): Promise<User> {
|
|
140
|
-
const user = await this.ctx.request<User>(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
153
|
+
const user = await this.ctx.request<User>(
|
|
154
|
+
'GET',
|
|
155
|
+
`/auth/user/${encodeURIComponent(publicKey)}`,
|
|
156
|
+
undefined,
|
|
157
|
+
{
|
|
158
|
+
cache: true,
|
|
159
|
+
cacheTTL: SESSION_USER_TTL,
|
|
160
|
+
skipAuth: true,
|
|
161
|
+
},
|
|
162
|
+
);
|
|
145
163
|
return normalizeUserIdentity(user);
|
|
146
164
|
}
|
|
147
165
|
|
|
@@ -205,22 +223,32 @@ export class UsersApi {
|
|
|
205
223
|
*/
|
|
206
224
|
async resolveHandle(handle: string): Promise<User | null> {
|
|
207
225
|
try {
|
|
208
|
-
const result = await this.ctx.request<User | null>(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
226
|
+
const result = await this.ctx.request<User | null>(
|
|
227
|
+
'GET',
|
|
228
|
+
'/profiles/resolve',
|
|
229
|
+
{ handle },
|
|
230
|
+
{
|
|
231
|
+
cache: true,
|
|
232
|
+
cacheTTL: PROFILE_TTL,
|
|
233
|
+
},
|
|
234
|
+
);
|
|
212
235
|
return normalizeUserIdentityOrNull(result);
|
|
213
236
|
} catch (error: unknown) {
|
|
214
237
|
// A 404 (absent) and an upstream failure both return null; the log keeps
|
|
215
238
|
// them distinguishable without turning expected misses into noise.
|
|
216
239
|
const status = extractErrorStatus(error);
|
|
217
|
-
logger.debug(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
240
|
+
logger.debug(
|
|
241
|
+
status === 404
|
|
242
|
+
? 'users.resolveHandle: handle not found'
|
|
243
|
+
: 'users.resolveHandle: discovery failed',
|
|
244
|
+
{
|
|
245
|
+
method: 'users.resolveHandle',
|
|
246
|
+
handle,
|
|
247
|
+
status,
|
|
248
|
+
notFound: status === 404,
|
|
249
|
+
error: error instanceof Error ? error.message : String(error),
|
|
250
|
+
},
|
|
251
|
+
);
|
|
224
252
|
return null;
|
|
225
253
|
}
|
|
226
254
|
}
|
|
@@ -236,11 +264,19 @@ export class UsersApi {
|
|
|
236
264
|
|
|
237
265
|
/** Profiles similar to `userId`, by co-follower overlap. Cached 5 minutes. */
|
|
238
266
|
async similar(userId: string, limitOrPagination?: number | PaginationParams): Promise<User[]> {
|
|
239
|
-
const pagination =
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
267
|
+
const pagination =
|
|
268
|
+
typeof limitOrPagination === 'number'
|
|
269
|
+
? { limit: limitOrPagination }
|
|
270
|
+
: (limitOrPagination ?? {});
|
|
271
|
+
const users = await this.ctx.request<User[]>(
|
|
272
|
+
'GET',
|
|
273
|
+
`/profiles/${userId}/similar`,
|
|
274
|
+
buildQueryParams(pagination),
|
|
275
|
+
{
|
|
276
|
+
cache: true,
|
|
277
|
+
cacheTTL: PROFILE_TTL,
|
|
278
|
+
},
|
|
279
|
+
);
|
|
244
280
|
return users.map((user) => normalizeUserIdentity(user));
|
|
245
281
|
}
|
|
246
282
|
|
|
@@ -266,7 +302,12 @@ export class UsersApi {
|
|
|
266
302
|
try {
|
|
267
303
|
if (scored && options) {
|
|
268
304
|
const body = recommendationRequestSchema.parse(options);
|
|
269
|
-
return await this.ctx.request<RecommendationItem[]>(
|
|
305
|
+
return await this.ctx.request<RecommendationItem[]>(
|
|
306
|
+
'POST',
|
|
307
|
+
'/profiles/recommendations',
|
|
308
|
+
body,
|
|
309
|
+
{ cache: true },
|
|
310
|
+
);
|
|
270
311
|
}
|
|
271
312
|
const params: Record<string, string> = {};
|
|
272
313
|
if (options?.excludeTypes?.length) params.excludeTypes = options.excludeTypes.join(',');
|
|
@@ -306,7 +347,9 @@ export class UsersApi {
|
|
|
306
347
|
async updateMe(updates: UserProfileUpdate): Promise<User> {
|
|
307
348
|
let result: User;
|
|
308
349
|
try {
|
|
309
|
-
result = normalizeUserIdentity(
|
|
350
|
+
result = normalizeUserIdentity(
|
|
351
|
+
await this.ctx.request<User>('PUT', '/users/me', updates, { cache: false }),
|
|
352
|
+
);
|
|
310
353
|
} catch (error) {
|
|
311
354
|
if (extractErrorStatus(error) === 401 && !this.ctx.oxy.session.isAuthenticated) {
|
|
312
355
|
throw new Error('AUTH_REQUIRED_OFFLINE_SESSION: Session needs to be synced to get a token');
|
|
@@ -325,8 +368,16 @@ export class UsersApi {
|
|
|
325
368
|
}
|
|
326
369
|
|
|
327
370
|
/** Ask for the verified badge. */
|
|
328
|
-
async requestVerification(
|
|
329
|
-
|
|
371
|
+
async requestVerification(
|
|
372
|
+
reason: string,
|
|
373
|
+
evidence?: string,
|
|
374
|
+
): Promise<{ message: string; requestId: string }> {
|
|
375
|
+
return this.ctx.request(
|
|
376
|
+
'POST',
|
|
377
|
+
'/users/verify/request',
|
|
378
|
+
{ reason, evidence },
|
|
379
|
+
{ cache: false },
|
|
380
|
+
);
|
|
330
381
|
}
|
|
331
382
|
|
|
332
383
|
/**
|
|
@@ -335,7 +386,12 @@ export class UsersApi {
|
|
|
335
386
|
*/
|
|
336
387
|
async deleteMe(confirmText: string, proof: DeleteAccountProof): Promise<{ message: string }> {
|
|
337
388
|
if ('reauth' in proof) {
|
|
338
|
-
return this.ctx.request(
|
|
389
|
+
return this.ctx.request(
|
|
390
|
+
'DELETE',
|
|
391
|
+
'/users/me',
|
|
392
|
+
{ confirmText, reauth: proof.reauth },
|
|
393
|
+
{ cache: false },
|
|
394
|
+
);
|
|
339
395
|
}
|
|
340
396
|
|
|
341
397
|
// Loaded on demand: only a Commons account deleting from its own device
|
|
@@ -343,14 +399,21 @@ export class UsersApi {
|
|
|
343
399
|
const { KeyManager, SignatureService } = await import('../crypto/internal');
|
|
344
400
|
const publicKey = await KeyManager.getPublicKey();
|
|
345
401
|
if (!publicKey) {
|
|
346
|
-
throw new Error(
|
|
402
|
+
throw new Error(
|
|
403
|
+
'No identity found on this device. Account deletion requires the device that holds your identity key.',
|
|
404
|
+
);
|
|
347
405
|
}
|
|
348
406
|
const timestamp = Date.now();
|
|
349
407
|
const signature = await SignatureService.sign(`delete:${publicKey}:${timestamp}`);
|
|
350
408
|
return this.ctx.request(
|
|
351
409
|
'DELETE',
|
|
352
410
|
'/users/me',
|
|
353
|
-
{
|
|
411
|
+
{
|
|
412
|
+
signature,
|
|
413
|
+
timestamp,
|
|
414
|
+
confirmText,
|
|
415
|
+
...(proof.totpCode ? { totpCode: proof.totpCode } : {}),
|
|
416
|
+
},
|
|
354
417
|
{ cache: false },
|
|
355
418
|
);
|
|
356
419
|
}
|