@oxyhq/core 3.1.0 → 3.2.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/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/AuthManager.js +11 -2
- package/dist/cjs/OxyServices.js +1 -0
- package/dist/cjs/mixins/OxyServices.applications.js +30 -2
- package/dist/cjs/mixins/OxyServices.workspaces.js +144 -0
- package/dist/cjs/mixins/index.js +2 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/AuthManager.js +11 -2
- package/dist/esm/OxyServices.js +1 -0
- package/dist/esm/mixins/OxyServices.applications.js +30 -2
- package/dist/esm/mixins/OxyServices.workspaces.js +141 -0
- package/dist/esm/mixins/index.js +2 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/OxyServices.d.ts +1 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/mixins/OxyServices.applications.d.ts +78 -8
- package/dist/types/mixins/OxyServices.workspaces.d.ts +199 -0
- package/dist/types/mixins/index.d.ts +2 -1
- package/dist/types/models/interfaces.d.ts +9 -0
- package/package.json +1 -1
- package/src/AuthManager.ts +11 -2
- package/src/OxyServices.ts +1 -0
- package/src/__tests__/authManager.cookiePath.test.ts +49 -0
- package/src/index.ts +19 -0
- package/src/mixins/OxyServices.applications.ts +95 -3
- package/src/mixins/OxyServices.workspaces.ts +309 -0
- package/src/mixins/index.ts +3 -0
- package/src/models/interfaces.ts +9 -0
|
@@ -58,12 +58,22 @@ export interface Application {
|
|
|
58
58
|
webhookUrl?: string;
|
|
59
59
|
devWebhookUrl?: string;
|
|
60
60
|
createdByUserId: string;
|
|
61
|
+
/**
|
|
62
|
+
* The workspace this application belongs to (workspace `_id`), or `null` for
|
|
63
|
+
* applications not owned by a workspace. Used by the console to scope apps to
|
|
64
|
+
* a workspace and to branch on workspace-derived access.
|
|
65
|
+
*/
|
|
66
|
+
workspaceId: string | null;
|
|
61
67
|
createdAt: string;
|
|
62
68
|
updatedAt: string;
|
|
63
69
|
/**
|
|
64
70
|
* The calling user's own membership in this application, embedded by the API
|
|
65
71
|
* on list (`GET /applications`) and detail (`GET /applications/:appId`)
|
|
66
72
|
* responses. Use `callerMembership.permissions` to gate UI affordances.
|
|
73
|
+
*
|
|
74
|
+
* When the caller's access is derived from a workspace membership rather than
|
|
75
|
+
* a direct application membership, the API returns a synthetic membership
|
|
76
|
+
* with `source: 'workspace'` and `_id: null`.
|
|
67
77
|
*/
|
|
68
78
|
callerMembership?: ApplicationMember;
|
|
69
79
|
}
|
|
@@ -73,7 +83,11 @@ export interface Application {
|
|
|
73
83
|
* on the server at write time.
|
|
74
84
|
*/
|
|
75
85
|
export interface ApplicationMember {
|
|
76
|
-
|
|
86
|
+
/**
|
|
87
|
+
* The membership's Mongo `_id`. `null` for a synthetic, workspace-derived
|
|
88
|
+
* membership (see {@link Application.callerMembership} and `source`).
|
|
89
|
+
*/
|
|
90
|
+
_id: string | null;
|
|
77
91
|
applicationId: string;
|
|
78
92
|
userId: string;
|
|
79
93
|
role: ApplicationRole;
|
|
@@ -81,6 +95,13 @@ export interface ApplicationMember {
|
|
|
81
95
|
invitedByUserId?: string;
|
|
82
96
|
joinedAt?: string;
|
|
83
97
|
status: ApplicationMemberStatus;
|
|
98
|
+
/**
|
|
99
|
+
* Origin of this membership. When `'workspace'`, the membership is synthetic
|
|
100
|
+
* and derived from the caller's workspace membership rather than a direct
|
|
101
|
+
* application membership (in which case `_id` is `null`). Absent or any other
|
|
102
|
+
* value indicates a direct application membership.
|
|
103
|
+
*/
|
|
104
|
+
source?: 'workspace';
|
|
84
105
|
createdAt: string;
|
|
85
106
|
updatedAt: string;
|
|
86
107
|
}
|
|
@@ -110,6 +131,39 @@ export interface ApplicationCredential {
|
|
|
110
131
|
updatedAt: string;
|
|
111
132
|
}
|
|
112
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Sanitized, PUBLIC application identity returned by the API when resolving a
|
|
136
|
+
* cross-app/OAuth client to a registered {@link Application}.
|
|
137
|
+
*
|
|
138
|
+
* Unlike {@link Application}, this shape carries NO sensitive or membership
|
|
139
|
+
* fields — it is safe to display unauthenticated in consent/authorize screens
|
|
140
|
+
* and device-flow approval UIs. The API resolves a `client_id` (OAuth
|
|
141
|
+
* credential public key) to the owning application and projects only the
|
|
142
|
+
* fields below. `id` is the application's `_id` as a string.
|
|
143
|
+
*/
|
|
144
|
+
export interface PublicApplication {
|
|
145
|
+
/** The application's Mongo `_id` as a string. */
|
|
146
|
+
id: string;
|
|
147
|
+
/** Human-readable application name shown to the user. */
|
|
148
|
+
name: string;
|
|
149
|
+
/** Optional short description of what the application does. */
|
|
150
|
+
description?: string;
|
|
151
|
+
/** Optional icon URL for the application. */
|
|
152
|
+
icon?: string;
|
|
153
|
+
/** Optional public website/homepage URL for the application. */
|
|
154
|
+
websiteUrl?: string;
|
|
155
|
+
/** Application classification (set by Oxy platform staff). */
|
|
156
|
+
type: ApplicationType;
|
|
157
|
+
/** Whether the application is an officially endorsed Oxy application. */
|
|
158
|
+
isOfficial: boolean;
|
|
159
|
+
/** Whether the application is an internal Oxy ecosystem application. */
|
|
160
|
+
isInternal: boolean;
|
|
161
|
+
/** OAuth scopes the application is configured to request. */
|
|
162
|
+
scopes: string[];
|
|
163
|
+
/** Optional display name of the developer/owner organisation. */
|
|
164
|
+
developerName?: string;
|
|
165
|
+
}
|
|
166
|
+
|
|
113
167
|
/** Input accepted by `createApplication`. Staff-only fields are not settable here. */
|
|
114
168
|
export interface CreateApplicationInput {
|
|
115
169
|
name: string;
|
|
@@ -118,6 +172,11 @@ export interface CreateApplicationInput {
|
|
|
118
172
|
icon?: string;
|
|
119
173
|
redirectUris?: string[];
|
|
120
174
|
scopes?: string[];
|
|
175
|
+
/**
|
|
176
|
+
* Optional workspace `_id` to create the app in. Omitted → API defaults to
|
|
177
|
+
* the caller's personal workspace.
|
|
178
|
+
*/
|
|
179
|
+
workspaceId?: string;
|
|
121
180
|
}
|
|
122
181
|
|
|
123
182
|
/** Input accepted by `updateApplication`. Staff-only fields are not settable here. */
|
|
@@ -222,14 +281,47 @@ export function OxyServicesApplicationsMixin<T extends typeof OxyServicesBase>(B
|
|
|
222
281
|
super(...(args as [any]));
|
|
223
282
|
}
|
|
224
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Resolve an OAuth client identifier to the owning application's PUBLIC
|
|
286
|
+
* identity. No authentication required — the API returns only sanitized,
|
|
287
|
+
* display-safe metadata ({@link PublicApplication}). Use this to render the
|
|
288
|
+
* requesting application's name/icon in consent, authorize, and device-flow
|
|
289
|
+
* approval UIs before any session exists.
|
|
290
|
+
*
|
|
291
|
+
* @param clientId - The OAuth `client_id` (an active credential's public
|
|
292
|
+
* key). URL-encoded before being placed in the path.
|
|
293
|
+
*/
|
|
294
|
+
async getPublicApplication(clientId: string): Promise<PublicApplication> {
|
|
295
|
+
try {
|
|
296
|
+
const res = await this.makeRequest<{ application: PublicApplication }>(
|
|
297
|
+
'GET',
|
|
298
|
+
`/auth/oauth/client/${encodeURIComponent(clientId)}`,
|
|
299
|
+
undefined,
|
|
300
|
+
{ cache: true, cacheTTL: CACHE_TIMES.MEDIUM },
|
|
301
|
+
);
|
|
302
|
+
return res.application;
|
|
303
|
+
} catch (error) {
|
|
304
|
+
throw this.handleError(error);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
225
308
|
/**
|
|
226
309
|
* List applications the current user is an active member of.
|
|
310
|
+
*
|
|
311
|
+
* @param workspaceId - Optional workspace `_id` to scope the listing to
|
|
312
|
+
* applications belonging to that workspace. When provided it is appended
|
|
313
|
+
* as a `workspaceId` query parameter (URL-encoded). The query string is
|
|
314
|
+
* part of the request path, so the response cache keys on it
|
|
315
|
+
* automatically — scoped and unscoped lists never collide.
|
|
227
316
|
*/
|
|
228
|
-
async getApplications(): Promise<Application[]> {
|
|
317
|
+
async getApplications(workspaceId?: string): Promise<Application[]> {
|
|
229
318
|
try {
|
|
319
|
+
const path = workspaceId
|
|
320
|
+
? `/applications?workspaceId=${encodeURIComponent(workspaceId)}`
|
|
321
|
+
: '/applications';
|
|
230
322
|
const res = await this.makeRequest<{ applications?: Application[] }>(
|
|
231
323
|
'GET',
|
|
232
|
-
|
|
324
|
+
path,
|
|
233
325
|
undefined,
|
|
234
326
|
{ cache: true, cacheTTL: CACHE_TIMES.MEDIUM },
|
|
235
327
|
);
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspaces Methods Mixin
|
|
3
|
+
*
|
|
4
|
+
* Provides methods for managing Oxy workspaces and their members via the
|
|
5
|
+
* `/workspaces` API. A workspace is a multi-user container that owns
|
|
6
|
+
* applications and other resources: membership (with a role) grants
|
|
7
|
+
* permissions. A `personal` workspace is created implicitly for every user;
|
|
8
|
+
* `team` workspaces are created explicitly and can invite additional members.
|
|
9
|
+
*
|
|
10
|
+
* Reference workspaces by their Mongo `_id` and members by their member `_id`.
|
|
11
|
+
* Never by name or slug.
|
|
12
|
+
*/
|
|
13
|
+
import type { OxyServicesBase } from '../OxyServices.base';
|
|
14
|
+
import { CACHE_TIMES } from './mixinHelpers';
|
|
15
|
+
|
|
16
|
+
/** Role a member holds within a workspace. */
|
|
17
|
+
export type WorkspaceRole = 'owner' | 'admin' | 'member' | 'viewer';
|
|
18
|
+
|
|
19
|
+
/** Workspace classification. A `personal` workspace is implicit per user. */
|
|
20
|
+
export type WorkspaceType = 'personal' | 'team';
|
|
21
|
+
|
|
22
|
+
/** Lifecycle status of a workspace. */
|
|
23
|
+
export type WorkspaceStatus = 'active' | 'deleted';
|
|
24
|
+
|
|
25
|
+
/** Membership lifecycle status. */
|
|
26
|
+
export type WorkspaceMemberStatus = 'active' | 'invited' | 'removed';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Client-facing WorkspaceMember shape. `permissions` is derived from `role`
|
|
30
|
+
* on the server at write time.
|
|
31
|
+
*/
|
|
32
|
+
export interface WorkspaceMember {
|
|
33
|
+
_id: string;
|
|
34
|
+
workspaceId: string;
|
|
35
|
+
userId: string;
|
|
36
|
+
role: WorkspaceRole;
|
|
37
|
+
permissions: string[];
|
|
38
|
+
invitedByUserId?: string | null;
|
|
39
|
+
joinedAt?: string | null;
|
|
40
|
+
status: WorkspaceMemberStatus;
|
|
41
|
+
createdAt: string;
|
|
42
|
+
updatedAt: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Client-facing Workspace shape returned by the `/workspaces` API. Mirrors the
|
|
47
|
+
* server `Workspace` model with `_id` as a string and dates serialized to ISO
|
|
48
|
+
* strings.
|
|
49
|
+
*/
|
|
50
|
+
export interface Workspace {
|
|
51
|
+
_id: string;
|
|
52
|
+
name: string;
|
|
53
|
+
slug: string;
|
|
54
|
+
type: WorkspaceType;
|
|
55
|
+
description?: string | null;
|
|
56
|
+
icon?: string | null;
|
|
57
|
+
ownerId: string;
|
|
58
|
+
status: WorkspaceStatus;
|
|
59
|
+
createdAt: string;
|
|
60
|
+
updatedAt: string;
|
|
61
|
+
/**
|
|
62
|
+
* The calling user's own membership in this workspace, embedded by the API
|
|
63
|
+
* on list (`GET /workspaces`) and detail (`GET /workspaces/:id`) responses.
|
|
64
|
+
* Use `callerMembership.permissions` to gate UI affordances.
|
|
65
|
+
*/
|
|
66
|
+
callerMembership?: WorkspaceMember | null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Input accepted by `createWorkspace`. */
|
|
70
|
+
export interface CreateWorkspaceInput {
|
|
71
|
+
name: string;
|
|
72
|
+
description?: string;
|
|
73
|
+
icon?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Input accepted by `updateWorkspace`. */
|
|
77
|
+
export interface UpdateWorkspaceInput {
|
|
78
|
+
name?: string;
|
|
79
|
+
description?: string | null;
|
|
80
|
+
icon?: string | null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Input accepted by `inviteWorkspaceMember`. The owner role cannot be invited. */
|
|
84
|
+
export interface InviteWorkspaceMemberInput {
|
|
85
|
+
userId: string;
|
|
86
|
+
role: Exclude<WorkspaceRole, 'owner'>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Input accepted by `updateWorkspaceMember`. The owner role cannot be assigned. */
|
|
90
|
+
export interface UpdateWorkspaceMemberInput {
|
|
91
|
+
role: Exclude<WorkspaceRole, 'owner'>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Input accepted by `transferWorkspaceOwnership`. */
|
|
95
|
+
export interface TransferWorkspaceOwnershipInput {
|
|
96
|
+
userId: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Result of a delete/remove/transfer operation. */
|
|
100
|
+
export interface WorkspaceSuccessResult {
|
|
101
|
+
success: boolean;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function OxyServicesWorkspacesMixin<T extends typeof OxyServicesBase>(Base: T) {
|
|
105
|
+
return class extends Base {
|
|
106
|
+
constructor(...args: any[]) {
|
|
107
|
+
super(...(args as [any]));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* List workspaces the current user is an active member of.
|
|
112
|
+
*/
|
|
113
|
+
async getWorkspaces(): Promise<Workspace[]> {
|
|
114
|
+
try {
|
|
115
|
+
const res = await this.makeRequest<{ workspaces?: Workspace[] }>(
|
|
116
|
+
'GET',
|
|
117
|
+
'/workspaces',
|
|
118
|
+
undefined,
|
|
119
|
+
{ cache: true, cacheTTL: CACHE_TIMES.MEDIUM },
|
|
120
|
+
);
|
|
121
|
+
return res.workspaces ?? [];
|
|
122
|
+
} catch (error) {
|
|
123
|
+
throw this.handleError(error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create a new team workspace. The caller becomes its `owner`.
|
|
129
|
+
* @param data - Workspace configuration.
|
|
130
|
+
*/
|
|
131
|
+
async createWorkspace(data: CreateWorkspaceInput): Promise<Workspace> {
|
|
132
|
+
try {
|
|
133
|
+
const res = await this.makeRequest<{ workspace: Workspace }>(
|
|
134
|
+
'POST',
|
|
135
|
+
'/workspaces',
|
|
136
|
+
data,
|
|
137
|
+
{ cache: false },
|
|
138
|
+
);
|
|
139
|
+
return res.workspace;
|
|
140
|
+
} catch (error) {
|
|
141
|
+
throw this.handleError(error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Fetch a single workspace by id.
|
|
147
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
148
|
+
*/
|
|
149
|
+
async getWorkspace(workspaceId: string): Promise<Workspace> {
|
|
150
|
+
try {
|
|
151
|
+
const res = await this.makeRequest<{ workspace: Workspace }>(
|
|
152
|
+
'GET',
|
|
153
|
+
`/workspaces/${encodeURIComponent(workspaceId)}`,
|
|
154
|
+
undefined,
|
|
155
|
+
{ cache: true, cacheTTL: CACHE_TIMES.LONG },
|
|
156
|
+
);
|
|
157
|
+
return res.workspace;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
throw this.handleError(error);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Update a workspace's mutable fields.
|
|
165
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
166
|
+
* @param data - Subset of updatable fields.
|
|
167
|
+
*/
|
|
168
|
+
async updateWorkspace(
|
|
169
|
+
workspaceId: string,
|
|
170
|
+
data: UpdateWorkspaceInput,
|
|
171
|
+
): Promise<Workspace> {
|
|
172
|
+
try {
|
|
173
|
+
const res = await this.makeRequest<{ workspace: Workspace }>(
|
|
174
|
+
'PATCH',
|
|
175
|
+
`/workspaces/${encodeURIComponent(workspaceId)}`,
|
|
176
|
+
data,
|
|
177
|
+
{ cache: false },
|
|
178
|
+
);
|
|
179
|
+
return res.workspace;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
throw this.handleError(error);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Soft-delete a workspace (owner only).
|
|
187
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
188
|
+
*/
|
|
189
|
+
async deleteWorkspace(workspaceId: string): Promise<WorkspaceSuccessResult> {
|
|
190
|
+
try {
|
|
191
|
+
return await this.makeRequest<WorkspaceSuccessResult>(
|
|
192
|
+
'DELETE',
|
|
193
|
+
`/workspaces/${encodeURIComponent(workspaceId)}`,
|
|
194
|
+
undefined,
|
|
195
|
+
{ cache: false },
|
|
196
|
+
);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
throw this.handleError(error);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* List members of a workspace.
|
|
204
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
205
|
+
*/
|
|
206
|
+
async getWorkspaceMembers(workspaceId: string): Promise<WorkspaceMember[]> {
|
|
207
|
+
try {
|
|
208
|
+
const res = await this.makeRequest<{ members?: WorkspaceMember[] }>(
|
|
209
|
+
'GET',
|
|
210
|
+
`/workspaces/${encodeURIComponent(workspaceId)}/members`,
|
|
211
|
+
undefined,
|
|
212
|
+
{ cache: true, cacheTTL: CACHE_TIMES.MEDIUM },
|
|
213
|
+
);
|
|
214
|
+
return res.members ?? [];
|
|
215
|
+
} catch (error) {
|
|
216
|
+
throw this.handleError(error);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Add a member to a workspace.
|
|
222
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
223
|
+
* @param data - Target user id and role (never `owner`).
|
|
224
|
+
*/
|
|
225
|
+
async inviteWorkspaceMember(
|
|
226
|
+
workspaceId: string,
|
|
227
|
+
data: InviteWorkspaceMemberInput,
|
|
228
|
+
): Promise<WorkspaceMember> {
|
|
229
|
+
try {
|
|
230
|
+
const res = await this.makeRequest<{ member: WorkspaceMember }>(
|
|
231
|
+
'POST',
|
|
232
|
+
`/workspaces/${encodeURIComponent(workspaceId)}/members`,
|
|
233
|
+
data,
|
|
234
|
+
{ cache: false },
|
|
235
|
+
);
|
|
236
|
+
return res.member;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
throw this.handleError(error);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Change a member's role.
|
|
244
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
245
|
+
* @param memberId - The member's Mongo `_id`.
|
|
246
|
+
* @param data - New role (never `owner`).
|
|
247
|
+
*/
|
|
248
|
+
async updateWorkspaceMember(
|
|
249
|
+
workspaceId: string,
|
|
250
|
+
memberId: string,
|
|
251
|
+
data: UpdateWorkspaceMemberInput,
|
|
252
|
+
): Promise<WorkspaceMember> {
|
|
253
|
+
try {
|
|
254
|
+
const res = await this.makeRequest<{ member: WorkspaceMember }>(
|
|
255
|
+
'PATCH',
|
|
256
|
+
`/workspaces/${encodeURIComponent(workspaceId)}/members/${encodeURIComponent(memberId)}`,
|
|
257
|
+
data,
|
|
258
|
+
{ cache: false },
|
|
259
|
+
);
|
|
260
|
+
return res.member;
|
|
261
|
+
} catch (error) {
|
|
262
|
+
throw this.handleError(error);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Remove a member from a workspace.
|
|
268
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
269
|
+
* @param memberId - The member's Mongo `_id`.
|
|
270
|
+
*/
|
|
271
|
+
async removeWorkspaceMember(
|
|
272
|
+
workspaceId: string,
|
|
273
|
+
memberId: string,
|
|
274
|
+
): Promise<WorkspaceSuccessResult> {
|
|
275
|
+
try {
|
|
276
|
+
return await this.makeRequest<WorkspaceSuccessResult>(
|
|
277
|
+
'DELETE',
|
|
278
|
+
`/workspaces/${encodeURIComponent(workspaceId)}/members/${encodeURIComponent(memberId)}`,
|
|
279
|
+
undefined,
|
|
280
|
+
{ cache: false },
|
|
281
|
+
);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
throw this.handleError(error);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Transfer ownership of a workspace to another member (owner only).
|
|
289
|
+
* Demotes the current owner and promotes the target to `owner`.
|
|
290
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
291
|
+
* @param data - Target user id.
|
|
292
|
+
*/
|
|
293
|
+
async transferWorkspaceOwnership(
|
|
294
|
+
workspaceId: string,
|
|
295
|
+
data: TransferWorkspaceOwnershipInput,
|
|
296
|
+
): Promise<WorkspaceSuccessResult> {
|
|
297
|
+
try {
|
|
298
|
+
return await this.makeRequest<WorkspaceSuccessResult>(
|
|
299
|
+
'POST',
|
|
300
|
+
`/workspaces/${encodeURIComponent(workspaceId)}/transfer-ownership`,
|
|
301
|
+
data,
|
|
302
|
+
{ cache: false },
|
|
303
|
+
);
|
|
304
|
+
} catch (error) {
|
|
305
|
+
throw this.handleError(error);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
package/src/mixins/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { OxyServicesPaymentMixin } from './OxyServices.payment';
|
|
|
18
18
|
import { OxyServicesKarmaMixin } from './OxyServices.karma';
|
|
19
19
|
import { OxyServicesAssetsMixin } from './OxyServices.assets';
|
|
20
20
|
import { OxyServicesApplicationsMixin } from './OxyServices.applications';
|
|
21
|
+
import { OxyServicesWorkspacesMixin } from './OxyServices.workspaces';
|
|
21
22
|
import { OxyServicesLocationMixin } from './OxyServices.location';
|
|
22
23
|
import { OxyServicesAnalyticsMixin } from './OxyServices.analytics';
|
|
23
24
|
import { OxyServicesDevicesMixin } from './OxyServices.devices';
|
|
@@ -51,6 +52,7 @@ type AllMixinInstances =
|
|
|
51
52
|
& InstanceType<ReturnType<typeof OxyServicesKarmaMixin<typeof OxyServicesBase>>>
|
|
52
53
|
& InstanceType<ReturnType<typeof OxyServicesAssetsMixin<typeof OxyServicesBase>>>
|
|
53
54
|
& InstanceType<ReturnType<typeof OxyServicesApplicationsMixin<typeof OxyServicesBase>>>
|
|
55
|
+
& InstanceType<ReturnType<typeof OxyServicesWorkspacesMixin<typeof OxyServicesBase>>>
|
|
54
56
|
& InstanceType<ReturnType<typeof OxyServicesLocationMixin<typeof OxyServicesBase>>>
|
|
55
57
|
& InstanceType<ReturnType<typeof OxyServicesAnalyticsMixin<typeof OxyServicesBase>>>
|
|
56
58
|
& InstanceType<ReturnType<typeof OxyServicesDevicesMixin<typeof OxyServicesBase>>>
|
|
@@ -115,6 +117,7 @@ const MIXIN_PIPELINE: MixinFunction[] = [
|
|
|
115
117
|
OxyServicesKarmaMixin,
|
|
116
118
|
OxyServicesAssetsMixin,
|
|
117
119
|
OxyServicesApplicationsMixin,
|
|
120
|
+
OxyServicesWorkspacesMixin,
|
|
118
121
|
OxyServicesLocationMixin,
|
|
119
122
|
OxyServicesAnalyticsMixin,
|
|
120
123
|
OxyServicesDevicesMixin,
|
package/src/models/interfaces.ts
CHANGED
|
@@ -17,6 +17,15 @@ export interface OxyConfig {
|
|
|
17
17
|
sessionBaseUrl?: string;
|
|
18
18
|
authWebUrl?: string;
|
|
19
19
|
authRedirectUri?: string;
|
|
20
|
+
/**
|
|
21
|
+
* The app's Oxy OAuth client id (ApplicationCredential publicKey).
|
|
22
|
+
*
|
|
23
|
+
* Identifies this app in OAuth authorize / consent flows (issue #214). Purely
|
|
24
|
+
* declarative: the SDK stores it on `OxyServices.config.clientId` for later
|
|
25
|
+
* OAuth-authorize use. It is unrelated to the cross-domain `/sso?client_id=…`
|
|
26
|
+
* bounce (which uses the RP origin, not this registered client id).
|
|
27
|
+
*/
|
|
28
|
+
clientId?: string;
|
|
20
29
|
// Performance & caching options
|
|
21
30
|
enableCache?: boolean;
|
|
22
31
|
cacheTTL?: number; // Cache TTL in milliseconds (default: 5 minutes)
|