@oxy.so/core 4.5.0-oxy-one.0 → 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 +49 -12
- package/dist/cjs/api/auth.js +37 -11
- 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 +49 -12
- package/dist/esm/api/auth.js +37 -11
- 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/api/assets.d.ts +2 -0
- package/dist/types/api/auth.d.ts +8 -3
- 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/requesterAssertion.d.ts +2 -2
- 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 +122 -40
- package/src/api/auth.ts +154 -79
- 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/dist/esm/HttpService.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import { TTLCache, registerCacheForCleanup, unregisterCacheFromCleanup } from './utils/cache.js';
|
|
16
16
|
import { RequestDeduplicator, RequestQueue, SimpleLogger } from './utils/requestUtils.js';
|
|
17
17
|
import { retryAsync } from './utils/asyncUtils.js';
|
|
18
|
-
import { createCancelledError, ErrorCodes, handleHttpError, isCancelledError, parseHttpErrorBody } from './utils/errorUtils.js';
|
|
18
|
+
import { createCancelledError, ErrorCodes, handleHttpError, isCancelledError, parseHttpErrorBody, } from './utils/errorUtils.js';
|
|
19
19
|
import { decodeTokenClaims } from './utils/tokenClaims.js';
|
|
20
20
|
import { isReactNative } from '@oxy.so/protocol/random';
|
|
21
21
|
import { computeIdentityTag, fnv1a32 } from './utils/cacheKey.js';
|
|
@@ -36,14 +36,25 @@ function sameTokenSession(left, right) {
|
|
|
36
36
|
return false;
|
|
37
37
|
// A refresh may rotate exp/iat/jti while preserving its account and session.
|
|
38
38
|
// Opaque/malformed context fields cannot establish that equivalence.
|
|
39
|
-
return [
|
|
39
|
+
return [
|
|
40
|
+
'userId',
|
|
41
|
+
'id',
|
|
42
|
+
'sub',
|
|
43
|
+
'sessionId',
|
|
44
|
+
'operatorId',
|
|
45
|
+
'clientId',
|
|
46
|
+
'appId',
|
|
47
|
+
'authMethodId',
|
|
48
|
+
].every((key) => (a[key] === undefined || typeof a[key] === 'string') && a[key] === b[key]);
|
|
40
49
|
}
|
|
41
50
|
/** Cancel this wait only; the shared mint continues for other callers. */
|
|
42
51
|
function awaitRequestSignal(pending, signal) {
|
|
43
52
|
if (!signal)
|
|
44
53
|
return pending;
|
|
45
54
|
return new Promise((resolve, reject) => {
|
|
46
|
-
const onAbort = () => {
|
|
55
|
+
const onAbort = () => {
|
|
56
|
+
reject(createCancelledError());
|
|
57
|
+
};
|
|
47
58
|
if (signal.aborted)
|
|
48
59
|
onAbort();
|
|
49
60
|
else
|
|
@@ -202,7 +213,9 @@ function isAbortLike(error) {
|
|
|
202
213
|
function linkAbort(parent, child) {
|
|
203
214
|
if (parent.aborted) {
|
|
204
215
|
child.abort(parent.reason);
|
|
205
|
-
return () => {
|
|
216
|
+
return () => {
|
|
217
|
+
/* nothing was ever attached */
|
|
218
|
+
};
|
|
206
219
|
}
|
|
207
220
|
const onAbort = () => {
|
|
208
221
|
child.abort(parent.reason);
|
|
@@ -314,8 +327,7 @@ export class HttpService {
|
|
|
314
327
|
// the cache for the global cleanup interval. Default (config unset) keeps
|
|
315
328
|
// caching ON with the 5-minute TTL — unchanged for existing consumers.
|
|
316
329
|
this.cacheDisabled =
|
|
317
|
-
config.enableCache === false ||
|
|
318
|
-
(typeof config.cacheTTL === 'number' && config.cacheTTL <= 0);
|
|
330
|
+
config.enableCache === false || (typeof config.cacheTTL === 'number' && config.cacheTTL <= 0);
|
|
319
331
|
this.cache = new TTLCache(config.cacheTTL && config.cacheTTL > 0 ? config.cacheTTL : 5 * 60 * 1000);
|
|
320
332
|
if (!this.cacheDisabled) {
|
|
321
333
|
registerCacheForCleanup(this.cache);
|
|
@@ -491,7 +503,7 @@ export class HttpService {
|
|
|
491
503
|
const isUrlEncoded = this.isUrlSearchParams(data);
|
|
492
504
|
// Build headers - start with defaults
|
|
493
505
|
const headers = {
|
|
494
|
-
|
|
506
|
+
Accept: 'application/json',
|
|
495
507
|
};
|
|
496
508
|
// Only set Content-Type for non-FormData requests (FormData sets it automatically with boundary)
|
|
497
509
|
if (isUrlEncoded) {
|
|
@@ -525,7 +537,11 @@ export class HttpService {
|
|
|
525
537
|
// `fetch` as-is: RN's fetch does not consistently encode it, and doing
|
|
526
538
|
// it here keeps the body identical across every platform.
|
|
527
539
|
const bodyValue = method !== 'GET' && data
|
|
528
|
-
?
|
|
540
|
+
? isFormData
|
|
541
|
+
? data
|
|
542
|
+
: isUrlEncoded
|
|
543
|
+
? data.toString()
|
|
544
|
+
: JSON.stringify(data)
|
|
529
545
|
: undefined;
|
|
530
546
|
// React Native FormData workaround:
|
|
531
547
|
// Expo SDK 56's "winter fetch" rejects RN file descriptors `{uri, type, name}`
|
|
@@ -567,7 +583,13 @@ export class HttpService {
|
|
|
567
583
|
// queue slot, so a queued retry waits for a slot while holding one.
|
|
568
584
|
// With every slot held by a 401 (a revoked session under load) no
|
|
569
585
|
// retry could ever start and the whole client stalled.
|
|
570
|
-
return this.request({
|
|
586
|
+
return this.request({
|
|
587
|
+
...config,
|
|
588
|
+
_isAuthRetry: true,
|
|
589
|
+
retry: false,
|
|
590
|
+
deduplicate: false,
|
|
591
|
+
bypassQueue: true,
|
|
592
|
+
});
|
|
571
593
|
}
|
|
572
594
|
// Refresh failed or no token — clear tokens
|
|
573
595
|
this.tokenStore.clearTokens();
|
|
@@ -594,7 +616,11 @@ export class HttpService {
|
|
|
594
616
|
const parsed = parseHttpErrorBody(errorBody);
|
|
595
617
|
const error = new Error(parsed.message ?? `HTTP ${response.status}: ${response.statusText}`);
|
|
596
618
|
error.status = response.status;
|
|
597
|
-
error.response = {
|
|
619
|
+
error.response = {
|
|
620
|
+
status: response.status,
|
|
621
|
+
statusText: response.statusText,
|
|
622
|
+
data: errorBody,
|
|
623
|
+
};
|
|
598
624
|
// Only set `code`/`details` when the server actually sent them.
|
|
599
625
|
// Assigning `undefined` would still create the property, which changes
|
|
600
626
|
// how `handleHttpError` classifies the error downstream.
|
|
@@ -641,7 +667,11 @@ export class HttpService {
|
|
|
641
667
|
}
|
|
642
668
|
}
|
|
643
669
|
}
|
|
644
|
-
else if (contentType &&
|
|
670
|
+
else if (contentType &&
|
|
671
|
+
(contentType.includes('application/octet-stream') ||
|
|
672
|
+
contentType.includes('image/') ||
|
|
673
|
+
contentType.includes('video/') ||
|
|
674
|
+
contentType.includes('audio/'))) {
|
|
645
675
|
// For binary responses (blobs), return the blob directly without unwrapping
|
|
646
676
|
responseData = await response.blob();
|
|
647
677
|
}
|
|
@@ -707,7 +737,9 @@ export class HttpService {
|
|
|
707
737
|
// Control-plane calls the auth lane depends on (`bypassQueue`, e.g. the
|
|
708
738
|
// device-secret mint) run DIRECTLY — a queued mint could never acquire a
|
|
709
739
|
// slot when every slot is parked awaiting it.
|
|
710
|
-
config.bypassQueue
|
|
740
|
+
config.bypassQueue
|
|
741
|
+
? attempt(domain)
|
|
742
|
+
: this.requestQueue.enqueue(() => attempt(domain), domain);
|
|
711
743
|
const execute = (domain) => retry
|
|
712
744
|
? retryAsync(() => runAttempt(domain), {
|
|
713
745
|
maxRetries,
|
|
@@ -813,7 +845,9 @@ export class HttpService {
|
|
|
813
845
|
try {
|
|
814
846
|
xhr.abort();
|
|
815
847
|
}
|
|
816
|
-
catch {
|
|
848
|
+
catch {
|
|
849
|
+
/* xhr already finished */
|
|
850
|
+
}
|
|
817
851
|
};
|
|
818
852
|
if (abortSignal.aborted) {
|
|
819
853
|
reject(new DOMException('The user aborted a request.', 'AbortError'));
|
|
@@ -1226,8 +1260,10 @@ export class HttpService {
|
|
|
1226
1260
|
// an auth mint, even when the trusted transport accepts absolute URLs.
|
|
1227
1261
|
const target = new URL(this.buildURL(config.url));
|
|
1228
1262
|
const base = new URL(this.baseURL);
|
|
1229
|
-
if (target.origin !== base.origin ||
|
|
1230
|
-
|
|
1263
|
+
if (target.origin !== base.origin ||
|
|
1264
|
+
!['http:', 'https:'].includes(target.protocol) ||
|
|
1265
|
+
target.username ||
|
|
1266
|
+
target.password) {
|
|
1231
1267
|
throw new Error('Raw response requests must target the configured API origin');
|
|
1232
1268
|
}
|
|
1233
1269
|
if (config.signal?.aborted)
|
|
@@ -1237,7 +1273,8 @@ export class HttpService {
|
|
|
1237
1273
|
const contextToken = this.syncAccessTokenFromProvider();
|
|
1238
1274
|
const beforeAuthEpoch = this.sessionEpoch;
|
|
1239
1275
|
const authHeader = await awaitRequestSignal(this.getAuthHeader(), config.signal);
|
|
1240
|
-
if (beforeAuthEpoch !== this.sessionEpoch ||
|
|
1276
|
+
if (beforeAuthEpoch !== this.sessionEpoch ||
|
|
1277
|
+
!sameTokenSession(contextToken, this.tokenStore.getAccessToken())) {
|
|
1241
1278
|
throw new OxyAuthenticationError('The request session changed', 'AUTH_SESSION_CHANGED');
|
|
1242
1279
|
}
|
|
1243
1280
|
if (config.signal?.aborted)
|
|
@@ -1250,7 +1287,8 @@ export class HttpService {
|
|
|
1250
1287
|
async requestResponseAttempt(config, fullUrl, authHeader, isAuthRetry, epoch, contextToken) {
|
|
1251
1288
|
const assertCurrent = () => {
|
|
1252
1289
|
this.syncAccessTokenFromProvider();
|
|
1253
|
-
if (epoch !== this.sessionEpoch ||
|
|
1290
|
+
if (epoch !== this.sessionEpoch ||
|
|
1291
|
+
!sameTokenSession(contextToken, this.tokenStore.getAccessToken())) {
|
|
1254
1292
|
throw new OxyAuthenticationError('The request session changed', 'AUTH_SESSION_CHANGED');
|
|
1255
1293
|
}
|
|
1256
1294
|
};
|
|
@@ -1295,7 +1333,11 @@ export class HttpService {
|
|
|
1295
1333
|
throw error;
|
|
1296
1334
|
}
|
|
1297
1335
|
const replayable = body === undefined || typeof body === 'string';
|
|
1298
|
-
if (response.status === 401 &&
|
|
1336
|
+
if (response.status === 401 &&
|
|
1337
|
+
!isAuthRetry &&
|
|
1338
|
+
authHeader &&
|
|
1339
|
+
replayable &&
|
|
1340
|
+
!config.signal?.aborted) {
|
|
1299
1341
|
let refreshed;
|
|
1300
1342
|
try {
|
|
1301
1343
|
refreshed = await awaitRequestSignal(this.refreshAccessToken('response-401'), config.signal);
|
|
@@ -1330,7 +1372,9 @@ export class HttpService {
|
|
|
1330
1372
|
this.config.onRequestEnd?.(config.url, config.method, duration, false);
|
|
1331
1373
|
const normalizedError = config.signal?.aborted || isCancelledError(error)
|
|
1332
1374
|
? createCancelledError()
|
|
1333
|
-
: error instanceof Error
|
|
1375
|
+
: error instanceof Error
|
|
1376
|
+
? error
|
|
1377
|
+
: new Error(String(error));
|
|
1334
1378
|
this.config.onRequestError?.(config.url, config.method, normalizedError);
|
|
1335
1379
|
if (isCancelledError(normalizedError) || normalizedError instanceof OxyAuthenticationError)
|
|
1336
1380
|
throw normalizedError;
|
|
@@ -1502,7 +1546,7 @@ export class HttpService {
|
|
|
1502
1546
|
* per resource.
|
|
1503
1547
|
* @returns Number of entries deleted
|
|
1504
1548
|
*/
|
|
1505
|
-
invalidateCache({ keys = [], prefixes = [] }) {
|
|
1549
|
+
invalidateCache({ keys = [], prefixes = [], }) {
|
|
1506
1550
|
if (keys.length === 0 && prefixes.length === 0)
|
|
1507
1551
|
return 0;
|
|
1508
1552
|
const exact = new Set(keys);
|
package/dist/esm/api/accounts.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* no per-request "acting-as" header. Identity is carried by the session/token,
|
|
18
18
|
* so a switch propagates through reload and cross-domain exactly like a login.
|
|
19
19
|
*/
|
|
20
|
-
import { agentKeyOperationSchema, executeAgentKeyOperationSchema, agentKeyOperationChallengeSchema, agentKeyOperationResultSchema, agentKeyListResponseSchema } from '@oxy.so/contracts';
|
|
20
|
+
import { agentKeyOperationSchema, executeAgentKeyOperationSchema, agentKeyOperationChallengeSchema, agentKeyOperationResultSchema, agentKeyListResponseSchema, } from '@oxy.so/contracts';
|
|
21
21
|
import { normalizeUserIdentity } from '../utils/userIdentity.js';
|
|
22
22
|
import { evictOxyIdentityCache } from '../utils/identityCacheSweep.js';
|
|
23
23
|
import { evictOxyAccountForestCache, oxyAccountDetailCacheKey, OXY_ACCOUNT_PER_ACCOUNT_CACHE_PREFIX, } from '../utils/accountCacheSweep.js';
|
|
@@ -93,7 +93,9 @@ export class AccountAgentKeysApi {
|
|
|
93
93
|
this.ctx = ctx;
|
|
94
94
|
}
|
|
95
95
|
async list(accountId) {
|
|
96
|
-
return agentKeyListResponseSchema.parse(await this.ctx.request('GET', `/accounts/${enc(accountId)}/agent-keys`, undefined, {
|
|
96
|
+
return agentKeyListResponseSchema.parse(await this.ctx.request('GET', `/accounts/${enc(accountId)}/agent-keys`, undefined, {
|
|
97
|
+
cache: false,
|
|
98
|
+
}));
|
|
97
99
|
}
|
|
98
100
|
async requestChallenge(accountId, operation) {
|
|
99
101
|
const response = await this.ctx.request('POST', `/accounts/${enc(accountId)}/agent-keys/challenge`, agentKeyOperationSchema.parse(operation), { cache: false });
|
|
@@ -182,7 +184,9 @@ export class AccountsApi {
|
|
|
182
184
|
* @param data - Account configuration: kind, optional parent, and profile.
|
|
183
185
|
*/
|
|
184
186
|
async create(data) {
|
|
185
|
-
const res = await this.ctx.request('POST', '/accounts', data, {
|
|
187
|
+
const res = await this.ctx.request('POST', '/accounts', data, {
|
|
188
|
+
cache: false,
|
|
189
|
+
});
|
|
186
190
|
// A new account changes the accessible forest — bust every cached list.
|
|
187
191
|
evictOxyAccountForestCache(this.ctx.http);
|
|
188
192
|
return res.account;
|
|
@@ -222,7 +226,10 @@ export class AccountsApi {
|
|
|
222
226
|
cache: false,
|
|
223
227
|
});
|
|
224
228
|
this.ctx.http.invalidateCache({
|
|
225
|
-
keys: [
|
|
229
|
+
keys: [
|
|
230
|
+
`GET:/accounts/${enc(accountId)}/members`,
|
|
231
|
+
`GET:/accounts/${enc(accountId)}/credentials`,
|
|
232
|
+
],
|
|
226
233
|
});
|
|
227
234
|
evictOxyAccountForestCache(this.ctx.http, accountId);
|
|
228
235
|
return result;
|
package/dist/esm/api/agency.js
CHANGED
|
@@ -33,7 +33,9 @@ export class DelegationGrantsApi {
|
|
|
33
33
|
}
|
|
34
34
|
/** Revoke a grant. */
|
|
35
35
|
async revoke(grantId, ownerAccountId) {
|
|
36
|
-
await this.ctx.request('DELETE', `/capabilities/grants/${enc(grantId)}`, undefined, {
|
|
36
|
+
await this.ctx.request('DELETE', `/capabilities/grants/${enc(grantId)}`, undefined, {
|
|
37
|
+
cache: false,
|
|
38
|
+
});
|
|
37
39
|
this.ctx.oxy.cache.delete(grantsKey(ownerAccountId));
|
|
38
40
|
}
|
|
39
41
|
}
|
package/dist/esm/api/apps.js
CHANGED
|
@@ -68,7 +68,10 @@ export class ConnectedAppsApi {
|
|
|
68
68
|
* `GET /auth/grants`, briefly cached; `revoke` busts it.
|
|
69
69
|
*/
|
|
70
70
|
async list() {
|
|
71
|
-
return this.ctx.request('GET', '/auth/grants', undefined, {
|
|
71
|
+
return this.ctx.request('GET', '/auth/grants', undefined, {
|
|
72
|
+
cache: true,
|
|
73
|
+
cacheTTL: SHORT_TTL,
|
|
74
|
+
});
|
|
72
75
|
}
|
|
73
76
|
/**
|
|
74
77
|
* Revoke this user's grant for a connected application. After this the
|
|
@@ -90,7 +93,9 @@ export class ConnectedAppsApi {
|
|
|
90
93
|
}
|
|
91
94
|
/** Revoke one external MCP connection and every token in its family. */
|
|
92
95
|
async revokeMcpClient(grantId) {
|
|
93
|
-
await this.ctx.request('DELETE', `/auth/mcp/oauth/grants/${enc(grantId)}`, undefined, {
|
|
96
|
+
await this.ctx.request('DELETE', `/auth/mcp/oauth/grants/${enc(grantId)}`, undefined, {
|
|
97
|
+
cache: false,
|
|
98
|
+
});
|
|
94
99
|
this.ctx.oxy.cache.delete('GET:/auth/mcp/oauth/grants');
|
|
95
100
|
}
|
|
96
101
|
}
|
|
@@ -149,7 +154,10 @@ export class AppsApi {
|
|
|
149
154
|
const result = await this.ctx.request('DELETE', appPath(applicationId), undefined, {
|
|
150
155
|
cache: false,
|
|
151
156
|
});
|
|
152
|
-
this.invalidateLists([
|
|
157
|
+
this.invalidateLists([
|
|
158
|
+
`GET:${appPath(applicationId)}`,
|
|
159
|
+
`GET:${credentialsPath(applicationId)}`,
|
|
160
|
+
]);
|
|
153
161
|
return result;
|
|
154
162
|
}
|
|
155
163
|
/**
|
|
@@ -180,7 +188,10 @@ export class AppsApi {
|
|
|
180
188
|
* `GET:/applications/<id>…` detail keys.
|
|
181
189
|
*/
|
|
182
190
|
invalidateLists(extraKeys = []) {
|
|
183
|
-
this.ctx.http.invalidateCache({
|
|
191
|
+
this.ctx.http.invalidateCache({
|
|
192
|
+
keys: ['GET:/applications', ...extraKeys],
|
|
193
|
+
prefixes: ['GET:/applications?'],
|
|
194
|
+
});
|
|
184
195
|
}
|
|
185
196
|
}
|
|
186
197
|
function appPath(applicationId) {
|
package/dist/esm/api/assets.js
CHANGED
|
@@ -34,6 +34,12 @@ const ASSET_URL_CACHE_LIFETIME_FRACTION = 0.5;
|
|
|
34
34
|
/** Assumed URL lifetime (seconds) when no `expiresIn` is asked for; the API default. */
|
|
35
35
|
const DEFAULT_ASSET_URL_EXPIRES_IN_SECONDS = 3600;
|
|
36
36
|
const ASSET_TTL = 5 * 60 * 1000;
|
|
37
|
+
/**
|
|
38
|
+
* Default bound on one `POST /assets/upload`, in ms. The client's per-request
|
|
39
|
+
* default (5s) is sized for JSON calls; a video sent over a phone connection
|
|
40
|
+
* needs minutes, and timing it out at 5s failed every upload past a few MB.
|
|
41
|
+
*/
|
|
42
|
+
const ASSET_UPLOAD_TIMEOUT_MS = 10 * 60 * 1000;
|
|
37
43
|
/**
|
|
38
44
|
* How long a resolved asset URL may stay in the SDK's GET cache, in ms: never
|
|
39
45
|
* longer than the media token's lifetime, and discounted below it.
|
|
@@ -61,7 +67,13 @@ export class AssetsApi {
|
|
|
61
67
|
});
|
|
62
68
|
if (body.type && !headers.has('Content-Type'))
|
|
63
69
|
headers.set('Content-Type', body.type);
|
|
64
|
-
const result = await fetch(target.toString(), {
|
|
70
|
+
const result = await fetch(target.toString(), {
|
|
71
|
+
method: 'PUT',
|
|
72
|
+
body,
|
|
73
|
+
headers,
|
|
74
|
+
credentials: 'omit',
|
|
75
|
+
redirect: 'error',
|
|
76
|
+
});
|
|
65
77
|
if (!result.ok)
|
|
66
78
|
throw new Error(`Presigned upload failed (${result.status})`);
|
|
67
79
|
}
|
|
@@ -79,7 +91,8 @@ export class AssetsApi {
|
|
|
79
91
|
const fileName = 'name' in file && file.name ? file.name : 'unknown';
|
|
80
92
|
const fileSize = 'size' in file && file.size ? file.size : 0;
|
|
81
93
|
const formData = new FormData();
|
|
82
|
-
if ((typeof File !== 'undefined' && file instanceof File) ||
|
|
94
|
+
if ((typeof File !== 'undefined' && file instanceof File) ||
|
|
95
|
+
(typeof Blob !== 'undefined' && file instanceof Blob)) {
|
|
83
96
|
formData.append('file', file, fileName);
|
|
84
97
|
}
|
|
85
98
|
else if ('uri' in file && typeof file.uri === 'string') {
|
|
@@ -95,7 +108,9 @@ export class AssetsApi {
|
|
|
95
108
|
throw new Error(`Failed to read file from uri (status ${res.status})`);
|
|
96
109
|
}
|
|
97
110
|
const fetched = await res.blob();
|
|
98
|
-
const blob = fetched.type === '' && descriptor.type
|
|
111
|
+
const blob = fetched.type === '' && descriptor.type
|
|
112
|
+
? new Blob([fetched], { type: descriptor.type })
|
|
113
|
+
: fetched;
|
|
99
114
|
if (blob.size === 0) {
|
|
100
115
|
throw new Error('Cannot upload an empty file');
|
|
101
116
|
}
|
|
@@ -110,13 +125,19 @@ export class AssetsApi {
|
|
|
110
125
|
if (options.metadata)
|
|
111
126
|
formData.append('metadata', JSON.stringify(options.metadata));
|
|
112
127
|
try {
|
|
113
|
-
const response = await this.ctx.request('POST', '/assets/upload', formData, {
|
|
128
|
+
const response = await this.ctx.request('POST', '/assets/upload', formData, {
|
|
129
|
+
cache: false,
|
|
130
|
+
timeout: options.timeout ?? ASSET_UPLOAD_TIMEOUT_MS,
|
|
131
|
+
});
|
|
114
132
|
options.onProgress?.(100);
|
|
115
133
|
return response;
|
|
116
134
|
}
|
|
117
135
|
catch (error) {
|
|
118
136
|
logger.error('File upload error', error, { component: 'oxy.assets' });
|
|
119
|
-
error.fileContext = {
|
|
137
|
+
error.fileContext = {
|
|
138
|
+
fileName,
|
|
139
|
+
fileSize,
|
|
140
|
+
};
|
|
120
141
|
throw error;
|
|
121
142
|
}
|
|
122
143
|
}
|
|
@@ -132,7 +153,9 @@ export class AssetsApi {
|
|
|
132
153
|
// ── Links ────────────────────────────────────────────────────────────────
|
|
133
154
|
/** Link an asset to an entity (what keeps it alive). */
|
|
134
155
|
async link(fileId, target, options = {}) {
|
|
135
|
-
const body = {
|
|
156
|
+
const body = {
|
|
157
|
+
...target,
|
|
158
|
+
};
|
|
136
159
|
if (options.visibility)
|
|
137
160
|
body.visibility = options.visibility;
|
|
138
161
|
if (options.webhookUrl)
|
|
@@ -152,7 +175,10 @@ export class AssetsApi {
|
|
|
152
175
|
// ── Reads ────────────────────────────────────────────────────────────────
|
|
153
176
|
/** An asset's record: size, mime, visibility, links, variants. */
|
|
154
177
|
async get(fileId) {
|
|
155
|
-
return this.ctx.request('GET', `/assets/${enc(fileId)}`, undefined, {
|
|
178
|
+
return this.ctx.request('GET', `/assets/${enc(fileId)}`, undefined, {
|
|
179
|
+
cache: true,
|
|
180
|
+
cacheTTL: ASSET_TTL,
|
|
181
|
+
});
|
|
156
182
|
}
|
|
157
183
|
/** The signed-in user's files, newest first. */
|
|
158
184
|
async list(params = {}) {
|
|
@@ -165,7 +191,9 @@ export class AssetsApi {
|
|
|
165
191
|
}
|
|
166
192
|
/** The account's storage usage, aggregated from its assets. */
|
|
167
193
|
async usage() {
|
|
168
|
-
return this.ctx.request('GET', '/storage/usage', undefined, {
|
|
194
|
+
return this.ctx.request('GET', '/storage/usage', undefined, {
|
|
195
|
+
cache: false,
|
|
196
|
+
});
|
|
169
197
|
}
|
|
170
198
|
// ── URLs ─────────────────────────────────────────────────────────────────
|
|
171
199
|
/**
|
|
@@ -247,7 +275,9 @@ export class AssetsApi {
|
|
|
247
275
|
body.expiresIn = options.expiresIn;
|
|
248
276
|
if (typeof options?.context === 'string')
|
|
249
277
|
body.context = options.context;
|
|
250
|
-
return this.ctx.request('POST', '/assets/batch-access', body, {
|
|
278
|
+
return this.ctx.request('POST', '/assets/batch-access', body, {
|
|
279
|
+
cache: false,
|
|
280
|
+
});
|
|
251
281
|
}
|
|
252
282
|
// ── Content ──────────────────────────────────────────────────────────────
|
|
253
283
|
/** An asset's content as text. */
|
|
@@ -267,7 +297,9 @@ export class AssetsApi {
|
|
|
267
297
|
*/
|
|
268
298
|
async delete(fileId, options = {}) {
|
|
269
299
|
const url = `/assets/${enc(fileId)}${options.force ? '?force=true' : ''}`;
|
|
270
|
-
const res = await this.ctx.request('DELETE', url, undefined, {
|
|
300
|
+
const res = await this.ctx.request('DELETE', url, undefined, {
|
|
301
|
+
cache: false,
|
|
302
|
+
});
|
|
271
303
|
this.evict(fileId);
|
|
272
304
|
return res;
|
|
273
305
|
}
|
|
@@ -309,7 +341,10 @@ export class AssetsApi {
|
|
|
309
341
|
}
|
|
310
342
|
/** Drop the cached record and every cached URL variant of an asset, in one pass. */
|
|
311
343
|
evict(fileId) {
|
|
312
|
-
this.ctx.http.invalidateCache({
|
|
344
|
+
this.ctx.http.invalidateCache({
|
|
345
|
+
keys: [`GET:/assets/${enc(fileId)}`],
|
|
346
|
+
prefixes: [`GET:/assets/${enc(fileId)}/url`],
|
|
347
|
+
});
|
|
313
348
|
}
|
|
314
349
|
}
|
|
315
350
|
const enc = encodeURIComponent;
|
|
@@ -328,7 +363,9 @@ function dedupeFileAccessRequests(requests) {
|
|
|
328
363
|
if (seen.has(key))
|
|
329
364
|
continue;
|
|
330
365
|
seen.add(key);
|
|
331
|
-
out.push(req.variant === undefined
|
|
366
|
+
out.push(req.variant === undefined
|
|
367
|
+
? { fileId: req.fileId }
|
|
368
|
+
: { fileId: req.fileId, variant: req.variant });
|
|
332
369
|
}
|
|
333
370
|
return out;
|
|
334
371
|
}
|
package/dist/esm/api/auth.js
CHANGED
|
@@ -196,7 +196,9 @@ export class AuthPasswordApi {
|
|
|
196
196
|
return signInStep(this.ctx, res, 'auth/signin/password');
|
|
197
197
|
}
|
|
198
198
|
async set(request) {
|
|
199
|
-
return this.ctx.request('PUT', '/users/me/password', request, {
|
|
199
|
+
return this.ctx.request('PUT', '/users/me/password', request, {
|
|
200
|
+
cache: false,
|
|
201
|
+
});
|
|
200
202
|
}
|
|
201
203
|
}
|
|
202
204
|
/** `oxy.auth.totp` — the account’s authenticator app. */
|
|
@@ -205,7 +207,9 @@ export class AuthTotpApi {
|
|
|
205
207
|
this.ctx = ctx;
|
|
206
208
|
}
|
|
207
209
|
async enroll() {
|
|
208
|
-
const res = await this.ctx.request('POST', '/users/me/totp/enroll', undefined, {
|
|
210
|
+
const res = await this.ctx.request('POST', '/users/me/totp/enroll', undefined, {
|
|
211
|
+
cache: false,
|
|
212
|
+
});
|
|
209
213
|
const parsed = safeParseContract(totpEnrollResponseSchema, res);
|
|
210
214
|
if (!parsed)
|
|
211
215
|
throw new Error('users/me/totp/enroll returned an unexpected response shape');
|
|
@@ -273,7 +277,10 @@ export class AuthOAuthApi {
|
|
|
273
277
|
client_id: params.clientId,
|
|
274
278
|
code_verifier: params.codeVerifier,
|
|
275
279
|
});
|
|
276
|
-
const res = await this.ctx.request('POST', '/auth/oauth/token', form, {
|
|
280
|
+
const res = await this.ctx.request('POST', '/auth/oauth/token', form, {
|
|
281
|
+
cache: false,
|
|
282
|
+
skipAuth: true,
|
|
283
|
+
});
|
|
277
284
|
if (!res || typeof res !== 'object') {
|
|
278
285
|
throw new Error('auth/oauth/token returned an unexpected response shape');
|
|
279
286
|
}
|
|
@@ -324,7 +331,9 @@ export class AuthOAuthApi {
|
|
|
324
331
|
* The response is a flat JSON document — no `{ data }` wrapper.
|
|
325
332
|
*/
|
|
326
333
|
async userInfo() {
|
|
327
|
-
const res = await this.ctx.request('GET', '/auth/oauth/userinfo', undefined, {
|
|
334
|
+
const res = await this.ctx.request('GET', '/auth/oauth/userinfo', undefined, {
|
|
335
|
+
cache: false,
|
|
336
|
+
});
|
|
328
337
|
if (!res || typeof res !== 'object') {
|
|
329
338
|
throw new Error('auth/oauth/userinfo returned an unexpected response shape');
|
|
330
339
|
}
|
|
@@ -652,12 +661,18 @@ export class AuthAgentApi {
|
|
|
652
661
|
}
|
|
653
662
|
async requestChallenge(publicKey) {
|
|
654
663
|
const body = agentChallengeRequestSchema.parse({ publicKey });
|
|
655
|
-
const response = await this.ctx.request('POST', '/auth/agent/challenge', body, {
|
|
664
|
+
const response = await this.ctx.request('POST', '/auth/agent/challenge', body, {
|
|
665
|
+
cache: false,
|
|
666
|
+
skipAuth: true,
|
|
667
|
+
});
|
|
656
668
|
return agentProofClaimsSchema.parse(response);
|
|
657
669
|
}
|
|
658
670
|
async verify(publicKey, proof) {
|
|
659
671
|
const body = agentVerifyRequestSchema.parse({ publicKey, ...proof });
|
|
660
|
-
const response = await this.ctx.request('POST', '/auth/agent/verify', body, {
|
|
672
|
+
const response = await this.ctx.request('POST', '/auth/agent/verify', body, {
|
|
673
|
+
cache: false,
|
|
674
|
+
skipAuth: true,
|
|
675
|
+
});
|
|
661
676
|
return plantSession(this.ctx, response, 'auth/agent/verify');
|
|
662
677
|
}
|
|
663
678
|
}
|
|
@@ -672,14 +687,19 @@ export class AuthApi {
|
|
|
672
687
|
this.agent = new AuthAgentApi(ctx);
|
|
673
688
|
}
|
|
674
689
|
/**
|
|
675
|
-
* Register a new
|
|
676
|
-
*
|
|
690
|
+
* Register a new account for a public key, together with its username.
|
|
691
|
+
*
|
|
692
|
+
* The username is required: the server writes it in the same insert as the
|
|
693
|
+
* key, so an account never exists without one. A taken username is a 409
|
|
694
|
+
* (`Username already taken`), as is a key that is already registered
|
|
695
|
+
* (`Identity already registered`).
|
|
677
696
|
*
|
|
678
697
|
* @param publicKey - The user's ECDSA public key (hex)
|
|
679
698
|
* @param signature - Signature of the registration request
|
|
680
699
|
* @param timestamp - Timestamp when the signature was created
|
|
700
|
+
* @param username - The account's username
|
|
681
701
|
*/
|
|
682
|
-
async registerKey(publicKey, signature, timestamp) {
|
|
702
|
+
async registerKey(publicKey, signature, timestamp, username) {
|
|
683
703
|
// Advisory for now (server soft-enforces — see
|
|
684
704
|
// `SessionController.register`), but solved unconditionally so every
|
|
685
705
|
// client is already sending it once the server starts requiring it.
|
|
@@ -689,6 +709,7 @@ export class AuthApi {
|
|
|
689
709
|
publicKey,
|
|
690
710
|
signature,
|
|
691
711
|
timestamp,
|
|
712
|
+
username,
|
|
692
713
|
powNonce,
|
|
693
714
|
}, { cache: false, skipAuth: true });
|
|
694
715
|
if (!res || (typeof res === 'object' && Object.keys(res).length === 0)) {
|
|
@@ -853,7 +874,10 @@ export class AuthApi {
|
|
|
853
874
|
*/
|
|
854
875
|
async checkUsername(username) {
|
|
855
876
|
// Public availability lookup (pre-session) — skip the bearer preflight.
|
|
856
|
-
return this.ctx.request('GET', `/auth/check-username/${username}`, undefined, {
|
|
877
|
+
return this.ctx.request('GET', `/auth/check-username/${username}`, undefined, {
|
|
878
|
+
cache: false,
|
|
879
|
+
skipAuth: true,
|
|
880
|
+
});
|
|
857
881
|
}
|
|
858
882
|
/**
|
|
859
883
|
* The authenticator's code (or a backup code) for a first factor's
|
|
@@ -871,7 +895,9 @@ export class AuthApi {
|
|
|
871
895
|
return plantSession(this.ctx, res, 'auth/signup');
|
|
872
896
|
}
|
|
873
897
|
async methods() {
|
|
874
|
-
const res = await this.ctx.request('GET', '/users/me/sign-in-methods', undefined, {
|
|
898
|
+
const res = await this.ctx.request('GET', '/users/me/sign-in-methods', undefined, {
|
|
899
|
+
cache: false,
|
|
900
|
+
});
|
|
875
901
|
const parsed = safeParseContract(signInMethodsSchema, res);
|
|
876
902
|
if (!parsed)
|
|
877
903
|
throw new Error('users/me/sign-in-methods returned an unexpected response shape');
|
package/dist/esm/api/billing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { personalPlanCheckoutRequestSchema, personalPlanCheckoutResultSchema } from '@oxy.so/contracts';
|
|
1
|
+
import { personalPlanCheckoutRequestSchema, personalPlanCheckoutResultSchema, } from '@oxy.so/contracts';
|
|
2
2
|
/**
|
|
3
3
|
* `oxy.billing` — the signed-in user's subscription, wallet and payment history.
|
|
4
4
|
*
|
|
@@ -24,7 +24,9 @@ export class BillingApi {
|
|
|
24
24
|
}
|
|
25
25
|
/** Public versioned personal plans. Discovery never proves customer access. */
|
|
26
26
|
async personalPlans() {
|
|
27
|
-
return personalPlanCatalogueSchema.parse(await this.ctx.request('GET', '/billing/personal-plans', undefined, {
|
|
27
|
+
return personalPlanCatalogueSchema.parse(await this.ctx.request('GET', '/billing/personal-plans', undefined, {
|
|
28
|
+
cache: false,
|
|
29
|
+
}));
|
|
28
30
|
}
|
|
29
31
|
/** Product rights only; requires a production application-bound user session. Never cached. */
|
|
30
32
|
async productAccess(query) {
|
|
@@ -34,19 +36,29 @@ export class BillingApi {
|
|
|
34
36
|
}
|
|
35
37
|
/** Named commercial sources for the current subject; no inferred plan collapse. */
|
|
36
38
|
async productSubscriptions(expectedSubjectAccountId) {
|
|
37
|
-
return productSubscriptionsResponseSchema.parse(await this.ctx.request(
|
|
39
|
+
return productSubscriptionsResponseSchema.parse(await this.ctx.request('GET', expectedSubjectAccountId
|
|
40
|
+
? `/billing/product-subscriptions?expectedSubjectAccountId=${encodeURIComponent(expectedSubjectAccountId)}`
|
|
41
|
+
: '/billing/product-subscriptions', undefined, { cache: false })).subscriptions;
|
|
38
42
|
}
|
|
39
43
|
/** Per-grant credit provenance; no interpretation of the historical mixed balance. */
|
|
40
44
|
async creditGrants() {
|
|
41
|
-
return subscriptionCreditGrantsResponseSchema.parse(await this.ctx.request(
|
|
45
|
+
return subscriptionCreditGrantsResponseSchema.parse(await this.ctx.request('GET', '/billing/credit-grants', undefined, { cache: false })).grants;
|
|
42
46
|
}
|
|
43
47
|
/** Payer-only named-source cancellation. Resolves on provider acceptance, including pending local reconciliation. Use cancelProductSubscriptionWithStatus for detailed completion state. */
|
|
44
48
|
async cancelProductSubscription(sourceId, expectedSubjectAccountId, actionId) {
|
|
45
|
-
await this.ctx.request(
|
|
49
|
+
await this.ctx.request('POST', '/billing/product-subscriptions/cancel', cancelProductSubscriptionSchema.parse({
|
|
50
|
+
sourceId,
|
|
51
|
+
...(actionId ? { actionId } : {}),
|
|
52
|
+
...(expectedSubjectAccountId ? { expectedSubjectAccountId } : {}),
|
|
53
|
+
}), { cache: false });
|
|
46
54
|
}
|
|
47
55
|
/** Provider acceptance versus completed local cancellation, for user-facing flows. */
|
|
48
56
|
async cancelProductSubscriptionWithStatus(sourceId, expectedSubjectAccountId, actionId) {
|
|
49
|
-
return productSubscriptionCancellationResultSchema.parse(await this.ctx.request('POST', '/billing/product-subscriptions/cancel', cancelProductSubscriptionSchema.parse({
|
|
57
|
+
return productSubscriptionCancellationResultSchema.parse(await this.ctx.request('POST', '/billing/product-subscriptions/cancel', cancelProductSubscriptionSchema.parse({
|
|
58
|
+
sourceId,
|
|
59
|
+
...(actionId ? { actionId } : {}),
|
|
60
|
+
...(expectedSubjectAccountId ? { expectedSubjectAccountId } : {}),
|
|
61
|
+
}), { cache: false }));
|
|
50
62
|
}
|
|
51
63
|
/** The signed-in user's payment history. Never cached. */
|
|
52
64
|
async payments() {
|
|
@@ -63,7 +75,10 @@ export class BillingApi {
|
|
|
63
75
|
/** A user's wallet (default: the signed-in user's). Cached briefly: the balance moves. */
|
|
64
76
|
async wallet(userId) {
|
|
65
77
|
const id = this.resolveUserId(userId);
|
|
66
|
-
return this.ctx.request('GET', `/wallet/${id}`, undefined, {
|
|
78
|
+
return this.ctx.request('GET', `/wallet/${id}`, undefined, {
|
|
79
|
+
cache: true,
|
|
80
|
+
cacheTTL: WALLET_TTL,
|
|
81
|
+
});
|
|
67
82
|
}
|
|
68
83
|
/** A page of a user's wallet transactions (default: the signed-in user's). Never cached. */
|
|
69
84
|
async walletTransactions(options = {}) {
|
|
@@ -73,7 +88,9 @@ export class BillingApi {
|
|
|
73
88
|
params.limit = options.limit;
|
|
74
89
|
if (options.offset)
|
|
75
90
|
params.offset = options.offset;
|
|
76
|
-
return this.ctx.request('GET', `/wallet/transactions/${id}`, params, {
|
|
91
|
+
return this.ctx.request('GET', `/wallet/transactions/${id}`, params, {
|
|
92
|
+
cache: false,
|
|
93
|
+
});
|
|
77
94
|
}
|
|
78
95
|
resolveUserId(userId) {
|
|
79
96
|
const id = userId || this.ctx.oxy.session.userId;
|