@oxyhq/core 3.0.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 +33 -3
- package/dist/cjs/mixins/OxyServices.utility.js +3 -0
- 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 +33 -3
- package/dist/esm/mixins/OxyServices.utility.js +3 -0
- 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 +99 -5
- package/dist/types/mixins/OxyServices.utility.d.ts +7 -0
- 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 +20 -0
- package/src/mixins/OxyServices.applications.ts +119 -7
- package/src/mixins/OxyServices.utility.ts +11 -0
- package/src/mixins/OxyServices.workspaces.ts +309 -0
- package/src/mixins/index.ts +3 -0
- package/src/models/interfaces.ts +9 -0
package/dist/cjs/AuthManager.js
CHANGED
|
@@ -686,7 +686,14 @@ class AuthManager {
|
|
|
686
686
|
* Get a valid access token, refreshing automatically if expired or expiring soon.
|
|
687
687
|
*/
|
|
688
688
|
async getAccessToken() {
|
|
689
|
-
|
|
689
|
+
// In cookieOnly / cookie-restore flows the active access token lives only in
|
|
690
|
+
// memory (`_lastKnownAccessToken` + httpService) and is intentionally never
|
|
691
|
+
// written to JS storage — the cookieOnly contract forbids persisting tokens
|
|
692
|
+
// in JS-accessible storage. Fall back to the in-memory token when storage has
|
|
693
|
+
// none, otherwise getAccessToken returns null after every cold-boot/reload and
|
|
694
|
+
// standalone API clients (e.g. the Console axios client) send no Authorization
|
|
695
|
+
// header → 401 on every authed endpoint while `isAuthenticated` is still true.
|
|
696
|
+
const token = (await this.storage.getItem(STORAGE_KEYS.ACCESS_TOKEN)) ?? this._lastKnownAccessToken;
|
|
690
697
|
if (!token)
|
|
691
698
|
return null;
|
|
692
699
|
try {
|
|
@@ -697,7 +704,9 @@ class AuthManager {
|
|
|
697
704
|
if (decoded.exp - now < buffer) {
|
|
698
705
|
const refreshed = await this.refreshToken();
|
|
699
706
|
if (refreshed) {
|
|
700
|
-
|
|
707
|
+
// refreshToken() updates both storage and `_lastKnownAccessToken`;
|
|
708
|
+
// prefer storage but fall back to memory for the cookieOnly path.
|
|
709
|
+
return (await this.storage.getItem(STORAGE_KEYS.ACCESS_TOKEN)) ?? this._lastKnownAccessToken;
|
|
701
710
|
}
|
|
702
711
|
}
|
|
703
712
|
}
|
package/dist/cjs/OxyServices.js
CHANGED
|
@@ -26,6 +26,7 @@ const mixins_1 = require("./mixins");
|
|
|
26
26
|
* - **Karma**: Karma system
|
|
27
27
|
* - **Assets**: File upload and asset management
|
|
28
28
|
* - **Applications**: Application, membership, and credential management
|
|
29
|
+
* - **Workspaces**: Workspace and membership management
|
|
29
30
|
* - **Location**: Location-based features
|
|
30
31
|
* - **Analytics**: Analytics tracking
|
|
31
32
|
* - **Devices**: Device management
|
|
@@ -7,12 +7,40 @@ function OxyServicesApplicationsMixin(Base) {
|
|
|
7
7
|
constructor(...args) {
|
|
8
8
|
super(...args);
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Resolve an OAuth client identifier to the owning application's PUBLIC
|
|
12
|
+
* identity. No authentication required — the API returns only sanitized,
|
|
13
|
+
* display-safe metadata ({@link PublicApplication}). Use this to render the
|
|
14
|
+
* requesting application's name/icon in consent, authorize, and device-flow
|
|
15
|
+
* approval UIs before any session exists.
|
|
16
|
+
*
|
|
17
|
+
* @param clientId - The OAuth `client_id` (an active credential's public
|
|
18
|
+
* key). URL-encoded before being placed in the path.
|
|
19
|
+
*/
|
|
20
|
+
async getPublicApplication(clientId) {
|
|
21
|
+
try {
|
|
22
|
+
const res = await this.makeRequest('GET', `/auth/oauth/client/${encodeURIComponent(clientId)}`, undefined, { cache: true, cacheTTL: mixinHelpers_1.CACHE_TIMES.MEDIUM });
|
|
23
|
+
return res.application;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
throw this.handleError(error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
10
29
|
/**
|
|
11
30
|
* List applications the current user is an active member of.
|
|
31
|
+
*
|
|
32
|
+
* @param workspaceId - Optional workspace `_id` to scope the listing to
|
|
33
|
+
* applications belonging to that workspace. When provided it is appended
|
|
34
|
+
* as a `workspaceId` query parameter (URL-encoded). The query string is
|
|
35
|
+
* part of the request path, so the response cache keys on it
|
|
36
|
+
* automatically — scoped and unscoped lists never collide.
|
|
12
37
|
*/
|
|
13
|
-
async getApplications() {
|
|
38
|
+
async getApplications(workspaceId) {
|
|
14
39
|
try {
|
|
15
|
-
const
|
|
40
|
+
const path = workspaceId
|
|
41
|
+
? `/applications?workspaceId=${encodeURIComponent(workspaceId)}`
|
|
42
|
+
: '/applications';
|
|
43
|
+
const res = await this.makeRequest('GET', path, undefined, { cache: true, cacheTTL: mixinHelpers_1.CACHE_TIMES.MEDIUM });
|
|
16
44
|
return res.applications ?? [];
|
|
17
45
|
}
|
|
18
46
|
catch (error) {
|
|
@@ -169,7 +197,9 @@ function OxyServicesApplicationsMixin(Base) {
|
|
|
169
197
|
}
|
|
170
198
|
/**
|
|
171
199
|
* Rotate a credential's secret. The new plaintext `secret` is returned
|
|
172
|
-
* exactly ONCE
|
|
200
|
+
* exactly ONCE, along with audit fields: `rotatedFrom` (the previous
|
|
201
|
+
* credentialId) and `graceExpiresAt` (ISO string for the grace window during
|
|
202
|
+
* which the old credential is still honoured).
|
|
173
203
|
* @param applicationId - The application's Mongo `_id`.
|
|
174
204
|
* @param credentialId - The credential's Mongo `_id`.
|
|
175
205
|
*/
|
|
@@ -475,6 +475,9 @@ function OxyServicesUtilityMixin(Base) {
|
|
|
475
475
|
appId,
|
|
476
476
|
appName: decoded.appName || 'unknown',
|
|
477
477
|
scopes: Array.isArray(decoded.scopes) ? decoded.scopes : [],
|
|
478
|
+
...(typeof decoded.credentialId === 'string' && decoded.credentialId.length > 0
|
|
479
|
+
? { credentialId: decoded.credentialId }
|
|
480
|
+
: {}),
|
|
478
481
|
};
|
|
479
482
|
if (debug) {
|
|
480
483
|
loggerUtils_1.logger.debug(`[oxy.auth] Service token OK app=${decoded.appName} delegateUser=${oxyUserId || '(none)'}`, {
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OxyServicesWorkspacesMixin = OxyServicesWorkspacesMixin;
|
|
4
|
+
const mixinHelpers_1 = require("./mixinHelpers");
|
|
5
|
+
function OxyServicesWorkspacesMixin(Base) {
|
|
6
|
+
return class extends Base {
|
|
7
|
+
constructor(...args) {
|
|
8
|
+
super(...args);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* List workspaces the current user is an active member of.
|
|
12
|
+
*/
|
|
13
|
+
async getWorkspaces() {
|
|
14
|
+
try {
|
|
15
|
+
const res = await this.makeRequest('GET', '/workspaces', undefined, { cache: true, cacheTTL: mixinHelpers_1.CACHE_TIMES.MEDIUM });
|
|
16
|
+
return res.workspaces ?? [];
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
throw this.handleError(error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a new team workspace. The caller becomes its `owner`.
|
|
24
|
+
* @param data - Workspace configuration.
|
|
25
|
+
*/
|
|
26
|
+
async createWorkspace(data) {
|
|
27
|
+
try {
|
|
28
|
+
const res = await this.makeRequest('POST', '/workspaces', data, { cache: false });
|
|
29
|
+
return res.workspace;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
throw this.handleError(error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Fetch a single workspace by id.
|
|
37
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
38
|
+
*/
|
|
39
|
+
async getWorkspace(workspaceId) {
|
|
40
|
+
try {
|
|
41
|
+
const res = await this.makeRequest('GET', `/workspaces/${encodeURIComponent(workspaceId)}`, undefined, { cache: true, cacheTTL: mixinHelpers_1.CACHE_TIMES.LONG });
|
|
42
|
+
return res.workspace;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
throw this.handleError(error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Update a workspace's mutable fields.
|
|
50
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
51
|
+
* @param data - Subset of updatable fields.
|
|
52
|
+
*/
|
|
53
|
+
async updateWorkspace(workspaceId, data) {
|
|
54
|
+
try {
|
|
55
|
+
const res = await this.makeRequest('PATCH', `/workspaces/${encodeURIComponent(workspaceId)}`, data, { cache: false });
|
|
56
|
+
return res.workspace;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw this.handleError(error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Soft-delete a workspace (owner only).
|
|
64
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
65
|
+
*/
|
|
66
|
+
async deleteWorkspace(workspaceId) {
|
|
67
|
+
try {
|
|
68
|
+
return await this.makeRequest('DELETE', `/workspaces/${encodeURIComponent(workspaceId)}`, undefined, { cache: false });
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
throw this.handleError(error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* List members of a workspace.
|
|
76
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
77
|
+
*/
|
|
78
|
+
async getWorkspaceMembers(workspaceId) {
|
|
79
|
+
try {
|
|
80
|
+
const res = await this.makeRequest('GET', `/workspaces/${encodeURIComponent(workspaceId)}/members`, undefined, { cache: true, cacheTTL: mixinHelpers_1.CACHE_TIMES.MEDIUM });
|
|
81
|
+
return res.members ?? [];
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw this.handleError(error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Add a member to a workspace.
|
|
89
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
90
|
+
* @param data - Target user id and role (never `owner`).
|
|
91
|
+
*/
|
|
92
|
+
async inviteWorkspaceMember(workspaceId, data) {
|
|
93
|
+
try {
|
|
94
|
+
const res = await this.makeRequest('POST', `/workspaces/${encodeURIComponent(workspaceId)}/members`, data, { cache: false });
|
|
95
|
+
return res.member;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
throw this.handleError(error);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Change a member's role.
|
|
103
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
104
|
+
* @param memberId - The member's Mongo `_id`.
|
|
105
|
+
* @param data - New role (never `owner`).
|
|
106
|
+
*/
|
|
107
|
+
async updateWorkspaceMember(workspaceId, memberId, data) {
|
|
108
|
+
try {
|
|
109
|
+
const res = await this.makeRequest('PATCH', `/workspaces/${encodeURIComponent(workspaceId)}/members/${encodeURIComponent(memberId)}`, data, { cache: false });
|
|
110
|
+
return res.member;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
throw this.handleError(error);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Remove a member from a workspace.
|
|
118
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
119
|
+
* @param memberId - The member's Mongo `_id`.
|
|
120
|
+
*/
|
|
121
|
+
async removeWorkspaceMember(workspaceId, memberId) {
|
|
122
|
+
try {
|
|
123
|
+
return await this.makeRequest('DELETE', `/workspaces/${encodeURIComponent(workspaceId)}/members/${encodeURIComponent(memberId)}`, undefined, { cache: false });
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
throw this.handleError(error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Transfer ownership of a workspace to another member (owner only).
|
|
131
|
+
* Demotes the current owner and promotes the target to `owner`.
|
|
132
|
+
* @param workspaceId - The workspace's Mongo `_id`.
|
|
133
|
+
* @param data - Target user id.
|
|
134
|
+
*/
|
|
135
|
+
async transferWorkspaceOwnership(workspaceId, data) {
|
|
136
|
+
try {
|
|
137
|
+
return await this.makeRequest('POST', `/workspaces/${encodeURIComponent(workspaceId)}/transfer-ownership`, data, { cache: false });
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
throw this.handleError(error);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
package/dist/cjs/mixins/index.js
CHANGED
|
@@ -21,6 +21,7 @@ const OxyServices_payment_1 = require("./OxyServices.payment");
|
|
|
21
21
|
const OxyServices_karma_1 = require("./OxyServices.karma");
|
|
22
22
|
const OxyServices_assets_1 = require("./OxyServices.assets");
|
|
23
23
|
const OxyServices_applications_1 = require("./OxyServices.applications");
|
|
24
|
+
const OxyServices_workspaces_1 = require("./OxyServices.workspaces");
|
|
24
25
|
const OxyServices_location_1 = require("./OxyServices.location");
|
|
25
26
|
const OxyServices_analytics_1 = require("./OxyServices.analytics");
|
|
26
27
|
const OxyServices_devices_1 = require("./OxyServices.devices");
|
|
@@ -65,6 +66,7 @@ const MIXIN_PIPELINE = [
|
|
|
65
66
|
OxyServices_karma_1.OxyServicesKarmaMixin,
|
|
66
67
|
OxyServices_assets_1.OxyServicesAssetsMixin,
|
|
67
68
|
OxyServices_applications_1.OxyServicesApplicationsMixin,
|
|
69
|
+
OxyServices_workspaces_1.OxyServicesWorkspacesMixin,
|
|
68
70
|
OxyServices_location_1.OxyServicesLocationMixin,
|
|
69
71
|
OxyServices_analytics_1.OxyServicesAnalyticsMixin,
|
|
70
72
|
OxyServices_devices_1.OxyServicesDevicesMixin,
|