@oxyhq/core 1.11.10 → 1.11.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/HttpService.js +13 -0
- package/dist/cjs/OxyServices.base.js +21 -0
- package/dist/cjs/mixins/OxyServices.managedAccounts.js +117 -0
- package/dist/cjs/mixins/OxyServices.utility.js +81 -2
- package/dist/cjs/mixins/index.js +2 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/HttpService.js +13 -0
- package/dist/esm/OxyServices.base.js +21 -0
- package/dist/esm/mixins/OxyServices.managedAccounts.js +114 -0
- package/dist/esm/mixins/OxyServices.utility.js +81 -2
- package/dist/esm/mixins/index.js +2 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/HttpService.d.ts +3 -0
- package/dist/types/OxyServices.base.d.ts +17 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/mixins/OxyServices.analytics.d.ts +2 -0
- package/dist/types/mixins/OxyServices.assets.d.ts +2 -0
- package/dist/types/mixins/OxyServices.auth.d.ts +2 -0
- package/dist/types/mixins/OxyServices.developer.d.ts +2 -0
- package/dist/types/mixins/OxyServices.devices.d.ts +2 -0
- package/dist/types/mixins/OxyServices.features.d.ts +5 -1
- package/dist/types/mixins/OxyServices.fedcm.d.ts +2 -0
- package/dist/types/mixins/OxyServices.karma.d.ts +2 -0
- package/dist/types/mixins/OxyServices.language.d.ts +2 -0
- package/dist/types/mixins/OxyServices.location.d.ts +2 -0
- package/dist/types/mixins/OxyServices.managedAccounts.d.ts +125 -0
- package/dist/types/mixins/OxyServices.payment.d.ts +2 -0
- package/dist/types/mixins/OxyServices.popup.d.ts +2 -0
- package/dist/types/mixins/OxyServices.privacy.d.ts +2 -0
- package/dist/types/mixins/OxyServices.redirect.d.ts +2 -0
- package/dist/types/mixins/OxyServices.security.d.ts +2 -0
- package/dist/types/mixins/OxyServices.topics.d.ts +2 -0
- package/dist/types/mixins/OxyServices.user.d.ts +2 -0
- package/dist/types/mixins/OxyServices.utility.d.ts +22 -0
- package/dist/types/models/interfaces.d.ts +2 -0
- package/package.json +1 -1
- package/src/HttpService.ts +17 -0
- package/src/OxyServices.base.ts +23 -0
- package/src/index.ts +1 -0
- package/src/mixins/OxyServices.managedAccounts.ts +147 -0
- package/src/mixins/OxyServices.utility.ts +103 -2
- package/src/mixins/index.ts +2 -0
- package/src/models/interfaces.ts +3 -0
|
@@ -50,6 +50,7 @@ export declare class HttpService {
|
|
|
50
50
|
private tokenRefreshPromise;
|
|
51
51
|
private tokenRefreshCooldownUntil;
|
|
52
52
|
private _onTokenRefreshed;
|
|
53
|
+
private _actingAsUserId;
|
|
53
54
|
private requestMetrics;
|
|
54
55
|
constructor(config: OxyConfig);
|
|
55
56
|
/**
|
|
@@ -93,6 +94,8 @@ export declare class HttpService {
|
|
|
93
94
|
put<T = unknown>(url: string, data?: unknown, config?: Omit<RequestConfig, 'method' | 'url' | 'data'>): Promise<T>;
|
|
94
95
|
patch<T = unknown>(url: string, data?: unknown, config?: Omit<RequestConfig, 'method' | 'url' | 'data'>): Promise<T>;
|
|
95
96
|
delete<T = unknown>(url: string, config?: Omit<RequestConfig, 'method' | 'url'>): Promise<T>;
|
|
97
|
+
setActingAs(userId: string | null): void;
|
|
98
|
+
getActingAs(): string | null;
|
|
96
99
|
setTokens(accessToken: string, refreshToken?: string): void;
|
|
97
100
|
set onTokenRefreshed(callback: ((accessToken: string) => void) | null);
|
|
98
101
|
clearTokens(): void;
|
|
@@ -81,6 +81,23 @@ export declare class OxyServicesBase {
|
|
|
81
81
|
* Get the raw access token (for constructing anchor URLs when needed)
|
|
82
82
|
*/
|
|
83
83
|
getAccessToken(): string | null;
|
|
84
|
+
/**
|
|
85
|
+
* Set the acting-as identity for managed accounts.
|
|
86
|
+
*
|
|
87
|
+
* When set, all subsequent API requests will include the `X-Acting-As` header,
|
|
88
|
+
* causing the server to attribute actions to the managed account. The
|
|
89
|
+
* authenticated user must be an authorized manager of the target account.
|
|
90
|
+
*
|
|
91
|
+
* Pass `null` to clear and revert to the authenticated user's own identity.
|
|
92
|
+
*
|
|
93
|
+
* @param userId - The managed account user ID, or null to clear
|
|
94
|
+
*/
|
|
95
|
+
setActingAs(userId: string | null): void;
|
|
96
|
+
/**
|
|
97
|
+
* Get the current acting-as identity (managed account user ID), or null
|
|
98
|
+
* if operating as the authenticated user's own identity.
|
|
99
|
+
*/
|
|
100
|
+
getActingAs(): string | null;
|
|
84
101
|
/**
|
|
85
102
|
* Wait for authentication to be ready
|
|
86
103
|
*
|
package/dist/types/index.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export type { PopupAuthOptions } from './mixins/OxyServices.popup';
|
|
|
25
25
|
export type { RedirectAuthOptions } from './mixins/OxyServices.redirect';
|
|
26
26
|
export type { ServiceTokenResponse } from './mixins/OxyServices.auth';
|
|
27
27
|
export type { ServiceApp } from './mixins/OxyServices.utility';
|
|
28
|
+
export type { CreateManagedAccountInput, ManagedAccountManager, ManagedAccount } from './mixins/OxyServices.managedAccounts';
|
|
28
29
|
export { KeyManager, SignatureService, RecoveryPhraseService } from './crypto';
|
|
29
30
|
export type { KeyPair, SignedMessage, AuthChallenge, RecoveryPhraseResult } from './crypto';
|
|
30
31
|
export * from './models/interfaces';
|
|
@@ -50,6 +50,8 @@ export declare function OxyServicesAnalyticsMixin<T extends typeof OxyServicesBa
|
|
|
50
50
|
getCurrentUserId(): string | null;
|
|
51
51
|
hasValidToken(): boolean;
|
|
52
52
|
getAccessToken(): string | null;
|
|
53
|
+
setActingAs(userId: string | null): void;
|
|
54
|
+
getActingAs(): string | null;
|
|
53
55
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
54
56
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
55
57
|
maxRetries?: number;
|
|
@@ -128,6 +128,8 @@ export declare function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>
|
|
|
128
128
|
getCurrentUserId(): string | null;
|
|
129
129
|
hasValidToken(): boolean;
|
|
130
130
|
getAccessToken(): string | null;
|
|
131
|
+
setActingAs(userId: string | null): void;
|
|
132
|
+
getActingAs(): string | null;
|
|
131
133
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
132
134
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
133
135
|
maxRetries?: number;
|
|
@@ -206,6 +206,8 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
206
206
|
getCurrentUserId(): string | null;
|
|
207
207
|
hasValidToken(): boolean;
|
|
208
208
|
getAccessToken(): string | null;
|
|
209
|
+
setActingAs(userId: string | null): void;
|
|
210
|
+
getActingAs(): string | null;
|
|
209
211
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
210
212
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
211
213
|
maxRetries?: number;
|
|
@@ -83,6 +83,8 @@ export declare function OxyServicesDeveloperMixin<T extends typeof OxyServicesBa
|
|
|
83
83
|
getCurrentUserId(): string | null;
|
|
84
84
|
hasValidToken(): boolean;
|
|
85
85
|
getAccessToken(): string | null;
|
|
86
|
+
setActingAs(userId: string | null): void;
|
|
87
|
+
getActingAs(): string | null;
|
|
86
88
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
87
89
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
88
90
|
maxRetries?: number;
|
|
@@ -80,6 +80,8 @@ export declare function OxyServicesDevicesMixin<T extends typeof OxyServicesBase
|
|
|
80
80
|
getCurrentUserId(): string | null;
|
|
81
81
|
hasValidToken(): boolean;
|
|
82
82
|
getAccessToken(): string | null;
|
|
83
|
+
setActingAs(userId: string | null): void;
|
|
84
|
+
getActingAs(): string | null;
|
|
83
85
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
84
86
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
85
87
|
maxRetries?: number;
|
|
@@ -212,6 +212,8 @@ export declare function OxyServicesFeaturesMixin<T extends typeof OxyServicesBas
|
|
|
212
212
|
getCurrentUserId(): string | null;
|
|
213
213
|
hasValidToken(): boolean;
|
|
214
214
|
getAccessToken(): string | null;
|
|
215
|
+
setActingAs(userId: string | null): void;
|
|
216
|
+
getActingAs(): string | null;
|
|
215
217
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
216
218
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
217
219
|
maxRetries?: number;
|
|
@@ -223,7 +225,9 @@ export declare function OxyServicesFeaturesMixin<T extends typeof OxyServicesBas
|
|
|
223
225
|
healthCheck(): Promise<{
|
|
224
226
|
status: string;
|
|
225
227
|
users?: number;
|
|
226
|
-
timestamp
|
|
228
|
+
timestamp? /**
|
|
229
|
+
* Get FAQs
|
|
230
|
+
*/: string;
|
|
227
231
|
[key: string]: any;
|
|
228
232
|
}>;
|
|
229
233
|
};
|
|
@@ -188,6 +188,8 @@ export declare function OxyServicesFedCMMixin<T extends typeof OxyServicesBase>(
|
|
|
188
188
|
getCurrentUserId(): string | null;
|
|
189
189
|
hasValidToken(): boolean;
|
|
190
190
|
getAccessToken(): string | null;
|
|
191
|
+
setActingAs(userId: string | null): void;
|
|
192
|
+
getActingAs(): string | null;
|
|
191
193
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
192
194
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
193
195
|
maxRetries?: number;
|
|
@@ -69,6 +69,8 @@ export declare function OxyServicesKarmaMixin<T extends typeof OxyServicesBase>(
|
|
|
69
69
|
getCurrentUserId(): string | null;
|
|
70
70
|
hasValidToken(): boolean;
|
|
71
71
|
getAccessToken(): string | null;
|
|
72
|
+
setActingAs(userId: string | null): void;
|
|
73
|
+
getActingAs(): string | null;
|
|
72
74
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
73
75
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
74
76
|
maxRetries?: number;
|
|
@@ -65,6 +65,8 @@ export declare function OxyServicesLanguageMixin<T extends typeof OxyServicesBas
|
|
|
65
65
|
getCurrentUserId(): string | null;
|
|
66
66
|
hasValidToken(): boolean;
|
|
67
67
|
getAccessToken(): string | null;
|
|
68
|
+
setActingAs(userId: string | null): void;
|
|
69
|
+
getActingAs(): string | null;
|
|
68
70
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
69
71
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
70
72
|
maxRetries?: number;
|
|
@@ -48,6 +48,8 @@ export declare function OxyServicesLocationMixin<T extends typeof OxyServicesBas
|
|
|
48
48
|
getCurrentUserId(): string | null;
|
|
49
49
|
hasValidToken(): boolean;
|
|
50
50
|
getAccessToken(): string | null;
|
|
51
|
+
setActingAs(userId: string | null): void;
|
|
52
|
+
getActingAs(): string | null;
|
|
51
53
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
52
54
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
53
55
|
maxRetries?: number;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed Accounts Methods Mixin
|
|
3
|
+
*
|
|
4
|
+
* Provides SDK methods for creating and managing sub-accounts (managed identities).
|
|
5
|
+
* Managed accounts are full User documents without passwords, accessible only
|
|
6
|
+
* by their owners/managers via the X-Acting-As header mechanism.
|
|
7
|
+
*/
|
|
8
|
+
import type { User } from '../models/interfaces';
|
|
9
|
+
import type { OxyServicesBase } from '../OxyServices.base';
|
|
10
|
+
export interface CreateManagedAccountInput {
|
|
11
|
+
username: string;
|
|
12
|
+
name?: {
|
|
13
|
+
first?: string;
|
|
14
|
+
last?: string;
|
|
15
|
+
};
|
|
16
|
+
bio?: string;
|
|
17
|
+
avatar?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ManagedAccountManager {
|
|
20
|
+
userId: string;
|
|
21
|
+
role: 'owner' | 'admin' | 'editor';
|
|
22
|
+
addedAt: string;
|
|
23
|
+
addedBy?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ManagedAccount {
|
|
26
|
+
accountId: string;
|
|
27
|
+
ownerId: string;
|
|
28
|
+
managers: ManagedAccountManager[];
|
|
29
|
+
account?: User;
|
|
30
|
+
createdAt?: string;
|
|
31
|
+
updatedAt?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function OxyServicesManagedAccountsMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
34
|
+
new (...args: any[]): {
|
|
35
|
+
/**
|
|
36
|
+
* Create a new managed account (sub-account).
|
|
37
|
+
*
|
|
38
|
+
* The server creates a User document with `isManagedAccount: true` and links
|
|
39
|
+
* it to the authenticated user as owner.
|
|
40
|
+
*/
|
|
41
|
+
createManagedAccount(data: CreateManagedAccountInput): Promise<ManagedAccount>;
|
|
42
|
+
/**
|
|
43
|
+
* List all accounts the authenticated user manages.
|
|
44
|
+
*/
|
|
45
|
+
getManagedAccounts(): Promise<ManagedAccount[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Get details for a specific managed account.
|
|
48
|
+
*/
|
|
49
|
+
getManagedAccountDetails(accountId: string): Promise<ManagedAccount>;
|
|
50
|
+
/**
|
|
51
|
+
* Update a managed account's profile data.
|
|
52
|
+
* Requires owner or admin role.
|
|
53
|
+
*/
|
|
54
|
+
updateManagedAccount(accountId: string, data: Partial<CreateManagedAccountInput>): Promise<ManagedAccount>;
|
|
55
|
+
/**
|
|
56
|
+
* Delete a managed account permanently.
|
|
57
|
+
* Requires owner role.
|
|
58
|
+
*/
|
|
59
|
+
deleteManagedAccount(accountId: string): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Add a manager to a managed account.
|
|
62
|
+
* Requires owner or admin role on the account.
|
|
63
|
+
*
|
|
64
|
+
* @param accountId - The managed account to add the manager to
|
|
65
|
+
* @param userId - The user to grant management access
|
|
66
|
+
* @param role - The role to assign: 'admin' or 'editor'
|
|
67
|
+
*/
|
|
68
|
+
addManager(accountId: string, userId: string, role: "admin" | "editor"): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Remove a manager from a managed account.
|
|
71
|
+
* Requires owner role.
|
|
72
|
+
*
|
|
73
|
+
* @param accountId - The managed account
|
|
74
|
+
* @param userId - The manager to remove
|
|
75
|
+
*/
|
|
76
|
+
removeManager(accountId: string, userId: string): Promise<void>;
|
|
77
|
+
httpService: import("../HttpService").HttpService;
|
|
78
|
+
cloudURL: string;
|
|
79
|
+
config: import("../OxyServices.base").OxyConfig;
|
|
80
|
+
__resetTokensForTests(): void;
|
|
81
|
+
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
82
|
+
getBaseURL(): string;
|
|
83
|
+
getClient(): import("../HttpService").HttpService;
|
|
84
|
+
getMetrics(): {
|
|
85
|
+
totalRequests: number;
|
|
86
|
+
successfulRequests: number;
|
|
87
|
+
failedRequests: number;
|
|
88
|
+
cacheHits: number;
|
|
89
|
+
cacheMisses: number;
|
|
90
|
+
averageResponseTime: number;
|
|
91
|
+
};
|
|
92
|
+
clearCache(): void;
|
|
93
|
+
clearCacheEntry(key: string): void;
|
|
94
|
+
getCacheStats(): {
|
|
95
|
+
size: number;
|
|
96
|
+
hits: number;
|
|
97
|
+
misses: number;
|
|
98
|
+
hitRate: number;
|
|
99
|
+
};
|
|
100
|
+
getCloudURL(): string;
|
|
101
|
+
setTokens(accessToken: string, refreshToken?: string): void;
|
|
102
|
+
clearTokens(): void;
|
|
103
|
+
_cachedUserId: string | null | undefined;
|
|
104
|
+
_cachedAccessToken: string | null;
|
|
105
|
+
getCurrentUserId(): string | null;
|
|
106
|
+
hasValidToken(): boolean;
|
|
107
|
+
getAccessToken(): string | null;
|
|
108
|
+
setActingAs(userId: string | null): void;
|
|
109
|
+
getActingAs(): string | null;
|
|
110
|
+
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
111
|
+
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
112
|
+
maxRetries?: number;
|
|
113
|
+
retryDelay?: number;
|
|
114
|
+
authTimeoutMs?: number;
|
|
115
|
+
}): Promise<T_1>;
|
|
116
|
+
validate(): Promise<boolean>;
|
|
117
|
+
handleError(error: unknown): Error;
|
|
118
|
+
healthCheck(): Promise<{
|
|
119
|
+
status: string;
|
|
120
|
+
users?: number;
|
|
121
|
+
timestamp?: string;
|
|
122
|
+
[key: string]: any;
|
|
123
|
+
}>;
|
|
124
|
+
};
|
|
125
|
+
} & T;
|
|
@@ -95,6 +95,8 @@ export declare function OxyServicesPaymentMixin<T extends typeof OxyServicesBase
|
|
|
95
95
|
getCurrentUserId(): string | null;
|
|
96
96
|
hasValidToken(): boolean;
|
|
97
97
|
getAccessToken(): string | null;
|
|
98
|
+
setActingAs(userId: string | null): void;
|
|
99
|
+
getActingAs(): string | null;
|
|
98
100
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
99
101
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
100
102
|
maxRetries?: number;
|
|
@@ -185,6 +185,8 @@ export declare function OxyServicesPopupAuthMixin<T extends typeof OxyServicesBa
|
|
|
185
185
|
getCurrentUserId(): string | null;
|
|
186
186
|
hasValidToken(): boolean;
|
|
187
187
|
getAccessToken(): string | null;
|
|
188
|
+
setActingAs(userId: string | null): void;
|
|
189
|
+
getActingAs(): string | null;
|
|
188
190
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
189
191
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
190
192
|
maxRetries?: number;
|
|
@@ -106,6 +106,8 @@ export declare function OxyServicesPrivacyMixin<T extends typeof OxyServicesBase
|
|
|
106
106
|
getCurrentUserId(): string | null;
|
|
107
107
|
hasValidToken(): boolean;
|
|
108
108
|
getAccessToken(): string | null;
|
|
109
|
+
setActingAs(userId: string | null): void;
|
|
110
|
+
getActingAs(): string | null;
|
|
109
111
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
110
112
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
111
113
|
maxRetries?: number;
|
|
@@ -222,6 +222,8 @@ export declare function OxyServicesRedirectAuthMixin<T extends typeof OxyService
|
|
|
222
222
|
getCurrentUserId(): string | null;
|
|
223
223
|
hasValidToken(): boolean;
|
|
224
224
|
getAccessToken(): string | null;
|
|
225
|
+
setActingAs(userId: string | null): void;
|
|
226
|
+
getActingAs(): string | null;
|
|
225
227
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
226
228
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
227
229
|
maxRetries?: number;
|
|
@@ -62,6 +62,8 @@ export declare function OxyServicesSecurityMixin<T extends typeof OxyServicesBas
|
|
|
62
62
|
getCurrentUserId(): string | null;
|
|
63
63
|
hasValidToken(): boolean;
|
|
64
64
|
getAccessToken(): string | null;
|
|
65
|
+
setActingAs(userId: string | null): void;
|
|
66
|
+
getActingAs(): string | null;
|
|
65
67
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
66
68
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
67
69
|
maxRetries?: number;
|
|
@@ -88,6 +88,8 @@ export declare function OxyServicesTopicsMixin<T extends typeof OxyServicesBase>
|
|
|
88
88
|
getCurrentUserId(): string | null;
|
|
89
89
|
hasValidToken(): boolean;
|
|
90
90
|
getAccessToken(): string | null;
|
|
91
|
+
setActingAs(userId: string | null): void;
|
|
92
|
+
getActingAs(): string | null;
|
|
91
93
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
92
94
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
93
95
|
maxRetries?: number;
|
|
@@ -205,6 +205,8 @@ export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(B
|
|
|
205
205
|
getCurrentUserId(): string | null;
|
|
206
206
|
hasValidToken(): boolean;
|
|
207
207
|
getAccessToken(): string | null;
|
|
208
|
+
setActingAs(userId: string | null): void;
|
|
209
|
+
getActingAs(): string | null;
|
|
208
210
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
209
211
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
210
212
|
maxRetries?: number;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { ApiError } from '../models/interfaces';
|
|
2
2
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
3
|
+
/**
|
|
4
|
+
* Result from the managed-accounts verification endpoint.
|
|
5
|
+
* Indicates whether a user is authorized to act as a given managed account.
|
|
6
|
+
*/
|
|
7
|
+
interface ActingAsVerification {
|
|
8
|
+
authorized: boolean;
|
|
9
|
+
role: 'owner' | 'admin' | 'editor';
|
|
10
|
+
}
|
|
3
11
|
/**
|
|
4
12
|
* Service app metadata attached to requests authenticated with service tokens
|
|
5
13
|
*/
|
|
@@ -28,6 +36,18 @@ interface AuthMiddlewareOptions {
|
|
|
28
36
|
}
|
|
29
37
|
export declare function OxyServicesUtilityMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
30
38
|
new (...args: any[]): {
|
|
39
|
+
/** @internal In-memory cache for acting-as verification results (TTL: 5 min) */
|
|
40
|
+
_actingAsCache: Map<string, {
|
|
41
|
+
result: ActingAsVerification | null;
|
|
42
|
+
expiresAt: number;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Verify that a user is authorized to act as a managed account.
|
|
46
|
+
* Results are cached in-memory for 5 minutes to avoid repeated API calls.
|
|
47
|
+
*
|
|
48
|
+
* @internal Used by the auth() middleware — not part of the public API
|
|
49
|
+
*/
|
|
50
|
+
verifyActingAs(userId: string, accountId: string): Promise<ActingAsVerification | null>;
|
|
31
51
|
/**
|
|
32
52
|
* Fetch link metadata
|
|
33
53
|
*/
|
|
@@ -157,6 +177,8 @@ export declare function OxyServicesUtilityMixin<T extends typeof OxyServicesBase
|
|
|
157
177
|
getCurrentUserId(): string | null;
|
|
158
178
|
hasValidToken(): boolean;
|
|
159
179
|
getAccessToken(): string | null;
|
|
180
|
+
setActingAs(userId: string | null): void;
|
|
181
|
+
getActingAs(): string | null;
|
|
160
182
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
161
183
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
162
184
|
maxRetries?: number;
|
package/package.json
CHANGED
package/src/HttpService.ts
CHANGED
|
@@ -131,6 +131,9 @@ export class HttpService {
|
|
|
131
131
|
private tokenRefreshCooldownUntil: number = 0;
|
|
132
132
|
private _onTokenRefreshed: ((accessToken: string) => void) | null = null;
|
|
133
133
|
|
|
134
|
+
// Acting-as identity for managed accounts
|
|
135
|
+
private _actingAsUserId: string | null = null;
|
|
136
|
+
|
|
134
137
|
// Performance monitoring
|
|
135
138
|
private requestMetrics = {
|
|
136
139
|
totalRequests: 0,
|
|
@@ -291,6 +294,11 @@ export class HttpService {
|
|
|
291
294
|
});
|
|
292
295
|
}
|
|
293
296
|
|
|
297
|
+
// Add X-Acting-As header for managed account identity delegation
|
|
298
|
+
if (this._actingAsUserId) {
|
|
299
|
+
headers['X-Acting-As'] = this._actingAsUserId;
|
|
300
|
+
}
|
|
301
|
+
|
|
294
302
|
// Merge custom headers if provided
|
|
295
303
|
if (config.headers) {
|
|
296
304
|
Object.entries(config.headers).forEach(([key, value]) => {
|
|
@@ -706,6 +714,15 @@ export class HttpService {
|
|
|
706
714
|
return this.request<T>({ method: 'DELETE', url, ...config });
|
|
707
715
|
}
|
|
708
716
|
|
|
717
|
+
// Acting-as identity management (managed accounts)
|
|
718
|
+
setActingAs(userId: string | null): void {
|
|
719
|
+
this._actingAsUserId = userId;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
getActingAs(): string | null {
|
|
723
|
+
return this._actingAsUserId;
|
|
724
|
+
}
|
|
725
|
+
|
|
709
726
|
// Token management
|
|
710
727
|
setTokens(accessToken: string, refreshToken = ''): void {
|
|
711
728
|
this.tokenStore.setTokens(accessToken, refreshToken);
|
package/src/OxyServices.base.ts
CHANGED
|
@@ -182,6 +182,29 @@ export class OxyServicesBase {
|
|
|
182
182
|
return this.httpService.getAccessToken();
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Set the acting-as identity for managed accounts.
|
|
187
|
+
*
|
|
188
|
+
* When set, all subsequent API requests will include the `X-Acting-As` header,
|
|
189
|
+
* causing the server to attribute actions to the managed account. The
|
|
190
|
+
* authenticated user must be an authorized manager of the target account.
|
|
191
|
+
*
|
|
192
|
+
* Pass `null` to clear and revert to the authenticated user's own identity.
|
|
193
|
+
*
|
|
194
|
+
* @param userId - The managed account user ID, or null to clear
|
|
195
|
+
*/
|
|
196
|
+
public setActingAs(userId: string | null): void {
|
|
197
|
+
this.httpService.setActingAs(userId);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Get the current acting-as identity (managed account user ID), or null
|
|
202
|
+
* if operating as the authenticated user's own identity.
|
|
203
|
+
*/
|
|
204
|
+
public getActingAs(): string | null {
|
|
205
|
+
return this.httpService.getActingAs();
|
|
206
|
+
}
|
|
207
|
+
|
|
185
208
|
/**
|
|
186
209
|
* Wait for authentication to be ready
|
|
187
210
|
*
|
package/src/index.ts
CHANGED
|
@@ -32,6 +32,7 @@ export type { PopupAuthOptions } from './mixins/OxyServices.popup';
|
|
|
32
32
|
export type { RedirectAuthOptions } from './mixins/OxyServices.redirect';
|
|
33
33
|
export type { ServiceTokenResponse } from './mixins/OxyServices.auth';
|
|
34
34
|
export type { ServiceApp } from './mixins/OxyServices.utility';
|
|
35
|
+
export type { CreateManagedAccountInput, ManagedAccountManager, ManagedAccount } from './mixins/OxyServices.managedAccounts';
|
|
35
36
|
|
|
36
37
|
// --- Crypto / Identity ---
|
|
37
38
|
export { KeyManager, SignatureService, RecoveryPhraseService } from './crypto';
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed Accounts Methods Mixin
|
|
3
|
+
*
|
|
4
|
+
* Provides SDK methods for creating and managing sub-accounts (managed identities).
|
|
5
|
+
* Managed accounts are full User documents without passwords, accessible only
|
|
6
|
+
* by their owners/managers via the X-Acting-As header mechanism.
|
|
7
|
+
*/
|
|
8
|
+
import type { User } from '../models/interfaces';
|
|
9
|
+
import type { OxyServicesBase } from '../OxyServices.base';
|
|
10
|
+
|
|
11
|
+
export interface CreateManagedAccountInput {
|
|
12
|
+
username: string;
|
|
13
|
+
name?: { first?: string; last?: string };
|
|
14
|
+
bio?: string;
|
|
15
|
+
avatar?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ManagedAccountManager {
|
|
19
|
+
userId: string;
|
|
20
|
+
role: 'owner' | 'admin' | 'editor';
|
|
21
|
+
addedAt: string;
|
|
22
|
+
addedBy?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ManagedAccount {
|
|
26
|
+
accountId: string;
|
|
27
|
+
ownerId: string;
|
|
28
|
+
managers: ManagedAccountManager[];
|
|
29
|
+
account?: User;
|
|
30
|
+
createdAt?: string;
|
|
31
|
+
updatedAt?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function OxyServicesManagedAccountsMixin<T extends typeof OxyServicesBase>(Base: T) {
|
|
35
|
+
return class extends Base {
|
|
36
|
+
constructor(...args: any[]) {
|
|
37
|
+
super(...(args as [any]));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create a new managed account (sub-account).
|
|
42
|
+
*
|
|
43
|
+
* The server creates a User document with `isManagedAccount: true` and links
|
|
44
|
+
* it to the authenticated user as owner.
|
|
45
|
+
*/
|
|
46
|
+
async createManagedAccount(data: CreateManagedAccountInput): Promise<ManagedAccount> {
|
|
47
|
+
try {
|
|
48
|
+
return await this.makeRequest<ManagedAccount>('POST', '/managed-accounts', data, {
|
|
49
|
+
cache: false,
|
|
50
|
+
});
|
|
51
|
+
} catch (error) {
|
|
52
|
+
throw this.handleError(error);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* List all accounts the authenticated user manages.
|
|
58
|
+
*/
|
|
59
|
+
async getManagedAccounts(): Promise<ManagedAccount[]> {
|
|
60
|
+
try {
|
|
61
|
+
return await this.makeRequest<ManagedAccount[]>('GET', '/managed-accounts', undefined, {
|
|
62
|
+
cache: true,
|
|
63
|
+
cacheTTL: 2 * 60 * 1000, // 2 minutes cache
|
|
64
|
+
});
|
|
65
|
+
} catch (error) {
|
|
66
|
+
throw this.handleError(error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get details for a specific managed account.
|
|
72
|
+
*/
|
|
73
|
+
async getManagedAccountDetails(accountId: string): Promise<ManagedAccount> {
|
|
74
|
+
try {
|
|
75
|
+
return await this.makeRequest<ManagedAccount>('GET', `/managed-accounts/${accountId}`, undefined, {
|
|
76
|
+
cache: true,
|
|
77
|
+
cacheTTL: 2 * 60 * 1000,
|
|
78
|
+
});
|
|
79
|
+
} catch (error) {
|
|
80
|
+
throw this.handleError(error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Update a managed account's profile data.
|
|
86
|
+
* Requires owner or admin role.
|
|
87
|
+
*/
|
|
88
|
+
async updateManagedAccount(accountId: string, data: Partial<CreateManagedAccountInput>): Promise<ManagedAccount> {
|
|
89
|
+
try {
|
|
90
|
+
return await this.makeRequest<ManagedAccount>('PUT', `/managed-accounts/${accountId}`, data, {
|
|
91
|
+
cache: false,
|
|
92
|
+
});
|
|
93
|
+
} catch (error) {
|
|
94
|
+
throw this.handleError(error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Delete a managed account permanently.
|
|
100
|
+
* Requires owner role.
|
|
101
|
+
*/
|
|
102
|
+
async deleteManagedAccount(accountId: string): Promise<void> {
|
|
103
|
+
try {
|
|
104
|
+
await this.makeRequest<void>('DELETE', `/managed-accounts/${accountId}`, undefined, {
|
|
105
|
+
cache: false,
|
|
106
|
+
});
|
|
107
|
+
} catch (error) {
|
|
108
|
+
throw this.handleError(error);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Add a manager to a managed account.
|
|
114
|
+
* Requires owner or admin role on the account.
|
|
115
|
+
*
|
|
116
|
+
* @param accountId - The managed account to add the manager to
|
|
117
|
+
* @param userId - The user to grant management access
|
|
118
|
+
* @param role - The role to assign: 'admin' or 'editor'
|
|
119
|
+
*/
|
|
120
|
+
async addManager(accountId: string, userId: string, role: 'admin' | 'editor'): Promise<void> {
|
|
121
|
+
try {
|
|
122
|
+
await this.makeRequest<void>('POST', `/managed-accounts/${accountId}/managers`, { userId, role }, {
|
|
123
|
+
cache: false,
|
|
124
|
+
});
|
|
125
|
+
} catch (error) {
|
|
126
|
+
throw this.handleError(error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Remove a manager from a managed account.
|
|
132
|
+
* Requires owner role.
|
|
133
|
+
*
|
|
134
|
+
* @param accountId - The managed account
|
|
135
|
+
* @param userId - The manager to remove
|
|
136
|
+
*/
|
|
137
|
+
async removeManager(accountId: string, userId: string): Promise<void> {
|
|
138
|
+
try {
|
|
139
|
+
await this.makeRequest<void>('DELETE', `/managed-accounts/${accountId}/managers/${userId}`, undefined, {
|
|
140
|
+
cache: false,
|
|
141
|
+
});
|
|
142
|
+
} catch (error) {
|
|
143
|
+
throw this.handleError(error);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|