@oxy.so/core 4.5.0-oxy-one.1 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/HttpService.js +63 -19
- package/dist/cjs/api/accounts.js +10 -3
- package/dist/cjs/api/agency.js +3 -1
- package/dist/cjs/api/apps.js +15 -4
- package/dist/cjs/api/assets.js +39 -11
- package/dist/cjs/api/auth.js +28 -8
- package/dist/cjs/api/billing.js +24 -7
- package/dist/cjs/api/civic.js +14 -4
- package/dist/cjs/api/follows.js +9 -2
- package/dist/cjs/api/identity.js +31 -9
- package/dist/cjs/api/nodes.js +3 -1
- package/dist/cjs/api/privacy.js +8 -2
- package/dist/cjs/api/session.js +15 -4
- package/dist/cjs/api/store.js +15 -5
- package/dist/cjs/api/topics.js +10 -3
- package/dist/cjs/api/users.js +16 -4
- package/dist/cjs/boot/sessionColdBoot.js +40 -13
- package/dist/cjs/constants/version.js +6 -6
- package/dist/cjs/crypto/identityMarker.js +3 -1
- package/dist/cjs/crypto/identityProof.js +6 -1
- package/dist/cjs/crypto/keyManager.js +87 -32
- package/dist/cjs/crypto/recoveryPhrase.js +2 -2
- package/dist/cjs/crypto/signatureService.js +3 -4
- package/dist/cjs/i18n/index.js +16 -3
- package/dist/cjs/i18n/locales/ar-SA.js +366 -366
- package/dist/cjs/i18n/locales/ca-ES.js +366 -366
- package/dist/cjs/i18n/locales/de-DE.js +366 -366
- package/dist/cjs/i18n/locales/en-US.js +1994 -1994
- package/dist/cjs/i18n/locales/es-ES.js +1994 -1994
- package/dist/cjs/i18n/locales/fr-FR.js +366 -366
- package/dist/cjs/i18n/locales/it-IT.js +366 -366
- package/dist/cjs/i18n/locales/ja-JP.js +366 -366
- package/dist/cjs/i18n/locales/ko-KR.js +366 -366
- package/dist/cjs/i18n/locales/pt-PT.js +366 -366
- package/dist/cjs/i18n/locales/zh-CN.js +366 -366
- package/dist/cjs/inference/OxyInferenceClient.js +12 -18
- package/dist/cjs/models/interfaces.js +11 -11
- package/dist/cjs/server/OxyServer.js +86 -28
- package/dist/cjs/server/agentAccount.js +6 -2
- package/dist/cjs/server/aliaMachineCredential.js +39 -14
- package/dist/cjs/server/auth.js +5 -4
- package/dist/cjs/server/capabilityTicket.js +5 -5
- package/dist/cjs/server/index.js +2 -1
- package/dist/cjs/server/liveCapabilityTicket.js +4 -1
- package/dist/cjs/server/middleware.js +61 -42
- package/dist/cjs/server/namespaces.js +28 -7
- package/dist/cjs/server/requesterAssertion.js +36 -30
- package/dist/cjs/server/serviceTokenLifetime.js +7 -4
- package/dist/cjs/server/traffic.js +53 -14
- package/dist/cjs/server/trafficNodeHttp.js +33 -8
- package/dist/cjs/server/workloadIdentity.client.js +4 -0
- package/dist/cjs/server/workloadIdentity.js +28 -1
- package/dist/cjs/session/SessionClient.js +54 -17
- package/dist/cjs/session/accountDelegationAccess.js +4 -6
- package/dist/cjs/session/accountDialogController.js +1 -1
- package/dist/cjs/session/authStateStore.js +18 -9
- package/dist/cjs/session/identityPin.js +6 -2
- package/dist/cjs/session/refresh.js +81 -23
- package/dist/cjs/session/sharedDeviceCredential.js +28 -15
- package/dist/cjs/shared/utils/errorUtils.js +1 -1
- package/dist/cjs/shared/utils/networkUtils.js +1 -1
- package/dist/cjs/shared/utils/themeUtils.js +1 -1
- package/dist/cjs/utils/accountCacheSweep.js +3 -1
- package/dist/cjs/utils/accountUtils.js +1 -3
- package/dist/cjs/utils/asyncUtils.js +1 -1
- package/dist/cjs/utils/authHelpers.js +2 -1
- package/dist/cjs/utils/avatarUtils.js +4 -2
- package/dist/cjs/utils/cache.js +1 -1
- package/dist/cjs/utils/cacheKey.js +3 -1
- package/dist/cjs/utils/deviceManager.js +4 -4
- package/dist/cjs/utils/errorUtils.js +6 -4
- package/dist/cjs/utils/languageUtils.js +404 -57
- package/dist/cjs/utils/profileLinks.js +1 -3
- package/dist/cjs/utils/requestUtils.js +7 -1
- package/dist/cjs/utils/userIdentity.js +1 -1
- package/dist/cjs/utils/validationUtils.js +5 -6
- package/dist/esm/HttpService.js +64 -20
- package/dist/esm/api/accounts.js +11 -4
- package/dist/esm/api/agency.js +3 -1
- package/dist/esm/api/apps.js +15 -4
- package/dist/esm/api/assets.js +39 -11
- package/dist/esm/api/auth.js +28 -8
- package/dist/esm/api/billing.js +25 -8
- package/dist/esm/api/civic.js +14 -4
- package/dist/esm/api/follows.js +9 -2
- package/dist/esm/api/identity.js +31 -9
- package/dist/esm/api/nodes.js +3 -1
- package/dist/esm/api/privacy.js +8 -2
- package/dist/esm/api/session.js +15 -4
- package/dist/esm/api/store.js +15 -5
- package/dist/esm/api/topics.js +10 -3
- package/dist/esm/api/users.js +16 -4
- package/dist/esm/boot/sessionColdBoot.js +41 -14
- package/dist/esm/constants/version.js +6 -6
- package/dist/esm/crypto/identityMarker.js +3 -1
- package/dist/esm/crypto/identityProof.js +6 -1
- package/dist/esm/crypto/internal.js +1 -1
- package/dist/esm/crypto/keyManager.js +87 -32
- package/dist/esm/crypto/recoveryPhrase.js +2 -2
- package/dist/esm/crypto/signatureService.js +3 -4
- package/dist/esm/i18n/index.js +16 -3
- package/dist/esm/i18n/locales/ar-SA.js +366 -366
- package/dist/esm/i18n/locales/ca-ES.js +366 -366
- package/dist/esm/i18n/locales/de-DE.js +366 -366
- package/dist/esm/i18n/locales/en-US.js +1994 -1994
- package/dist/esm/i18n/locales/es-ES.js +1994 -1994
- package/dist/esm/i18n/locales/fr-FR.js +366 -366
- package/dist/esm/i18n/locales/it-IT.js +366 -366
- package/dist/esm/i18n/locales/ja-JP.js +366 -366
- package/dist/esm/i18n/locales/ko-KR.js +366 -366
- package/dist/esm/i18n/locales/pt-PT.js +366 -366
- package/dist/esm/i18n/locales/zh-CN.js +366 -366
- package/dist/esm/index.js +1 -1
- package/dist/esm/inference/OxyInferenceClient.js +13 -19
- package/dist/esm/models/interfaces.js +11 -11
- package/dist/esm/server/OxyServer.js +87 -29
- package/dist/esm/server/agentAccount.js +6 -2
- package/dist/esm/server/aliaMachineCredential.js +39 -14
- package/dist/esm/server/auth.js +6 -5
- package/dist/esm/server/capabilityTicket.js +6 -6
- package/dist/esm/server/index.js +5 -5
- package/dist/esm/server/liveCapabilityTicket.js +6 -3
- package/dist/esm/server/middleware.js +62 -43
- package/dist/esm/server/namespaces.js +31 -10
- package/dist/esm/server/requesterAssertion.js +36 -30
- package/dist/esm/server/serviceTokenLifetime.js +7 -4
- package/dist/esm/server/traffic.js +55 -16
- package/dist/esm/server/trafficNodeHttp.js +34 -9
- package/dist/esm/server/userInvalidation.js +1 -1
- package/dist/esm/server/workloadIdentity.client.js +3 -0
- package/dist/esm/server/workloadIdentity.js +27 -1
- package/dist/esm/session/SessionClient.js +54 -17
- package/dist/esm/session/accountDelegationAccess.js +5 -7
- package/dist/esm/session/accountDialogController.js +1 -1
- package/dist/esm/session/authStateStore.js +18 -9
- package/dist/esm/session/identityPin.js +6 -2
- package/dist/esm/session/refresh.js +82 -24
- package/dist/esm/session/sharedDeviceCredential.js +28 -15
- package/dist/esm/shared/utils/errorUtils.js +1 -1
- package/dist/esm/shared/utils/networkUtils.js +1 -1
- package/dist/esm/shared/utils/themeUtils.js +1 -1
- package/dist/esm/utils/accountCacheSweep.js +3 -1
- package/dist/esm/utils/accountUtils.js +1 -3
- package/dist/esm/utils/asyncUtils.js +1 -1
- package/dist/esm/utils/authHelpers.js +2 -1
- package/dist/esm/utils/avatarUtils.js +4 -2
- package/dist/esm/utils/cache.js +1 -1
- package/dist/esm/utils/cacheKey.js +3 -1
- package/dist/esm/utils/deviceManager.js +4 -4
- package/dist/esm/utils/errorUtils.js +6 -4
- package/dist/esm/utils/languageUtils.js +404 -57
- package/dist/esm/utils/profileLinks.js +1 -3
- package/dist/esm/utils/requestUtils.js +7 -1
- package/dist/esm/utils/userIdentity.js +1 -1
- package/dist/esm/utils/validationUtils.js +5 -6
- package/dist/types/HttpService.d.ts +1 -1
- package/dist/types/api/accounts.d.ts +1 -1
- package/dist/types/api/apps.d.ts +4 -4
- package/dist/types/crypto/internal.d.ts +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/server/index.d.ts +6 -6
- package/dist/types/server/workloadIdentity.client.d.ts +5 -1
- package/dist/types/server/workloadIdentity.d.ts +26 -0
- package/dist/types/session/accountDelegationAccess.d.ts +1 -1
- package/dist/types/session/index.d.ts +1 -1
- package/dist/types/utils/userIdentity.d.ts +1 -1
- package/dist/types/utils/validationUtils.d.ts +4 -5
- package/package.json +2 -3
- package/src/HttpService.ts +183 -53
- package/src/OxyServices.errors.ts +7 -3
- package/src/OxyServices.ts +6 -2
- package/src/api/accounts.ts +76 -26
- package/src/api/agency.ts +24 -9
- package/src/api/appData.ts +12 -2
- package/src/api/apps.ts +81 -31
- package/src/api/assets.ts +113 -43
- package/src/api/auth.ts +145 -77
- package/src/api/billing.ts +112 -65
- package/src/api/civic.ts +61 -19
- package/src/api/contacts.ts +4 -1
- package/src/api/devices.ts +54 -21
- package/src/api/follows.ts +88 -31
- package/src/api/identity.ts +101 -33
- package/src/api/linkedAccounts.ts +26 -8
- package/src/api/nodes.ts +18 -6
- package/src/api/notifications.ts +26 -6
- package/src/api/privacy.ts +42 -8
- package/src/api/reputation.ts +18 -7
- package/src/api/session.ts +23 -5
- package/src/api/store.ts +81 -31
- package/src/api/topics.ts +18 -6
- package/src/api/users.ts +98 -35
- package/src/boot/sessionColdBoot.ts +60 -19
- package/src/civic/payloads.ts +1 -4
- package/src/client/context.ts +6 -1
- package/src/constants/version.ts +7 -6
- package/src/crypto/aead.ts +1 -5
- package/src/crypto/ecdh.ts +1 -4
- package/src/crypto/identityDerivations.ts +5 -1
- package/src/crypto/identityMarker.ts +3 -1
- package/src/crypto/identityProof.ts +6 -1
- package/src/crypto/index.ts +11 -11
- package/src/crypto/internal.ts +6 -1
- package/src/crypto/keyManager.ts +348 -98
- package/src/crypto/recoveryPhrase.ts +14 -9
- package/src/crypto/registrationPow.ts +1 -1
- package/src/crypto/signatureService.ts +14 -6
- package/src/i18n/accountCategoryLabels.ts +1 -4
- package/src/i18n/accountRoleLabels.ts +1 -4
- package/src/i18n/index.ts +25 -7
- package/src/i18n/locales/ar-SA.ts +375 -366
- package/src/i18n/locales/ca-ES.ts +382 -366
- package/src/i18n/locales/de-DE.ts +387 -366
- package/src/i18n/locales/en-US.ts +2034 -1994
- package/src/i18n/locales/es-ES.ts +2043 -1994
- package/src/i18n/locales/fr-FR.ts +387 -366
- package/src/i18n/locales/it-IT.ts +380 -366
- package/src/i18n/locales/ja-JP.ts +380 -366
- package/src/i18n/locales/ko-KR.ts +377 -366
- package/src/i18n/locales/pt-PT.ts +383 -366
- package/src/i18n/locales/zh-CN.ts +373 -366
- package/src/i18n/trustTierLabels.ts +1 -4
- package/src/index.ts +371 -349
- package/src/inference/OxyInferenceClient.ts +784 -780
- package/src/models/interfaces.ts +30 -27
- package/src/server/OxyServer.ts +227 -68
- package/src/server/agentAccount.ts +8 -2
- package/src/server/aliaMachineCredential.ts +57 -16
- package/src/server/auth.ts +9 -5
- package/src/server/capabilityTicket.ts +30 -21
- package/src/server/index.ts +29 -6
- package/src/server/liveCapabilityTicket.ts +31 -9
- package/src/server/middleware.ts +212 -121
- package/src/server/namespaces.ts +247 -94
- package/src/server/rateLimit.ts +2 -4
- package/src/server/requesterAssertion.ts +93 -54
- package/src/server/serviceTokenLifetime.ts +9 -4
- package/src/server/traffic.ts +117 -23
- package/src/server/trafficNodeHttp.ts +61 -14
- package/src/server/userInvalidation.ts +1 -4
- package/src/server/workloadIdentity.client.ts +12 -1
- package/src/server/workloadIdentity.ts +52 -5
- package/src/session/SessionClient.ts +170 -49
- package/src/session/accountDelegationAccess.ts +24 -31
- package/src/session/accountDialogController.ts +59 -14
- package/src/session/accountSwitchTargets.ts +10 -15
- package/src/session/authStateStore.ts +121 -81
- package/src/session/deviceDirectory.ts +1 -3
- package/src/session/identityPin.ts +10 -11
- package/src/session/identitySession.ts +3 -1
- package/src/session/index.ts +87 -82
- package/src/session/refresh.ts +138 -44
- package/src/session/sessionClientHost.ts +1 -3
- package/src/session/sharedDeviceCredential.ts +35 -14
- package/src/session/socketLoader.ts +9 -2
- package/src/shared/utils/errorUtils.ts +5 -2
- package/src/shared/utils/networkUtils.ts +5 -8
- package/src/shared/utils/themeUtils.ts +2 -6
- package/src/types/buffer.d.ts +66 -21
- package/src/types/expo-secure-store.d.ts +5 -1
- package/src/utils/accountCacheSweep.ts +4 -5
- package/src/utils/accountUtils.ts +107 -108
- package/src/utils/apiUtils.ts +3 -3
- package/src/utils/asyncUtils.ts +2 -2
- package/src/utils/authHelpers.ts +10 -5
- package/src/utils/avatarUtils.ts +11 -6
- package/src/utils/cache.ts +9 -10
- package/src/utils/cacheKey.ts +5 -1
- package/src/utils/coldBoot.ts +1 -3
- package/src/utils/commonsDelivery.ts +1 -4
- package/src/utils/deviceManager.ts +15 -14
- package/src/utils/errorUtils.ts +68 -86
- package/src/utils/languageUtils.ts +407 -58
- package/src/utils/oauthPkce.ts +1 -4
- package/src/utils/platform.ts +0 -1
- package/src/utils/profileLinks.ts +2 -5
- package/src/utils/requestUtils.ts +18 -14
- package/src/utils/sessionUtils.ts +34 -33
- package/src/utils/userHandle.ts +3 -1
- package/src/utils/userIdentity.ts +1 -1
- package/src/utils/validationUtils.ts +11 -9
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* app.use('/api', createOxyAuthMiddleware(oxy));
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
export { OxyServer, ServiceCredentialMismatchError, ANONYMOUS_SERVICE_TOKEN_RETRY_MS } from './OxyServer';
|
|
17
|
+
export { OxyServer, ServiceCredentialMismatchError, ANONYMOUS_SERVICE_TOKEN_RETRY_MS, } from './OxyServer';
|
|
18
18
|
export type { OxyServerConfig, ServiceTokenResponse } from './OxyServer';
|
|
19
19
|
export { ServerAppsApi, ServerAgencyApi, ServerAssetsApi, ServerLinkedAccountsApi, ServerNotificationsApi, ServerReputationApi, } from './namespaces';
|
|
20
20
|
export { createOxyAliaMachineCredentialAuth, getOxyAliaMachineCredentialBearer, isOxyAliaMachinePrincipal, OXY_ALIA_RESOURCE_APPLICATION_ID, OXY_ALIA_MACHINE_SCOPES, } from './aliaMachineCredential';
|
|
@@ -42,10 +42,10 @@ export { createLiveCapabilityTicketVerifier } from './liveCapabilityTicket';
|
|
|
42
42
|
export type { LiveCapabilityTicketVerifierOptions } from './liveCapabilityTicket';
|
|
43
43
|
export { createOxyUserInvalidationHandler, publishOxyUserInvalidation, } from './userInvalidation';
|
|
44
44
|
export type { OxyInvalidationPublisher, OxyUserInvalidationHandlerOptions, } from './userInvalidation';
|
|
45
|
-
export { evictOxyIdentityCache, oxyUserByIdCacheKey, OXY_IDENTITY_CACHE_PREFIXES } from '../utils/identityCacheSweep';
|
|
45
|
+
export { evictOxyIdentityCache, oxyUserByIdCacheKey, OXY_IDENTITY_CACHE_PREFIXES, } from '../utils/identityCacheSweep';
|
|
46
46
|
export type { OxyIdentityCacheEvictor } from '../utils/identityCacheSweep';
|
|
47
47
|
export { registrableApex } from '../utils/registrableApex';
|
|
48
|
-
export { isLoopbackOrigin, isOfficialWebOrigin, isAllowedDeviceJoinOrigin } from '../utils/officialOrigins';
|
|
48
|
+
export { isLoopbackOrigin, isOfficialWebOrigin, isAllowedDeviceJoinOrigin, } from '../utils/officialOrigins';
|
|
49
49
|
export { createEcosystemTraffic } from './traffic';
|
|
50
50
|
export type { EcosystemTrafficOptions } from './traffic';
|
|
51
51
|
export { observeNodeHttp, withoutNodeHttpObservation } from './trafficNodeHttp';
|
|
@@ -55,8 +55,8 @@ export { observeNodeHttp, withoutNodeHttpObservation } from './trafficNodeHttp';
|
|
|
55
55
|
* exported from this subpath rather than the root barrel because it reaches the
|
|
56
56
|
* container credentials endpoint.
|
|
57
57
|
*/
|
|
58
|
-
export { canAttestWorkloadIdentity, requestWorkloadServiceToken } from './workloadIdentity';
|
|
59
|
-
export type { WorkloadServiceToken, WorkloadServiceTokenOptions } from './workloadIdentity';
|
|
60
|
-
export { OXY_SERVICE_TOKEN_MAX_LIFETIME_SECONDS, hasBoundedServiceTokenLifetime } from './serviceTokenLifetime';
|
|
58
|
+
export { attestWorkloadIdentity, canAttestWorkloadIdentity, requestWorkloadServiceToken, } from './workloadIdentity';
|
|
59
|
+
export type { WorkloadAttestation, WorkloadServiceToken, WorkloadServiceTokenOptions, } from './workloadIdentity';
|
|
60
|
+
export { OXY_SERVICE_TOKEN_MAX_LIFETIME_SECONDS, hasBoundedServiceTokenLifetime, } from './serviceTokenLifetime';
|
|
61
61
|
export { signInAgentAccount } from './agentAccount';
|
|
62
62
|
export type { AgentAccountSigner } from './agentAccount';
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type { WorkloadServiceToken, WorkloadServiceTokenOptions } from './workloadIdentity';
|
|
1
|
+
import type { WorkloadAttestation, WorkloadServiceToken, WorkloadServiceTokenOptions } from './workloadIdentity';
|
|
2
2
|
/** Workload attestation belongs to a Node host, never a browser or device. */
|
|
3
3
|
export declare function canAttestWorkloadIdentity(): boolean;
|
|
4
4
|
export declare function requestWorkloadServiceToken(_options: WorkloadServiceTokenOptions): Promise<WorkloadServiceToken>;
|
|
5
|
+
export declare function attestWorkloadIdentity(_options: {
|
|
6
|
+
nonce: string;
|
|
7
|
+
fetch?: typeof fetch;
|
|
8
|
+
}): Promise<WorkloadAttestation>;
|
|
@@ -18,6 +18,32 @@ export interface WorkloadServiceToken {
|
|
|
18
18
|
* checkout has no attestation to offer and must fall back to a credential.
|
|
19
19
|
*/
|
|
20
20
|
export declare function canAttestWorkloadIdentity(env?: NodeJS.ProcessEnv): boolean;
|
|
21
|
+
/** A proof of this process's identity, exactly as `POST /auth/service-token/workload` takes it. */
|
|
22
|
+
export interface WorkloadAttestation {
|
|
23
|
+
provider: 'aws-iam';
|
|
24
|
+
attestation: {
|
|
25
|
+
headers: Record<string, string>;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Signs this process's identity proof over a nonce the CALLER chose, and sends
|
|
30
|
+
* it nowhere.
|
|
31
|
+
*
|
|
32
|
+
* {@link requestWorkloadServiceToken} is the ordinary consumer: Oxy issues the
|
|
33
|
+
* nonce and replays the proof. This exists for the one host that is its own
|
|
34
|
+
* verifier — Oxy's API acting as an application it hosts (Inbox) needs to learn
|
|
35
|
+
* which role it runs as, and the honest way to learn that is the way it learns
|
|
36
|
+
* anyone else's: sign `GetCallerIdentity` and let STS say whose signature it is.
|
|
37
|
+
* Reading a role name out of configuration would be the process's own word for
|
|
38
|
+
* what it is, which is what ADR 0026 refuses from every other caller.
|
|
39
|
+
*
|
|
40
|
+
* The same signer, so the two can never disagree about the shape the verifier
|
|
41
|
+
* accepts. Throws exactly as the token path does when there is no identity here.
|
|
42
|
+
*/
|
|
43
|
+
export declare function attestWorkloadIdentity(options: {
|
|
44
|
+
nonce: string;
|
|
45
|
+
fetch?: typeof fetch;
|
|
46
|
+
}): Promise<WorkloadAttestation>;
|
|
21
47
|
/**
|
|
22
48
|
* Exchanges this process's identity for an Oxy service token.
|
|
23
49
|
*
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* (or the structural subset below), so the SDK and every agent runtime read the
|
|
14
14
|
* API's already-resolved relationship and effective permissions identically.
|
|
15
15
|
*/
|
|
16
|
-
import type { AccountKind, AccountMember, AccountRelationship } from
|
|
16
|
+
import type { AccountKind, AccountMember, AccountRelationship } from '../api/accounts';
|
|
17
17
|
export interface AccountDelegationAccess {
|
|
18
18
|
/** The caller owns the account or has a live membership in it. */
|
|
19
19
|
readonly hasStanding: boolean;
|
|
@@ -10,7 +10,7 @@ import '../crypto/polyfill';
|
|
|
10
10
|
export { DeviceManager } from '../utils/deviceManager';
|
|
11
11
|
export type { DeviceFingerprint, StoredDeviceInfo } from '../utils/deviceManager';
|
|
12
12
|
export { SessionClient } from './SessionClient';
|
|
13
|
-
export type { TokenTransport, SessionClientHost, SessionClientOptions, DeviceCredential, SessionStateOrigin } from './SessionClient';
|
|
13
|
+
export type { TokenTransport, SessionClientHost, SessionClientOptions, DeviceCredential, SessionStateOrigin, } from './SessionClient';
|
|
14
14
|
export type { SocketIOFactory, MinimalSocket } from './socketLoader';
|
|
15
15
|
export { createSessionClientHost } from './sessionClientHost';
|
|
16
16
|
export { createSessionClient } from './createSessionClient';
|
|
@@ -4,7 +4,7 @@ interface UserIdentityInput {
|
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
6
|
* Returns the stable SDK user id from API payloads that may use either `id` or
|
|
7
|
-
*
|
|
7
|
+
* a raw `_id`.
|
|
8
8
|
*/
|
|
9
9
|
export declare function getNormalizedUserId(user: UserIdentityInput | null | undefined): string | null;
|
|
10
10
|
/**
|
|
@@ -65,10 +65,10 @@ export declare function isValidPassword(password: string): boolean;
|
|
|
65
65
|
* — script digits (`٠١٢`, `०१२`), 1082 symbols (`֍ ۞ ৳`), 180 punctuation marks
|
|
66
66
|
* (`։ ، ؛ ।`), and 9 INVISIBLE format/control characters, among them U+061C
|
|
67
67
|
* ARABIC LETTER MARK (a bidi control that can visually reorder a name) and
|
|
68
|
-
* U+180E
|
|
68
|
+
* U+180E (the Mong-script vowel separator). Without it the rejections listed above held
|
|
69
69
|
* for ASCII input only. It is the set of scripts Unicode UTS #39 marks
|
|
70
70
|
* "Recommended" for general interchange / identifiers, plus Cherokee and
|
|
71
|
-
*
|
|
71
|
+
* the Mong script, ISO 15924 (both in real modern name use). "Common" script is deliberately
|
|
72
72
|
* EXCLUDED — that is where ASCII digits and general punctuation live, and this
|
|
73
73
|
* policy excludes those; the space separators, combining marks, and apostrophe a
|
|
74
74
|
* name needs are added back explicitly. Limited-use / excluded / historic
|
|
@@ -257,9 +257,8 @@ export declare function sanitizeString(input: string): string;
|
|
|
257
257
|
*/
|
|
258
258
|
export declare function sanitizeHTML(input: string): string;
|
|
259
259
|
/**
|
|
260
|
-
* Validate
|
|
261
|
-
*
|
|
262
|
-
* This function works in environments where mongoose may not be available (e.g., client-side)
|
|
260
|
+
* Validate the legacy 24-hex id format (a format check only; it does not
|
|
261
|
+
* prove the id exists).
|
|
263
262
|
*/
|
|
264
263
|
export declare function isValidObjectId(id: string): boolean;
|
|
265
264
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxy.so/core",
|
|
3
|
-
"version": "4.5.0
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "OxyHQ SDK Foundation — API client, authentication, cryptographic identity, and shared utilities",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
"@oxy.so/telemetry": "^1.2.0",
|
|
180
180
|
"@noble/ciphers": "^1.3.0",
|
|
181
181
|
"@noble/hashes": "^1.8.0",
|
|
182
|
-
"@oxy.so/contracts": "4.
|
|
182
|
+
"@oxy.so/contracts": "4.12.0",
|
|
183
183
|
"@oxy.so/protocol": "^1.2.2",
|
|
184
184
|
"@scure/bip39": "^1.6.0",
|
|
185
185
|
"buffer": "^6.0.3",
|
|
@@ -212,7 +212,6 @@
|
|
|
212
212
|
}
|
|
213
213
|
},
|
|
214
214
|
"devDependencies": {
|
|
215
|
-
"@biomejs/biome": "^1.9.4",
|
|
216
215
|
"@react-native-async-storage/async-storage": "^2.2.0",
|
|
217
216
|
"@types/express": "^4.17.25",
|
|
218
217
|
"@types/invariant": "^2.2.34",
|
package/src/HttpService.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Unified HTTP Service
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Consolidates HttpClient + RequestManager into a single efficient class.
|
|
5
5
|
* Uses native fetch instead of axios for smaller bundle size.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Handles:
|
|
8
8
|
* - Authentication (token management, auto-refresh)
|
|
9
9
|
* - Caching (TTL-based)
|
|
@@ -16,7 +16,13 @@
|
|
|
16
16
|
import { TTLCache, registerCacheForCleanup, unregisterCacheFromCleanup } from './utils/cache';
|
|
17
17
|
import { RequestDeduplicator, RequestQueue, SimpleLogger } from './utils/requestUtils';
|
|
18
18
|
import { retryAsync } from './utils/asyncUtils';
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
createCancelledError,
|
|
21
|
+
ErrorCodes,
|
|
22
|
+
handleHttpError,
|
|
23
|
+
isCancelledError,
|
|
24
|
+
parseHttpErrorBody,
|
|
25
|
+
} from './utils/errorUtils';
|
|
20
26
|
import { decodeTokenClaims } from './utils/tokenClaims';
|
|
21
27
|
import { isReactNative } from '@oxy.so/protocol/random';
|
|
22
28
|
import { computeIdentityTag, fnv1a32 } from './utils/cacheKey';
|
|
@@ -46,15 +52,25 @@ function sameTokenSession(left: string | null, right: string | null): boolean {
|
|
|
46
52
|
if (!a || !b || !(a.userId || a.id || a.sub) || !(b.userId || b.id || b.sub)) return false;
|
|
47
53
|
// A refresh may rotate exp/iat/jti while preserving its account and session.
|
|
48
54
|
// Opaque/malformed context fields cannot establish that equivalence.
|
|
49
|
-
return [
|
|
50
|
-
|
|
55
|
+
return [
|
|
56
|
+
'userId',
|
|
57
|
+
'id',
|
|
58
|
+
'sub',
|
|
59
|
+
'sessionId',
|
|
60
|
+
'operatorId',
|
|
61
|
+
'clientId',
|
|
62
|
+
'appId',
|
|
63
|
+
'authMethodId',
|
|
64
|
+
].every((key) => (a[key] === undefined || typeof a[key] === 'string') && a[key] === b[key]);
|
|
51
65
|
}
|
|
52
66
|
|
|
53
67
|
/** Cancel this wait only; the shared mint continues for other callers. */
|
|
54
68
|
function awaitRequestSignal<T>(pending: Promise<T>, signal?: AbortSignal): Promise<T> {
|
|
55
69
|
if (!signal) return pending;
|
|
56
70
|
return new Promise<T>((resolve, reject) => {
|
|
57
|
-
const onAbort = (): void => {
|
|
71
|
+
const onAbort = (): void => {
|
|
72
|
+
reject(createCancelledError());
|
|
73
|
+
};
|
|
58
74
|
if (signal.aborted) onAbort();
|
|
59
75
|
else signal.addEventListener('abort', onAbort, { once: true });
|
|
60
76
|
// Both handlers remain attached even after cancellation, so a late shared
|
|
@@ -336,7 +352,9 @@ function isAbortLike(error: unknown): boolean {
|
|
|
336
352
|
function linkAbort(parent: AbortSignal, child: AbortController): () => void {
|
|
337
353
|
if (parent.aborted) {
|
|
338
354
|
child.abort((parent as AbortSignal & { reason?: unknown }).reason);
|
|
339
|
-
return () => {
|
|
355
|
+
return () => {
|
|
356
|
+
/* nothing was ever attached */
|
|
357
|
+
};
|
|
340
358
|
}
|
|
341
359
|
const onAbort = (): void => {
|
|
342
360
|
child.abort((parent as AbortSignal & { reason?: unknown }).reason);
|
|
@@ -461,11 +479,11 @@ export class HttpService {
|
|
|
461
479
|
this.config = config;
|
|
462
480
|
this.baseURL = config.baseURL;
|
|
463
481
|
this.tokenStore = new TokenStore();
|
|
464
|
-
|
|
482
|
+
|
|
465
483
|
this.logger = new SimpleLogger(
|
|
466
484
|
config.enableLogging || false,
|
|
467
485
|
config.logLevel || 'error',
|
|
468
|
-
'HttpService'
|
|
486
|
+
'HttpService',
|
|
469
487
|
);
|
|
470
488
|
|
|
471
489
|
// Initialize performance infrastructure. The per-instance GET response
|
|
@@ -475,16 +493,17 @@ export class HttpService {
|
|
|
475
493
|
// the cache for the global cleanup interval. Default (config unset) keeps
|
|
476
494
|
// caching ON with the 5-minute TTL — unchanged for existing consumers.
|
|
477
495
|
this.cacheDisabled =
|
|
478
|
-
config.enableCache === false ||
|
|
479
|
-
|
|
480
|
-
|
|
496
|
+
config.enableCache === false || (typeof config.cacheTTL === 'number' && config.cacheTTL <= 0);
|
|
497
|
+
this.cache = new TTLCache<unknown>(
|
|
498
|
+
config.cacheTTL && config.cacheTTL > 0 ? config.cacheTTL : 5 * 60 * 1000,
|
|
499
|
+
);
|
|
481
500
|
if (!this.cacheDisabled) {
|
|
482
501
|
registerCacheForCleanup(this.cache);
|
|
483
502
|
}
|
|
484
503
|
this.deduplicator = new RequestDeduplicator();
|
|
485
504
|
this.requestQueue = new RequestQueue(
|
|
486
505
|
config.maxConcurrentRequests || 10,
|
|
487
|
-
config.requestQueueSize || 100
|
|
506
|
+
config.requestQueueSize || 100,
|
|
488
507
|
);
|
|
489
508
|
}
|
|
490
509
|
|
|
@@ -690,7 +709,7 @@ export class HttpService {
|
|
|
690
709
|
|
|
691
710
|
// Build headers - start with defaults
|
|
692
711
|
const headers: Record<string, string> = {
|
|
693
|
-
|
|
712
|
+
Accept: 'application/json',
|
|
694
713
|
};
|
|
695
714
|
|
|
696
715
|
// Only set Content-Type for non-FormData requests (FormData sets it automatically with boundary)
|
|
@@ -711,7 +730,9 @@ export class HttpService {
|
|
|
711
730
|
// For FormData, explicitly remove Content-Type if user tries to set it
|
|
712
731
|
// The browser/fetch API will set it automatically with the boundary
|
|
713
732
|
if (isFormData && key.toLowerCase() === 'content-type') {
|
|
714
|
-
this.logger.debug(
|
|
733
|
+
this.logger.debug(
|
|
734
|
+
'Ignoring Content-Type header for FormData - will be set automatically',
|
|
735
|
+
);
|
|
715
736
|
continue;
|
|
716
737
|
}
|
|
717
738
|
headers[key] = value;
|
|
@@ -727,8 +748,13 @@ export class HttpService {
|
|
|
727
748
|
// `URLSearchParams` is serialised explicitly rather than handed to
|
|
728
749
|
// `fetch` as-is: RN's fetch does not consistently encode it, and doing
|
|
729
750
|
// it here keeps the body identical across every platform.
|
|
730
|
-
const bodyValue =
|
|
731
|
-
|
|
751
|
+
const bodyValue =
|
|
752
|
+
method !== 'GET' && data
|
|
753
|
+
? isFormData
|
|
754
|
+
? data
|
|
755
|
+
: isUrlEncoded
|
|
756
|
+
? data.toString()
|
|
757
|
+
: JSON.stringify(data)
|
|
732
758
|
: undefined;
|
|
733
759
|
|
|
734
760
|
// React Native FormData workaround:
|
|
@@ -737,7 +763,8 @@ export class HttpService {
|
|
|
737
763
|
// RN's native XMLHttpRequest handles those descriptors correctly, so we
|
|
738
764
|
// route multipart uploads through XHR on RN only. JSON, text, etc. still
|
|
739
765
|
// use fetch on every platform.
|
|
740
|
-
const useXhrForUpload =
|
|
766
|
+
const useXhrForUpload =
|
|
767
|
+
isFormData && isReactNative() && typeof XMLHttpRequest !== 'undefined';
|
|
741
768
|
|
|
742
769
|
const response = useXhrForUpload
|
|
743
770
|
? await this.uploadViaXHR(
|
|
@@ -781,7 +808,13 @@ export class HttpService {
|
|
|
781
808
|
// queue slot, so a queued retry waits for a slot while holding one.
|
|
782
809
|
// With every slot held by a 401 (a revoked session under load) no
|
|
783
810
|
// retry could ever start and the whole client stalled.
|
|
784
|
-
return this.request<T>({
|
|
811
|
+
return this.request<T>({
|
|
812
|
+
...config,
|
|
813
|
+
_isAuthRetry: true,
|
|
814
|
+
retry: false,
|
|
815
|
+
deduplicate: false,
|
|
816
|
+
bypassQueue: true,
|
|
817
|
+
});
|
|
785
818
|
}
|
|
786
819
|
// Refresh failed or no token — clear tokens
|
|
787
820
|
this.tokenStore.clearTokens();
|
|
@@ -816,7 +849,11 @@ export class HttpService {
|
|
|
816
849
|
response?: { status: number; statusText: string; data?: unknown };
|
|
817
850
|
};
|
|
818
851
|
error.status = response.status;
|
|
819
|
-
error.response = {
|
|
852
|
+
error.response = {
|
|
853
|
+
status: response.status,
|
|
854
|
+
statusText: response.statusText,
|
|
855
|
+
data: errorBody,
|
|
856
|
+
};
|
|
820
857
|
// Only set `code`/`details` when the server actually sent them.
|
|
821
858
|
// Assigning `undefined` would still create the property, which changes
|
|
822
859
|
// how `handleHttpError` classifies the error downstream.
|
|
@@ -832,7 +869,7 @@ export class HttpService {
|
|
|
832
869
|
// Handle different response types (optimized - read response once)
|
|
833
870
|
const contentType = response.headers.get('content-type');
|
|
834
871
|
let responseData: unknown;
|
|
835
|
-
|
|
872
|
+
|
|
836
873
|
if (config.responseType === 'blob') {
|
|
837
874
|
responseData = await response.blob();
|
|
838
875
|
} else if (contentType?.includes('application/json')) {
|
|
@@ -860,7 +897,13 @@ export class HttpService {
|
|
|
860
897
|
throw new Error('Failed to read response from server');
|
|
861
898
|
}
|
|
862
899
|
}
|
|
863
|
-
} else if (
|
|
900
|
+
} else if (
|
|
901
|
+
contentType &&
|
|
902
|
+
(contentType.includes('application/octet-stream') ||
|
|
903
|
+
contentType.includes('image/') ||
|
|
904
|
+
contentType.includes('video/') ||
|
|
905
|
+
contentType.includes('audio/'))
|
|
906
|
+
) {
|
|
864
907
|
// For binary responses (blobs), return the blob directly without unwrapping
|
|
865
908
|
responseData = await response.blob();
|
|
866
909
|
} else {
|
|
@@ -878,7 +921,11 @@ export class HttpService {
|
|
|
878
921
|
const duration = Date.now() - startTime;
|
|
879
922
|
this.updateMetrics(false, duration);
|
|
880
923
|
this.config.onRequestEnd?.(url, method, duration, false);
|
|
881
|
-
this.config.onRequestError?.(
|
|
924
|
+
this.config.onRequestError?.(
|
|
925
|
+
url,
|
|
926
|
+
method,
|
|
927
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
928
|
+
);
|
|
882
929
|
|
|
883
930
|
// An abort is the one failure whose CAUSE the error cannot carry on its
|
|
884
931
|
// own: `fetch` reports a caller cancellation and our own timeout as the
|
|
@@ -931,7 +978,9 @@ export class HttpService {
|
|
|
931
978
|
// Control-plane calls the auth lane depends on (`bypassQueue`, e.g. the
|
|
932
979
|
// device-secret mint) run DIRECTLY — a queued mint could never acquire a
|
|
933
980
|
// slot when every slot is parked awaiting it.
|
|
934
|
-
config.bypassQueue
|
|
981
|
+
config.bypassQueue
|
|
982
|
+
? attempt(domain)
|
|
983
|
+
: this.requestQueue.enqueue(() => attempt(domain), domain);
|
|
935
984
|
const execute = (domain: AbortSignal): Promise<T> =>
|
|
936
985
|
retry
|
|
937
986
|
? retryAsync(() => runAttempt(domain), {
|
|
@@ -1050,7 +1099,11 @@ export class HttpService {
|
|
|
1050
1099
|
}
|
|
1051
1100
|
|
|
1052
1101
|
const onAbort = (): void => {
|
|
1053
|
-
try {
|
|
1102
|
+
try {
|
|
1103
|
+
xhr.abort();
|
|
1104
|
+
} catch {
|
|
1105
|
+
/* xhr already finished */
|
|
1106
|
+
}
|
|
1054
1107
|
};
|
|
1055
1108
|
if (abortSignal.aborted) {
|
|
1056
1109
|
reject(new DOMException('The user aborted a request.', 'AbortError'));
|
|
@@ -1065,11 +1118,13 @@ export class HttpService {
|
|
|
1065
1118
|
xhr.onload = (): void => {
|
|
1066
1119
|
cleanup();
|
|
1067
1120
|
const responseHeaders = HttpService.parseXHRHeaders(xhr.getAllResponseHeaders());
|
|
1068
|
-
resolve(
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1121
|
+
resolve(
|
|
1122
|
+
new Response(xhr.responseText, {
|
|
1123
|
+
status: xhr.status,
|
|
1124
|
+
statusText: xhr.statusText,
|
|
1125
|
+
headers: responseHeaders,
|
|
1126
|
+
}),
|
|
1127
|
+
);
|
|
1073
1128
|
};
|
|
1074
1129
|
xhr.onerror = (): void => {
|
|
1075
1130
|
cleanup();
|
|
@@ -1200,7 +1255,7 @@ export class HttpService {
|
|
|
1200
1255
|
const base = /^https?:\/\//i.test(url)
|
|
1201
1256
|
? url
|
|
1202
1257
|
: `${trimTrailingSlashes(this.baseURL)}/${trimLeadingSlashes(url)}`;
|
|
1203
|
-
|
|
1258
|
+
|
|
1204
1259
|
if (!params || Object.keys(params).length === 0) {
|
|
1205
1260
|
return base;
|
|
1206
1261
|
}
|
|
@@ -1511,13 +1566,20 @@ export class HttpService {
|
|
|
1511
1566
|
return this.requestRawResponse(config, false);
|
|
1512
1567
|
}
|
|
1513
1568
|
|
|
1514
|
-
private async requestRawResponse(
|
|
1569
|
+
private async requestRawResponse(
|
|
1570
|
+
config: ResponseRequest,
|
|
1571
|
+
requireAuth: boolean,
|
|
1572
|
+
): Promise<Response> {
|
|
1515
1573
|
// Validate before obtaining a bearer: an unrelated origin must not trigger
|
|
1516
1574
|
// an auth mint, even when the trusted transport accepts absolute URLs.
|
|
1517
1575
|
const target = new URL(this.buildURL(config.url));
|
|
1518
1576
|
const base = new URL(this.baseURL);
|
|
1519
|
-
if (
|
|
1520
|
-
|
|
1577
|
+
if (
|
|
1578
|
+
target.origin !== base.origin ||
|
|
1579
|
+
!['http:', 'https:'].includes(target.protocol) ||
|
|
1580
|
+
target.username ||
|
|
1581
|
+
target.password
|
|
1582
|
+
) {
|
|
1521
1583
|
throw new Error('Raw response requests must target the configured API origin');
|
|
1522
1584
|
}
|
|
1523
1585
|
if (config.signal?.aborted) throw createCancelledError();
|
|
@@ -1526,14 +1588,27 @@ export class HttpService {
|
|
|
1526
1588
|
const contextToken = this.syncAccessTokenFromProvider();
|
|
1527
1589
|
const beforeAuthEpoch = this.sessionEpoch;
|
|
1528
1590
|
const authHeader = await awaitRequestSignal(this.getAuthHeader(), config.signal);
|
|
1529
|
-
if (
|
|
1591
|
+
if (
|
|
1592
|
+
beforeAuthEpoch !== this.sessionEpoch ||
|
|
1593
|
+
!sameTokenSession(contextToken, this.tokenStore.getAccessToken())
|
|
1594
|
+
) {
|
|
1530
1595
|
throw new OxyAuthenticationError('The request session changed', 'AUTH_SESSION_CHANGED');
|
|
1531
1596
|
}
|
|
1532
1597
|
if (config.signal?.aborted) throw createCancelledError();
|
|
1533
1598
|
if (requireAuth && !authHeader) {
|
|
1534
|
-
throw new OxyAuthenticationError(
|
|
1599
|
+
throw new OxyAuthenticationError(
|
|
1600
|
+
'An active Oxy session is required for this request',
|
|
1601
|
+
'AUTH_REQUIRED',
|
|
1602
|
+
);
|
|
1535
1603
|
}
|
|
1536
|
-
return this.requestResponseAttempt(
|
|
1604
|
+
return this.requestResponseAttempt(
|
|
1605
|
+
request,
|
|
1606
|
+
target.href,
|
|
1607
|
+
authHeader,
|
|
1608
|
+
false,
|
|
1609
|
+
this.sessionEpoch,
|
|
1610
|
+
contextToken,
|
|
1611
|
+
);
|
|
1537
1612
|
}
|
|
1538
1613
|
|
|
1539
1614
|
private async requestResponseAttempt(
|
|
@@ -1546,7 +1621,10 @@ export class HttpService {
|
|
|
1546
1621
|
): Promise<Response> {
|
|
1547
1622
|
const assertCurrent = (): void => {
|
|
1548
1623
|
this.syncAccessTokenFromProvider();
|
|
1549
|
-
if (
|
|
1624
|
+
if (
|
|
1625
|
+
epoch !== this.sessionEpoch ||
|
|
1626
|
+
!sameTokenSession(contextToken, this.tokenStore.getAccessToken())
|
|
1627
|
+
) {
|
|
1550
1628
|
throw new OxyAuthenticationError('The request session changed', 'AUTH_SESSION_CHANGED');
|
|
1551
1629
|
}
|
|
1552
1630
|
};
|
|
@@ -1556,7 +1634,8 @@ export class HttpService {
|
|
|
1556
1634
|
const headers = new Headers(config.headers);
|
|
1557
1635
|
if (!headers.has('Accept')) headers.set('Accept', 'application/json');
|
|
1558
1636
|
// Never accept ambient credentials or another authority from a caller.
|
|
1559
|
-
for (const name of ['Authorization', 'Cookie', 'Cookie2', 'Host', 'Proxy-Authorization'])
|
|
1637
|
+
for (const name of ['Authorization', 'Cookie', 'Cookie2', 'Host', 'Proxy-Authorization'])
|
|
1638
|
+
headers.delete(name);
|
|
1560
1639
|
if (authHeader) headers.set('Authorization', authHeader);
|
|
1561
1640
|
const edgeRegionHeader = peekBrowserEdgeRegionHeader();
|
|
1562
1641
|
for (const [name, value] of Object.entries(edgeRegionHeader)) headers.set(name, value);
|
|
@@ -1577,21 +1656,47 @@ export class HttpService {
|
|
|
1577
1656
|
// multipart bodies keep the platform's existing body serialization.
|
|
1578
1657
|
if (body && typeof body === 'object' && 'getReader' in body) init.duplex = 'half';
|
|
1579
1658
|
const response = await (config.fetch ?? globalThis.fetch)(fullUrl, init);
|
|
1580
|
-
try {
|
|
1659
|
+
try {
|
|
1660
|
+
assertCurrent();
|
|
1661
|
+
} catch (error) {
|
|
1662
|
+
await response.body?.cancel();
|
|
1663
|
+
throw error;
|
|
1664
|
+
}
|
|
1581
1665
|
const replayable = body === undefined || typeof body === 'string';
|
|
1582
|
-
if (
|
|
1666
|
+
if (
|
|
1667
|
+
response.status === 401 &&
|
|
1668
|
+
!isAuthRetry &&
|
|
1669
|
+
authHeader &&
|
|
1670
|
+
replayable &&
|
|
1671
|
+
!config.signal?.aborted
|
|
1672
|
+
) {
|
|
1583
1673
|
let refreshed: string | null;
|
|
1584
1674
|
try {
|
|
1585
|
-
refreshed = await awaitRequestSignal(
|
|
1675
|
+
refreshed = await awaitRequestSignal(
|
|
1676
|
+
this.refreshAccessToken('response-401'),
|
|
1677
|
+
config.signal,
|
|
1678
|
+
);
|
|
1586
1679
|
} catch (error) {
|
|
1587
1680
|
void response.body?.cancel().catch(() => undefined);
|
|
1588
1681
|
throw error;
|
|
1589
1682
|
}
|
|
1590
|
-
try {
|
|
1683
|
+
try {
|
|
1684
|
+
assertCurrent();
|
|
1685
|
+
} catch (error) {
|
|
1686
|
+
await response.body?.cancel();
|
|
1687
|
+
throw error;
|
|
1688
|
+
}
|
|
1591
1689
|
if (refreshed) {
|
|
1592
1690
|
await response.body?.cancel();
|
|
1593
1691
|
if (config.signal?.aborted) throw createCancelledError();
|
|
1594
|
-
return this.requestResponseAttempt(
|
|
1692
|
+
return this.requestResponseAttempt(
|
|
1693
|
+
config,
|
|
1694
|
+
fullUrl,
|
|
1695
|
+
`Bearer ${refreshed}`,
|
|
1696
|
+
true,
|
|
1697
|
+
epoch,
|
|
1698
|
+
contextToken,
|
|
1699
|
+
);
|
|
1595
1700
|
}
|
|
1596
1701
|
this.clearTokens();
|
|
1597
1702
|
}
|
|
@@ -1604,11 +1709,15 @@ export class HttpService {
|
|
|
1604
1709
|
const duration = Date.now() - startTime;
|
|
1605
1710
|
this.updateMetrics(false, duration);
|
|
1606
1711
|
this.config.onRequestEnd?.(config.url, config.method, duration, false);
|
|
1607
|
-
const normalizedError =
|
|
1608
|
-
|
|
1609
|
-
|
|
1712
|
+
const normalizedError =
|
|
1713
|
+
config.signal?.aborted || isCancelledError(error)
|
|
1714
|
+
? createCancelledError()
|
|
1715
|
+
: error instanceof Error
|
|
1716
|
+
? error
|
|
1717
|
+
: new Error(String(error));
|
|
1610
1718
|
this.config.onRequestError?.(config.url, config.method, normalizedError);
|
|
1611
|
-
if (isCancelledError(normalizedError) || normalizedError instanceof OxyAuthenticationError)
|
|
1719
|
+
if (isCancelledError(normalizedError) || normalizedError instanceof OxyAuthenticationError)
|
|
1720
|
+
throw normalizedError;
|
|
1612
1721
|
throw handleHttpError(normalizedError);
|
|
1613
1722
|
}
|
|
1614
1723
|
}
|
|
@@ -1618,19 +1727,34 @@ export class HttpService {
|
|
|
1618
1727
|
return this.request<T>({ method: 'GET', url, ...config });
|
|
1619
1728
|
}
|
|
1620
1729
|
|
|
1621
|
-
async post<T = unknown>(
|
|
1730
|
+
async post<T = unknown>(
|
|
1731
|
+
url: string,
|
|
1732
|
+
data?: unknown,
|
|
1733
|
+
config?: Omit<RequestConfig, 'method' | 'url' | 'data'>,
|
|
1734
|
+
): Promise<T> {
|
|
1622
1735
|
return this.request<T>({ method: 'POST', url, data, ...config });
|
|
1623
1736
|
}
|
|
1624
1737
|
|
|
1625
|
-
async put<T = unknown>(
|
|
1738
|
+
async put<T = unknown>(
|
|
1739
|
+
url: string,
|
|
1740
|
+
data?: unknown,
|
|
1741
|
+
config?: Omit<RequestConfig, 'method' | 'url' | 'data'>,
|
|
1742
|
+
): Promise<T> {
|
|
1626
1743
|
return this.request<T>({ method: 'PUT', url, data, ...config });
|
|
1627
1744
|
}
|
|
1628
1745
|
|
|
1629
|
-
async patch<T = unknown>(
|
|
1746
|
+
async patch<T = unknown>(
|
|
1747
|
+
url: string,
|
|
1748
|
+
data?: unknown,
|
|
1749
|
+
config?: Omit<RequestConfig, 'method' | 'url' | 'data'>,
|
|
1750
|
+
): Promise<T> {
|
|
1630
1751
|
return this.request<T>({ method: 'PATCH', url, data, ...config });
|
|
1631
1752
|
}
|
|
1632
1753
|
|
|
1633
|
-
async delete<T = unknown>(
|
|
1754
|
+
async delete<T = unknown>(
|
|
1755
|
+
url: string,
|
|
1756
|
+
config?: Omit<RequestConfig, 'method' | 'url'>,
|
|
1757
|
+
): Promise<T> {
|
|
1634
1758
|
return this.request<T>({ method: 'DELETE', url, ...config });
|
|
1635
1759
|
}
|
|
1636
1760
|
|
|
@@ -1794,7 +1918,13 @@ export class HttpService {
|
|
|
1794
1918
|
* per resource.
|
|
1795
1919
|
* @returns Number of entries deleted
|
|
1796
1920
|
*/
|
|
1797
|
-
invalidateCache({
|
|
1921
|
+
invalidateCache({
|
|
1922
|
+
keys = [],
|
|
1923
|
+
prefixes = [],
|
|
1924
|
+
}: {
|
|
1925
|
+
keys?: readonly string[];
|
|
1926
|
+
prefixes?: readonly string[];
|
|
1927
|
+
}): number {
|
|
1798
1928
|
if (keys.length === 0 && prefixes.length === 0) return 0;
|
|
1799
1929
|
const exact = new Set(keys);
|
|
1800
1930
|
const delim = HttpService.CACHE_IDENTITY_DELIM;
|
|
@@ -54,7 +54,12 @@ export class AssetUrlResolutionError extends Error {
|
|
|
54
54
|
*/
|
|
55
55
|
public readonly cause?: unknown;
|
|
56
56
|
|
|
57
|
-
constructor(
|
|
57
|
+
constructor(
|
|
58
|
+
fileId: string,
|
|
59
|
+
variant: string | undefined,
|
|
60
|
+
status: number | undefined,
|
|
61
|
+
cause?: unknown,
|
|
62
|
+
) {
|
|
58
63
|
const variantSuffix = variant ? ` (variant "${variant}")` : '';
|
|
59
64
|
const statusSuffix = typeof status === 'number' ? ` — status ${status}` : '';
|
|
60
65
|
super(`Could not resolve a download URL for asset "${fileId}"${variantSuffix}${statusSuffix}`);
|
|
@@ -152,13 +157,12 @@ export class OxyAuthenticationTimeoutError extends OxyAuthenticationError {
|
|
|
152
157
|
super(
|
|
153
158
|
`Authentication timeout (${timeoutMs}ms): ${operationName} requires user authentication. Please ensure the user is logged in before calling this method.`,
|
|
154
159
|
'AUTH_TIMEOUT',
|
|
155
|
-
408
|
|
160
|
+
408,
|
|
156
161
|
);
|
|
157
162
|
this.name = 'OxyAuthenticationTimeoutError';
|
|
158
163
|
}
|
|
159
164
|
}
|
|
160
165
|
|
|
161
|
-
|
|
162
166
|
/**
|
|
163
167
|
* The one error every `OxyServices` call rejects with.
|
|
164
168
|
*
|