@oxy.so/core 4.5.0-oxy-one.1 → 4.6.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 +16 -3
- 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/models/interfaces.d.ts +9 -1
- 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 +3 -4
- package/src/HttpService.ts +183 -53
- package/src/OxyServices.errors.ts +7 -3
- package/src/OxyServices.ts +6 -2
- package/src/api/accounts.ts +96 -28
- 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 +39 -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
|
@@ -67,7 +67,13 @@ export class AssetsApi {
|
|
|
67
67
|
});
|
|
68
68
|
if (body.type && !headers.has('Content-Type'))
|
|
69
69
|
headers.set('Content-Type', body.type);
|
|
70
|
-
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
|
+
});
|
|
71
77
|
if (!result.ok)
|
|
72
78
|
throw new Error(`Presigned upload failed (${result.status})`);
|
|
73
79
|
}
|
|
@@ -85,7 +91,8 @@ export class AssetsApi {
|
|
|
85
91
|
const fileName = 'name' in file && file.name ? file.name : 'unknown';
|
|
86
92
|
const fileSize = 'size' in file && file.size ? file.size : 0;
|
|
87
93
|
const formData = new FormData();
|
|
88
|
-
if ((typeof File !== 'undefined' && file instanceof File) ||
|
|
94
|
+
if ((typeof File !== 'undefined' && file instanceof File) ||
|
|
95
|
+
(typeof Blob !== 'undefined' && file instanceof Blob)) {
|
|
89
96
|
formData.append('file', file, fileName);
|
|
90
97
|
}
|
|
91
98
|
else if ('uri' in file && typeof file.uri === 'string') {
|
|
@@ -101,7 +108,9 @@ export class AssetsApi {
|
|
|
101
108
|
throw new Error(`Failed to read file from uri (status ${res.status})`);
|
|
102
109
|
}
|
|
103
110
|
const fetched = await res.blob();
|
|
104
|
-
const blob = fetched.type === '' && descriptor.type
|
|
111
|
+
const blob = fetched.type === '' && descriptor.type
|
|
112
|
+
? new Blob([fetched], { type: descriptor.type })
|
|
113
|
+
: fetched;
|
|
105
114
|
if (blob.size === 0) {
|
|
106
115
|
throw new Error('Cannot upload an empty file');
|
|
107
116
|
}
|
|
@@ -125,7 +134,10 @@ export class AssetsApi {
|
|
|
125
134
|
}
|
|
126
135
|
catch (error) {
|
|
127
136
|
logger.error('File upload error', error, { component: 'oxy.assets' });
|
|
128
|
-
error.fileContext = {
|
|
137
|
+
error.fileContext = {
|
|
138
|
+
fileName,
|
|
139
|
+
fileSize,
|
|
140
|
+
};
|
|
129
141
|
throw error;
|
|
130
142
|
}
|
|
131
143
|
}
|
|
@@ -141,7 +153,9 @@ export class AssetsApi {
|
|
|
141
153
|
// ── Links ────────────────────────────────────────────────────────────────
|
|
142
154
|
/** Link an asset to an entity (what keeps it alive). */
|
|
143
155
|
async link(fileId, target, options = {}) {
|
|
144
|
-
const body = {
|
|
156
|
+
const body = {
|
|
157
|
+
...target,
|
|
158
|
+
};
|
|
145
159
|
if (options.visibility)
|
|
146
160
|
body.visibility = options.visibility;
|
|
147
161
|
if (options.webhookUrl)
|
|
@@ -161,7 +175,10 @@ export class AssetsApi {
|
|
|
161
175
|
// ── Reads ────────────────────────────────────────────────────────────────
|
|
162
176
|
/** An asset's record: size, mime, visibility, links, variants. */
|
|
163
177
|
async get(fileId) {
|
|
164
|
-
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
|
+
});
|
|
165
182
|
}
|
|
166
183
|
/** The signed-in user's files, newest first. */
|
|
167
184
|
async list(params = {}) {
|
|
@@ -174,7 +191,9 @@ export class AssetsApi {
|
|
|
174
191
|
}
|
|
175
192
|
/** The account's storage usage, aggregated from its assets. */
|
|
176
193
|
async usage() {
|
|
177
|
-
return this.ctx.request('GET', '/storage/usage', undefined, {
|
|
194
|
+
return this.ctx.request('GET', '/storage/usage', undefined, {
|
|
195
|
+
cache: false,
|
|
196
|
+
});
|
|
178
197
|
}
|
|
179
198
|
// ── URLs ─────────────────────────────────────────────────────────────────
|
|
180
199
|
/**
|
|
@@ -256,7 +275,9 @@ export class AssetsApi {
|
|
|
256
275
|
body.expiresIn = options.expiresIn;
|
|
257
276
|
if (typeof options?.context === 'string')
|
|
258
277
|
body.context = options.context;
|
|
259
|
-
return this.ctx.request('POST', '/assets/batch-access', body, {
|
|
278
|
+
return this.ctx.request('POST', '/assets/batch-access', body, {
|
|
279
|
+
cache: false,
|
|
280
|
+
});
|
|
260
281
|
}
|
|
261
282
|
// ── Content ──────────────────────────────────────────────────────────────
|
|
262
283
|
/** An asset's content as text. */
|
|
@@ -276,7 +297,9 @@ export class AssetsApi {
|
|
|
276
297
|
*/
|
|
277
298
|
async delete(fileId, options = {}) {
|
|
278
299
|
const url = `/assets/${enc(fileId)}${options.force ? '?force=true' : ''}`;
|
|
279
|
-
const res = await this.ctx.request('DELETE', url, undefined, {
|
|
300
|
+
const res = await this.ctx.request('DELETE', url, undefined, {
|
|
301
|
+
cache: false,
|
|
302
|
+
});
|
|
280
303
|
this.evict(fileId);
|
|
281
304
|
return res;
|
|
282
305
|
}
|
|
@@ -318,7 +341,10 @@ export class AssetsApi {
|
|
|
318
341
|
}
|
|
319
342
|
/** Drop the cached record and every cached URL variant of an asset, in one pass. */
|
|
320
343
|
evict(fileId) {
|
|
321
|
-
this.ctx.http.invalidateCache({
|
|
344
|
+
this.ctx.http.invalidateCache({
|
|
345
|
+
keys: [`GET:/assets/${enc(fileId)}`],
|
|
346
|
+
prefixes: [`GET:/assets/${enc(fileId)}/url`],
|
|
347
|
+
});
|
|
322
348
|
}
|
|
323
349
|
}
|
|
324
350
|
const enc = encodeURIComponent;
|
|
@@ -337,7 +363,9 @@ function dedupeFileAccessRequests(requests) {
|
|
|
337
363
|
if (seen.has(key))
|
|
338
364
|
continue;
|
|
339
365
|
seen.add(key);
|
|
340
|
-
out.push(req.variant === undefined
|
|
366
|
+
out.push(req.variant === undefined
|
|
367
|
+
? { fileId: req.fileId }
|
|
368
|
+
: { fileId: req.fileId, variant: req.variant });
|
|
341
369
|
}
|
|
342
370
|
return out;
|
|
343
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
|
}
|
|
@@ -859,7 +874,10 @@ export class AuthApi {
|
|
|
859
874
|
*/
|
|
860
875
|
async checkUsername(username) {
|
|
861
876
|
// Public availability lookup (pre-session) — skip the bearer preflight.
|
|
862
|
-
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
|
+
});
|
|
863
881
|
}
|
|
864
882
|
/**
|
|
865
883
|
* The authenticator's code (or a backup code) for a first factor's
|
|
@@ -877,7 +895,9 @@ export class AuthApi {
|
|
|
877
895
|
return plantSession(this.ctx, res, 'auth/signup');
|
|
878
896
|
}
|
|
879
897
|
async methods() {
|
|
880
|
-
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
|
+
});
|
|
881
901
|
const parsed = safeParseContract(signInMethodsSchema, res);
|
|
882
902
|
if (!parsed)
|
|
883
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;
|
package/dist/esm/api/civic.js
CHANGED
|
@@ -91,7 +91,9 @@ export class CivicApi {
|
|
|
91
91
|
...(input.geohash !== undefined ? { geohash: input.geohash } : {}),
|
|
92
92
|
...(input.biometricOk !== undefined ? { biometricOk: input.biometricOk } : {}),
|
|
93
93
|
}, { collection: ATTEST_COLLECTION, rkey: input.nonce });
|
|
94
|
-
return this.ctx.request('POST', '/civic/attestations', envelope, {
|
|
94
|
+
return this.ctx.request('POST', '/civic/attestations', envelope, {
|
|
95
|
+
cache: false,
|
|
96
|
+
});
|
|
95
97
|
}
|
|
96
98
|
/**
|
|
97
99
|
* Vouch that another user is a real person as the VOUCHER (B): sign a
|
|
@@ -187,7 +189,9 @@ export class CivicCredentialsApi {
|
|
|
187
189
|
* base type; an `expiresAt` ISO string becomes epoch ms. NATIVE-ONLY.
|
|
188
190
|
*/
|
|
189
191
|
async issue(input) {
|
|
190
|
-
const types = input.types.includes(CREDENTIAL_BASE_TYPE)
|
|
192
|
+
const types = input.types.includes(CREDENTIAL_BASE_TYPE)
|
|
193
|
+
? input.types
|
|
194
|
+
: [CREDENTIAL_BASE_TYPE, ...input.types];
|
|
191
195
|
let expiresAtMs;
|
|
192
196
|
if (input.expiresAt !== undefined) {
|
|
193
197
|
const parsed = Date.parse(input.expiresAt);
|
|
@@ -205,7 +209,10 @@ export class CivicCredentialsApi {
|
|
|
205
209
|
// A fresh crypto-random rkey: every credential is its own chain entry.
|
|
206
210
|
const { SignatureService } = await import('../crypto/internal.js');
|
|
207
211
|
const rkey = await SignatureService.generateChallenge();
|
|
208
|
-
const envelope = await signOwnChainRecord(this.ctx, 'credential', record, {
|
|
212
|
+
const envelope = await signOwnChainRecord(this.ctx, 'credential', record, {
|
|
213
|
+
collection: CREDENTIAL_COLLECTION,
|
|
214
|
+
rkey,
|
|
215
|
+
});
|
|
209
216
|
const result = await this.ctx.request('POST', '/civic/credentials', envelope, { cache: false });
|
|
210
217
|
this.sweep();
|
|
211
218
|
return result;
|
|
@@ -223,7 +230,10 @@ export class CivicCredentialsApi {
|
|
|
223
230
|
}
|
|
224
231
|
const base = `/civic/credentials/${encodeURIComponent(holder)}`;
|
|
225
232
|
const url = opts.status ? `${base}?status=${encodeURIComponent(opts.status)}` : base;
|
|
226
|
-
return this.ctx.request('GET', url, undefined, {
|
|
233
|
+
return this.ctx.request('GET', url, undefined, {
|
|
234
|
+
cache: true,
|
|
235
|
+
cacheTTL: SHORT_TTL,
|
|
236
|
+
});
|
|
227
237
|
}
|
|
228
238
|
/**
|
|
229
239
|
* Verify a credential by its signed-record id: the server re-checks the
|