@symbo.ls/sdk 3.2.3 → 3.2.7
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 +141 -0
- package/dist/cjs/config/environment.js +94 -10
- package/dist/cjs/index.js +152 -12
- package/dist/cjs/services/AdminService.js +351 -0
- package/dist/cjs/services/AuthService.js +738 -305
- package/dist/cjs/services/BaseService.js +158 -6
- package/dist/cjs/services/BranchService.js +484 -0
- package/dist/cjs/services/CollabService.js +439 -116
- package/dist/cjs/services/DnsService.js +340 -0
- package/dist/cjs/services/FeatureFlagService.js +175 -0
- package/dist/cjs/services/FileService.js +201 -0
- package/dist/cjs/services/IntegrationService.js +538 -0
- package/dist/cjs/services/MetricsService.js +62 -0
- package/dist/cjs/services/PaymentService.js +271 -0
- package/dist/cjs/services/PlanService.js +426 -0
- package/dist/cjs/services/ProjectService.js +1207 -0
- package/dist/cjs/services/PullRequestService.js +503 -0
- package/dist/cjs/services/ScreenshotService.js +304 -0
- package/dist/cjs/services/SubscriptionService.js +396 -0
- package/dist/cjs/services/TrackingService.js +661 -0
- package/dist/cjs/services/WaitlistService.js +148 -0
- package/dist/cjs/services/index.js +60 -4
- package/dist/cjs/state/RootStateManager.js +2 -23
- package/dist/cjs/state/rootEventBus.js +9 -0
- package/dist/cjs/utils/CollabClient.js +78 -12
- package/dist/cjs/utils/TokenManager.js +16 -3
- package/dist/cjs/utils/changePreprocessor.js +199 -0
- package/dist/cjs/utils/jsonDiff.js +46 -4
- package/dist/cjs/utils/ordering.js +309 -0
- package/dist/cjs/utils/services.js +285 -128
- package/dist/cjs/utils/validation.js +0 -3
- package/dist/esm/config/environment.js +94 -10
- package/dist/esm/index.js +47862 -18248
- package/dist/esm/services/AdminService.js +1132 -0
- package/dist/esm/services/AuthService.js +1493 -386
- package/dist/esm/services/BaseService.js +757 -6
- package/dist/esm/services/BranchService.js +1265 -0
- package/dist/esm/services/CollabService.js +24956 -16089
- package/dist/esm/services/DnsService.js +1121 -0
- package/dist/esm/services/FeatureFlagService.js +956 -0
- package/dist/esm/services/FileService.js +982 -0
- package/dist/esm/services/IntegrationService.js +1319 -0
- package/dist/esm/services/MetricsService.js +843 -0
- package/dist/esm/services/PaymentService.js +1052 -0
- package/dist/esm/services/PlanService.js +1207 -0
- package/dist/esm/services/ProjectService.js +2526 -0
- package/dist/esm/services/PullRequestService.js +1284 -0
- package/dist/esm/services/ScreenshotService.js +1085 -0
- package/dist/esm/services/SubscriptionService.js +1177 -0
- package/dist/esm/services/TrackingService.js +18454 -0
- package/dist/esm/services/WaitlistService.js +929 -0
- package/dist/esm/services/index.js +47373 -18027
- package/dist/esm/state/RootStateManager.js +11 -23
- package/dist/esm/state/rootEventBus.js +9 -0
- package/dist/esm/utils/CollabClient.js +17526 -16120
- package/dist/esm/utils/TokenManager.js +16 -3
- package/dist/esm/utils/changePreprocessor.js +542 -0
- package/dist/esm/utils/jsonDiff.js +958 -43
- package/dist/esm/utils/ordering.js +291 -0
- package/dist/esm/utils/services.js +285 -128
- package/dist/esm/utils/validation.js +116 -50
- package/dist/node/config/environment.js +94 -10
- package/dist/node/index.js +183 -16
- package/dist/node/services/AdminService.js +332 -0
- package/dist/node/services/AuthService.js +742 -310
- package/dist/node/services/BaseService.js +148 -6
- package/dist/node/services/BranchService.js +465 -0
- package/dist/node/services/CollabService.js +439 -116
- package/dist/node/services/DnsService.js +321 -0
- package/dist/node/services/FeatureFlagService.js +156 -0
- package/dist/node/services/FileService.js +182 -0
- package/dist/node/services/IntegrationService.js +519 -0
- package/dist/node/services/MetricsService.js +43 -0
- package/dist/node/services/PaymentService.js +252 -0
- package/dist/node/services/PlanService.js +407 -0
- package/dist/node/services/ProjectService.js +1188 -0
- package/dist/node/services/PullRequestService.js +484 -0
- package/dist/node/services/ScreenshotService.js +285 -0
- package/dist/node/services/SubscriptionService.js +377 -0
- package/dist/node/services/TrackingService.js +632 -0
- package/dist/node/services/WaitlistService.js +129 -0
- package/dist/node/services/index.js +60 -4
- package/dist/node/state/RootStateManager.js +2 -23
- package/dist/node/state/rootEventBus.js +9 -0
- package/dist/node/utils/CollabClient.js +77 -11
- package/dist/node/utils/TokenManager.js +16 -3
- package/dist/node/utils/changePreprocessor.js +180 -0
- package/dist/node/utils/jsonDiff.js +46 -4
- package/dist/node/utils/ordering.js +290 -0
- package/dist/node/utils/services.js +285 -128
- package/dist/node/utils/validation.js +0 -3
- package/package.json +30 -18
- package/src/config/environment.js +95 -10
- package/src/index.js +190 -23
- package/src/services/AdminService.js +374 -0
- package/src/services/AuthService.js +874 -328
- package/src/services/BaseService.js +166 -6
- package/src/services/BranchService.js +536 -0
- package/src/services/CollabService.js +557 -148
- package/src/services/DnsService.js +366 -0
- package/src/services/FeatureFlagService.js +174 -0
- package/src/services/FileService.js +213 -0
- package/src/services/IntegrationService.js +548 -0
- package/src/services/MetricsService.js +40 -0
- package/src/services/PaymentService.js +287 -0
- package/src/services/PlanService.js +468 -0
- package/src/services/ProjectService.js +1366 -0
- package/src/services/PullRequestService.js +537 -0
- package/src/services/ScreenshotService.js +258 -0
- package/src/services/SubscriptionService.js +425 -0
- package/src/services/TrackingService.js +853 -0
- package/src/services/WaitlistService.js +130 -0
- package/src/services/index.js +79 -5
- package/src/services/tests/BranchService/createBranch.test.js +153 -0
- package/src/services/tests/BranchService/deleteBranch.test.js +173 -0
- package/src/services/tests/BranchService/getBranchChanges.test.js +146 -0
- package/src/services/tests/BranchService/listBranches.test.js +87 -0
- package/src/services/tests/BranchService/mergeBranch.test.js +210 -0
- package/src/services/tests/BranchService/publishVersion.test.js +183 -0
- package/src/services/tests/BranchService/renameBranch.test.js +240 -0
- package/src/services/tests/BranchService/resetBranch.test.js +152 -0
- package/src/services/tests/FeatureFlagService/adminFeatureFlags.test.js +67 -0
- package/src/services/tests/FeatureFlagService/getFeatureFlags.test.js +75 -0
- package/src/services/tests/FileService/createFileFormData.test.js +74 -0
- package/src/services/tests/FileService/getFileUrl.test.js +69 -0
- package/src/services/tests/FileService/updateProjectIcon.test.js +109 -0
- package/src/services/tests/FileService/uploadDocument.test.js +36 -0
- package/src/services/tests/FileService/uploadFile.test.js +78 -0
- package/src/services/tests/FileService/uploadFileWithValidation.test.js +114 -0
- package/src/services/tests/FileService/uploadImage.test.js +36 -0
- package/src/services/tests/FileService/uploadMultipleFiles.test.js +111 -0
- package/src/services/tests/FileService/validateFile.test.js +63 -0
- package/src/services/tests/PlanService/createPlan.test.js +104 -0
- package/src/services/tests/PlanService/createPlanWithValidation.test.js +523 -0
- package/src/services/tests/PlanService/deletePlan.test.js +92 -0
- package/src/services/tests/PlanService/getActivePlans.test.js +123 -0
- package/src/services/tests/PlanService/getAdminPlans.test.js +84 -0
- package/src/services/tests/PlanService/getPlan.test.js +50 -0
- package/src/services/tests/PlanService/getPlanByKey.test.js +109 -0
- package/src/services/tests/PlanService/getPlanWithValidation.test.js +85 -0
- package/src/services/tests/PlanService/getPlans.test.js +53 -0
- package/src/services/tests/PlanService/getPlansByPriceRange.test.js +109 -0
- package/src/services/tests/PlanService/getPlansWithValidation.test.js +48 -0
- package/src/services/tests/PlanService/initializePlans.test.js +75 -0
- package/src/services/tests/PlanService/updatePlan.test.js +111 -0
- package/src/services/tests/PlanService/updatePlanWithValidation.test.js +556 -0
- package/src/state/RootStateManager.js +37 -32
- package/src/state/rootEventBus.js +19 -0
- package/src/utils/CollabClient.js +99 -12
- package/src/utils/TokenManager.js +20 -3
- package/src/utils/changePreprocessor.js +239 -0
- package/src/utils/jsonDiff.js +40 -5
- package/src/utils/ordering.js +271 -0
- package/src/utils/services.js +306 -139
- package/src/utils/validation.js +0 -3
- package/dist/cjs/services/AIService.js +0 -155
- package/dist/cjs/services/BasedService.js +0 -1185
- package/dist/cjs/services/CoreService.js +0 -2295
- package/dist/cjs/services/SocketService.js +0 -309
- package/dist/cjs/services/SymstoryService.js +0 -571
- package/dist/cjs/utils/basedQuerys.js +0 -181
- package/dist/cjs/utils/symstoryClient.js +0 -259
- package/dist/esm/services/AIService.js +0 -185
- package/dist/esm/services/BasedService.js +0 -5262
- package/dist/esm/services/CoreService.js +0 -2827
- package/dist/esm/services/SocketService.js +0 -456
- package/dist/esm/services/SymstoryService.js +0 -7025
- package/dist/esm/utils/basedQuerys.js +0 -163
- package/dist/esm/utils/symstoryClient.js +0 -354
- package/dist/node/services/AIService.js +0 -136
- package/dist/node/services/BasedService.js +0 -1156
- package/dist/node/services/CoreService.js +0 -2266
- package/dist/node/services/SocketService.js +0 -280
- package/dist/node/services/SymstoryService.js +0 -542
- package/dist/node/utils/basedQuerys.js +0 -162
- package/dist/node/utils/symstoryClient.js +0 -230
- package/src/services/AIService.js +0 -150
- package/src/services/BasedService.js +0 -1302
- package/src/services/CoreService.js +0 -2548
- package/src/services/SocketService.js +0 -336
- package/src/services/SymstoryService.js +0 -649
- package/src/utils/basedQuerys.js +0 -164
- package/src/utils/symstoryClient.js +0 -252
|
@@ -1,191 +1,745 @@
|
|
|
1
1
|
import { BaseService } from "./BaseService.js";
|
|
2
2
|
import {
|
|
3
|
-
PERMISSION_MAP,
|
|
4
3
|
ROLE_PERMISSIONS,
|
|
5
4
|
TIER_FEATURES,
|
|
6
5
|
PROJECT_ROLE_PERMISSIONS
|
|
7
6
|
} from "../utils/permission.js";
|
|
7
|
+
const PLUGIN_SESSION_STORAGE_KEY = "plugin_auth_session";
|
|
8
8
|
class AuthService extends BaseService {
|
|
9
9
|
constructor(config) {
|
|
10
|
+
var _a, _b;
|
|
10
11
|
super(config);
|
|
11
12
|
this._userRoles = /* @__PURE__ */ new Set(["guest", "editor", "admin", "owner"]);
|
|
12
13
|
this._projectTiers = /* @__PURE__ */ new Set([
|
|
13
14
|
"ready",
|
|
14
|
-
"
|
|
15
|
+
"starter",
|
|
15
16
|
"pro1",
|
|
16
17
|
"pro2",
|
|
17
18
|
"enterprise"
|
|
18
19
|
]);
|
|
19
|
-
this.
|
|
20
|
+
this._projectRoleCache = /* @__PURE__ */ new Map();
|
|
21
|
+
this._roleCacheExpiry = 5 * 60 * 1e3;
|
|
22
|
+
this._pluginSession = null;
|
|
23
|
+
this._resolvePluginSession(
|
|
24
|
+
(config == null ? void 0 : config.session) || (config == null ? void 0 : config.pluginSession) || ((_a = config == null ? void 0 : config.options) == null ? void 0 : _a.pluginSession) || ((_b = config == null ? void 0 : config.context) == null ? void 0 : _b.pluginSession) || null
|
|
25
|
+
);
|
|
20
26
|
}
|
|
21
|
-
//
|
|
22
|
-
|
|
27
|
+
// Use BaseService.init/_request/_requireReady implementations
|
|
28
|
+
// ==================== AUTH METHODS ====================
|
|
29
|
+
async register(userData, options = {}) {
|
|
23
30
|
try {
|
|
24
|
-
const {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
const { payload, session } = this._preparePluginPayload(
|
|
32
|
+
{ ...userData || {} },
|
|
33
|
+
options.session
|
|
34
|
+
);
|
|
35
|
+
const response = await this._request("/auth/register", {
|
|
36
|
+
method: "POST",
|
|
37
|
+
body: JSON.stringify(payload),
|
|
38
|
+
methodName: "register"
|
|
39
|
+
});
|
|
40
|
+
if (response.success) {
|
|
41
|
+
if (session) {
|
|
42
|
+
this._clearPluginSession(session);
|
|
30
43
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
return response.data;
|
|
45
|
+
}
|
|
46
|
+
throw new Error(response.message);
|
|
34
47
|
} catch (error) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
_requiresInit(methodName) {
|
|
40
|
-
const noInitMethods = /* @__PURE__ */ new Set([
|
|
41
|
-
"users:login",
|
|
42
|
-
"users:register",
|
|
43
|
-
"users:request-password-reset",
|
|
44
|
-
"users:reset-password",
|
|
45
|
-
"users:reset-password-confirm",
|
|
46
|
-
"users:register-confirmation",
|
|
47
|
-
"users:google-auth",
|
|
48
|
-
"users:github-auth"
|
|
49
|
-
]);
|
|
50
|
-
return !noInitMethods.has(methodName);
|
|
48
|
+
throw new Error(`Registration failed: ${error.message}`, { cause: error });
|
|
49
|
+
}
|
|
51
50
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
async login(email, password, options = {}) {
|
|
52
|
+
var _a;
|
|
53
|
+
try {
|
|
54
|
+
const { payload, session } = this._preparePluginPayload(
|
|
55
|
+
{
|
|
56
|
+
email,
|
|
57
|
+
password
|
|
58
|
+
},
|
|
59
|
+
options.session
|
|
60
|
+
);
|
|
61
|
+
const response = await this._request("/auth/login", {
|
|
62
|
+
method: "POST",
|
|
63
|
+
body: JSON.stringify(payload),
|
|
64
|
+
methodName: "login"
|
|
65
|
+
});
|
|
66
|
+
if (response.success && response.data && response.data.tokens) {
|
|
67
|
+
const { tokens } = response.data;
|
|
68
|
+
const tokenData = {
|
|
69
|
+
access_token: tokens.accessToken,
|
|
70
|
+
refresh_token: tokens.refreshToken,
|
|
71
|
+
expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
|
|
72
|
+
token_type: "Bearer"
|
|
73
|
+
};
|
|
74
|
+
if (this._tokenManager) {
|
|
75
|
+
this._tokenManager.setTokens(tokenData);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (response.success) {
|
|
79
|
+
if (session) {
|
|
80
|
+
this._clearPluginSession(session);
|
|
81
|
+
}
|
|
82
|
+
return response.data;
|
|
83
|
+
}
|
|
84
|
+
throw new Error(response.message);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
throw new Error(`Login failed: ${error.message}`, { cause: error });
|
|
55
87
|
}
|
|
56
88
|
}
|
|
57
|
-
|
|
89
|
+
async logout() {
|
|
90
|
+
this._requireReady("logout");
|
|
91
|
+
try {
|
|
92
|
+
await this._request("/auth/logout", {
|
|
93
|
+
method: "POST",
|
|
94
|
+
methodName: "logout"
|
|
95
|
+
});
|
|
96
|
+
if (this._tokenManager) {
|
|
97
|
+
this._tokenManager.clearTokens();
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
if (this._tokenManager) {
|
|
101
|
+
this._tokenManager.clearTokens();
|
|
102
|
+
}
|
|
103
|
+
throw new Error(`Logout failed: ${error.message}`, { cause: error });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async refreshToken(refreshToken) {
|
|
107
|
+
try {
|
|
108
|
+
const response = await this._request("/auth/refresh", {
|
|
109
|
+
method: "POST",
|
|
110
|
+
body: JSON.stringify({ refreshToken }),
|
|
111
|
+
methodName: "refreshToken"
|
|
112
|
+
});
|
|
113
|
+
if (response.success) {
|
|
114
|
+
return response.data;
|
|
115
|
+
}
|
|
116
|
+
throw new Error(response.message);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
throw new Error(`Token refresh failed: ${error.message}`, { cause: error });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async googleAuth(idToken, inviteToken = null, options = {}) {
|
|
58
122
|
var _a;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
123
|
+
try {
|
|
124
|
+
const { payload, session } = this._preparePluginPayload({ idToken }, options.session);
|
|
125
|
+
if (inviteToken) {
|
|
126
|
+
payload.inviteToken = inviteToken;
|
|
127
|
+
}
|
|
128
|
+
const response = await this._request("/auth/google", {
|
|
129
|
+
method: "POST",
|
|
130
|
+
body: JSON.stringify(payload),
|
|
131
|
+
methodName: "googleAuth"
|
|
132
|
+
});
|
|
133
|
+
if (response.success && response.data && response.data.tokens) {
|
|
134
|
+
const { tokens } = response.data;
|
|
135
|
+
const tokenData = {
|
|
136
|
+
access_token: tokens.accessToken,
|
|
137
|
+
refresh_token: tokens.refreshToken,
|
|
138
|
+
expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
|
|
139
|
+
token_type: "Bearer"
|
|
140
|
+
};
|
|
141
|
+
if (this._tokenManager) {
|
|
142
|
+
this._tokenManager.setTokens(tokenData);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (response.success) {
|
|
146
|
+
if (session) {
|
|
147
|
+
this._clearPluginSession(session);
|
|
148
|
+
}
|
|
149
|
+
return response.data;
|
|
150
|
+
}
|
|
151
|
+
throw new Error(response.message);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
throw new Error(`Google auth failed: ${error.message}`, { cause: error });
|
|
62
154
|
}
|
|
63
|
-
return based._client;
|
|
64
155
|
}
|
|
65
|
-
async
|
|
156
|
+
async githubAuth(code, inviteToken = null, options = {}) {
|
|
157
|
+
var _a;
|
|
66
158
|
try {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
projectRoles: response.projectRoles,
|
|
76
|
-
globalRole: response.globalRole,
|
|
77
|
-
persistent: true
|
|
159
|
+
const { payload, session } = this._preparePluginPayload({ code }, options.session);
|
|
160
|
+
if (inviteToken) {
|
|
161
|
+
payload.inviteToken = inviteToken;
|
|
162
|
+
}
|
|
163
|
+
const response = await this._request("/auth/github", {
|
|
164
|
+
method: "POST",
|
|
165
|
+
body: JSON.stringify(payload),
|
|
166
|
+
methodName: "githubAuth"
|
|
78
167
|
});
|
|
79
|
-
|
|
168
|
+
if (response.success && response.data && response.data.tokens) {
|
|
169
|
+
const { tokens } = response.data;
|
|
170
|
+
const tokenData = {
|
|
171
|
+
access_token: tokens.accessToken,
|
|
172
|
+
refresh_token: tokens.refreshToken,
|
|
173
|
+
expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
|
|
174
|
+
token_type: "Bearer"
|
|
175
|
+
};
|
|
176
|
+
if (this._tokenManager) {
|
|
177
|
+
this._tokenManager.setTokens(tokenData);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (response.success) {
|
|
181
|
+
if (session) {
|
|
182
|
+
this._clearPluginSession(session);
|
|
183
|
+
}
|
|
184
|
+
return response.data;
|
|
185
|
+
}
|
|
186
|
+
throw new Error(response.message);
|
|
80
187
|
} catch (error) {
|
|
81
|
-
throw new Error(`
|
|
188
|
+
throw new Error(`GitHub auth failed: ${error.message}`, { cause: error });
|
|
82
189
|
}
|
|
83
190
|
}
|
|
84
|
-
async
|
|
191
|
+
async googleAuthCallback(code, redirectUri, inviteToken = null, options = {}) {
|
|
192
|
+
var _a;
|
|
85
193
|
try {
|
|
86
|
-
const
|
|
87
|
-
|
|
194
|
+
const { payload: body, session } = this._preparePluginPayload(
|
|
195
|
+
{ code, redirectUri },
|
|
196
|
+
options.session
|
|
197
|
+
);
|
|
198
|
+
if (inviteToken) {
|
|
199
|
+
body.inviteToken = inviteToken;
|
|
200
|
+
}
|
|
201
|
+
const response = await this._request("/auth/google/callback", {
|
|
202
|
+
method: "POST",
|
|
203
|
+
body: JSON.stringify(body),
|
|
204
|
+
methodName: "googleAuthCallback"
|
|
205
|
+
});
|
|
206
|
+
if (response.success && response.data && response.data.tokens) {
|
|
207
|
+
const { tokens } = response.data;
|
|
208
|
+
const tokenData = {
|
|
209
|
+
access_token: tokens.accessToken,
|
|
210
|
+
refresh_token: tokens.refreshToken,
|
|
211
|
+
expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
|
|
212
|
+
token_type: "Bearer"
|
|
213
|
+
};
|
|
214
|
+
if (this._tokenManager) {
|
|
215
|
+
this._tokenManager.setTokens(tokenData);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (response.success) {
|
|
219
|
+
if (session) {
|
|
220
|
+
this._clearPluginSession(session);
|
|
221
|
+
}
|
|
222
|
+
return response.data;
|
|
223
|
+
}
|
|
224
|
+
throw new Error(response.message);
|
|
88
225
|
} catch (error) {
|
|
89
|
-
throw new Error(`
|
|
226
|
+
throw new Error(`Google auth callback failed: ${error.message}`, { cause: error });
|
|
90
227
|
}
|
|
91
228
|
}
|
|
92
|
-
async
|
|
229
|
+
async requestPasswordReset(email) {
|
|
93
230
|
try {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
based.setAuthState({
|
|
100
|
-
token: response.token,
|
|
101
|
-
userId: response.userId,
|
|
102
|
-
persistent: true
|
|
231
|
+
const response = await this._request("/auth/request-password-reset", {
|
|
232
|
+
method: "POST",
|
|
233
|
+
body: JSON.stringify({ email }),
|
|
234
|
+
methodName: "requestPasswordReset"
|
|
103
235
|
});
|
|
104
|
-
|
|
236
|
+
if (response.success) {
|
|
237
|
+
return response.data;
|
|
238
|
+
}
|
|
239
|
+
throw new Error(response.message);
|
|
105
240
|
} catch (error) {
|
|
106
|
-
throw new Error(`
|
|
241
|
+
throw new Error(`Password reset request failed: ${error.message}`, { cause: error });
|
|
107
242
|
}
|
|
108
243
|
}
|
|
109
|
-
async
|
|
244
|
+
async confirmPasswordReset(token, password) {
|
|
110
245
|
try {
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
246
|
+
const response = await this._request("/auth/reset-password-confirm", {
|
|
247
|
+
method: "POST",
|
|
248
|
+
body: JSON.stringify({ token, password }),
|
|
249
|
+
methodName: "confirmPasswordReset"
|
|
115
250
|
});
|
|
116
|
-
if (
|
|
117
|
-
|
|
251
|
+
if (response.success) {
|
|
252
|
+
return response.data;
|
|
118
253
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
254
|
+
throw new Error(response.message);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
throw new Error(`Password reset confirmation failed: ${error.message}`, { cause: error });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
async confirmRegistration(token) {
|
|
260
|
+
try {
|
|
261
|
+
const response = await this._request("/auth/register-confirmation", {
|
|
262
|
+
method: "POST",
|
|
263
|
+
body: JSON.stringify({ token }),
|
|
264
|
+
methodName: "confirmRegistration"
|
|
123
265
|
});
|
|
124
|
-
|
|
266
|
+
if (response.success) {
|
|
267
|
+
return response.data;
|
|
268
|
+
}
|
|
269
|
+
throw new Error(response.message);
|
|
125
270
|
} catch (error) {
|
|
126
|
-
throw new Error(`
|
|
271
|
+
throw new Error(`Registration confirmation failed: ${error.message}`, { cause: error });
|
|
127
272
|
}
|
|
128
273
|
}
|
|
129
|
-
async
|
|
274
|
+
async requestPasswordChange() {
|
|
275
|
+
this._requireReady("requestPasswordChange");
|
|
130
276
|
try {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
this.updateContext({ authToken: response.token });
|
|
135
|
-
}
|
|
136
|
-
based.setAuthState({
|
|
137
|
-
token: response.token,
|
|
138
|
-
userId: response.userId,
|
|
139
|
-
persistent: true
|
|
277
|
+
const response = await this._request("/auth/request-password-change", {
|
|
278
|
+
method: "POST",
|
|
279
|
+
methodName: "requestPasswordChange"
|
|
140
280
|
});
|
|
141
|
-
|
|
281
|
+
if (response.success) {
|
|
282
|
+
return response.data;
|
|
283
|
+
}
|
|
284
|
+
throw new Error(response.message);
|
|
142
285
|
} catch (error) {
|
|
143
|
-
throw new Error(`
|
|
286
|
+
throw new Error(`Password change request failed: ${error.message}`, { cause: error });
|
|
144
287
|
}
|
|
145
288
|
}
|
|
146
|
-
async
|
|
147
|
-
this._requireReady("
|
|
289
|
+
async confirmPasswordChange(currentPassword, newPassword, code) {
|
|
290
|
+
this._requireReady("confirmPasswordChange");
|
|
148
291
|
try {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
292
|
+
const response = await this._request("/auth/confirm-password-change", {
|
|
293
|
+
method: "POST",
|
|
294
|
+
body: JSON.stringify({ currentPassword, newPassword, code }),
|
|
295
|
+
methodName: "confirmPasswordChange"
|
|
296
|
+
});
|
|
297
|
+
if (response.success) {
|
|
298
|
+
return response.data;
|
|
299
|
+
}
|
|
300
|
+
throw new Error(response.message);
|
|
152
301
|
} catch (error) {
|
|
153
|
-
throw new Error(`
|
|
302
|
+
throw new Error(`Password change confirmation failed: ${error.message}`, { cause: error });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
async getMe(options = {}) {
|
|
306
|
+
this._requireReady("getMe");
|
|
307
|
+
try {
|
|
308
|
+
const session = this._resolvePluginSession(options.session);
|
|
309
|
+
const endpoint = session ? `/auth/me?session=${encodeURIComponent(session)}` : "/auth/me";
|
|
310
|
+
const response = await this._request(endpoint, {
|
|
311
|
+
method: "GET",
|
|
312
|
+
methodName: "getMe"
|
|
313
|
+
});
|
|
314
|
+
if (response.success) {
|
|
315
|
+
return response.data;
|
|
316
|
+
}
|
|
317
|
+
throw new Error(response.message);
|
|
318
|
+
} catch (error) {
|
|
319
|
+
throw new Error(`Failed to get user profile: ${error.message}`, { cause: error });
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
getAuthToken() {
|
|
323
|
+
if (!this._tokenManager) {
|
|
324
|
+
return null;
|
|
154
325
|
}
|
|
326
|
+
return this._tokenManager.getAccessToken();
|
|
155
327
|
}
|
|
156
|
-
|
|
157
|
-
|
|
328
|
+
/**
|
|
329
|
+
* Get stored authentication state (backward compatibility method)
|
|
330
|
+
* Replaces AuthService.getStoredAuthState()
|
|
331
|
+
*/
|
|
332
|
+
async getStoredAuthState() {
|
|
333
|
+
try {
|
|
334
|
+
if (!this._tokenManager) {
|
|
335
|
+
return {
|
|
336
|
+
userId: false,
|
|
337
|
+
authToken: false
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
const tokenStatus = this._tokenManager.getTokenStatus();
|
|
341
|
+
if (!tokenStatus.hasTokens) {
|
|
342
|
+
return {
|
|
343
|
+
userId: false,
|
|
344
|
+
authToken: false
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
if (!tokenStatus.isValid && tokenStatus.hasRefreshToken) {
|
|
348
|
+
try {
|
|
349
|
+
await this._tokenManager.ensureValidToken();
|
|
350
|
+
} catch (error) {
|
|
351
|
+
console.warn("[AuthService] Token refresh failed:", error.message);
|
|
352
|
+
if (error.message.includes("401") || error.message.includes("403") || error.message.includes("invalid") || error.message.includes("expired")) {
|
|
353
|
+
this._tokenManager.clearTokens();
|
|
354
|
+
return {
|
|
355
|
+
userId: false,
|
|
356
|
+
authToken: false,
|
|
357
|
+
error: `Authentication failed: ${error.message}`
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
return {
|
|
361
|
+
userId: false,
|
|
362
|
+
authToken: this._tokenManager.getAccessToken(),
|
|
363
|
+
error: `Network error during token refresh: ${error.message}`,
|
|
364
|
+
hasTokens: true
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const currentAccessToken = this._tokenManager.getAccessToken();
|
|
369
|
+
if (!currentAccessToken) {
|
|
370
|
+
return {
|
|
371
|
+
userId: false,
|
|
372
|
+
authToken: false
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
const currentUser = await this.getMe();
|
|
377
|
+
return {
|
|
378
|
+
userId: currentUser.user.id,
|
|
379
|
+
authToken: currentAccessToken,
|
|
380
|
+
...currentUser,
|
|
381
|
+
error: null
|
|
382
|
+
};
|
|
383
|
+
} catch (error) {
|
|
384
|
+
console.warn("[AuthService] Failed to get user data:", error.message);
|
|
385
|
+
if (error.message.includes("401") || error.message.includes("403")) {
|
|
386
|
+
this._tokenManager.clearTokens();
|
|
387
|
+
return {
|
|
388
|
+
userId: false,
|
|
389
|
+
authToken: false,
|
|
390
|
+
error: `Authentication failed: ${error.message}`
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
userId: false,
|
|
395
|
+
authToken: currentAccessToken,
|
|
396
|
+
error: `Failed to get user data: ${error.message}`,
|
|
397
|
+
hasTokens: true
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
} catch (error) {
|
|
401
|
+
console.error(
|
|
402
|
+
"[AuthService] Unexpected error in getStoredAuthState:",
|
|
403
|
+
error
|
|
404
|
+
);
|
|
405
|
+
return {
|
|
406
|
+
userId: false,
|
|
407
|
+
authToken: false,
|
|
408
|
+
error: `Failed to get stored auth state: ${error.message}`
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// ==================== USER METHODS ====================
|
|
413
|
+
async getUserProfile() {
|
|
414
|
+
this._requireReady("getUserProfile");
|
|
415
|
+
try {
|
|
416
|
+
const response = await this._request("/users/profile", {
|
|
417
|
+
method: "GET",
|
|
418
|
+
methodName: "getUserProfile"
|
|
419
|
+
});
|
|
420
|
+
if (response.success) {
|
|
421
|
+
return response.data;
|
|
422
|
+
}
|
|
423
|
+
throw new Error(response.message);
|
|
424
|
+
} catch (error) {
|
|
425
|
+
throw new Error(`Failed to get user profile: ${error.message}`, { cause: error });
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
async updateUserProfile(profileData) {
|
|
429
|
+
this._requireReady("updateUserProfile");
|
|
430
|
+
try {
|
|
431
|
+
const response = await this._request("/users/profile", {
|
|
432
|
+
method: "PATCH",
|
|
433
|
+
body: JSON.stringify(profileData),
|
|
434
|
+
methodName: "updateUserProfile"
|
|
435
|
+
});
|
|
436
|
+
if (response.success) {
|
|
437
|
+
return response.data;
|
|
438
|
+
}
|
|
439
|
+
throw new Error(response.message);
|
|
440
|
+
} catch (error) {
|
|
441
|
+
throw new Error(`Failed to update user profile: ${error.message}`, { cause: error });
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
async getUserProjects() {
|
|
445
|
+
this._requireReady("getUserProjects");
|
|
446
|
+
try {
|
|
447
|
+
const response = await this._request("/users/projects", {
|
|
448
|
+
method: "GET",
|
|
449
|
+
methodName: "getUserProjects"
|
|
450
|
+
});
|
|
451
|
+
if (response.success) {
|
|
452
|
+
return response.data.map((project) => ({
|
|
453
|
+
...project,
|
|
454
|
+
...project.icon && {
|
|
455
|
+
icon: {
|
|
456
|
+
src: `${this._apiUrl}/core/files/public/${project.icon.id}/download`,
|
|
457
|
+
...project.icon
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}));
|
|
461
|
+
}
|
|
462
|
+
throw new Error(response.message);
|
|
463
|
+
} catch (error) {
|
|
464
|
+
throw new Error(`Failed to get user projects: ${error.message}`, { cause: error });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
async getUser(userId) {
|
|
468
|
+
this._requireReady("getUser");
|
|
158
469
|
if (!userId) {
|
|
159
470
|
throw new Error("User ID is required");
|
|
160
471
|
}
|
|
161
|
-
|
|
162
|
-
|
|
472
|
+
try {
|
|
473
|
+
const response = await this._request(`/users/${userId}`, {
|
|
474
|
+
method: "GET",
|
|
475
|
+
methodName: "getUser"
|
|
476
|
+
});
|
|
477
|
+
if (response.success) {
|
|
478
|
+
return response.data;
|
|
479
|
+
}
|
|
480
|
+
throw new Error(response.message);
|
|
481
|
+
} catch (error) {
|
|
482
|
+
throw new Error(`Failed to get user: ${error.message}`, { cause: error });
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
async getUserByEmail(email) {
|
|
486
|
+
this._requireReady("getUserByEmail");
|
|
487
|
+
if (!email) {
|
|
488
|
+
throw new Error("Email is required");
|
|
163
489
|
}
|
|
164
490
|
try {
|
|
165
|
-
const
|
|
166
|
-
|
|
491
|
+
const response = await this._request(`/auth/user?email=${email}`, {
|
|
492
|
+
method: "GET",
|
|
493
|
+
methodName: "getUserByEmail"
|
|
494
|
+
});
|
|
495
|
+
if (response.success) {
|
|
496
|
+
return response.data.user;
|
|
497
|
+
}
|
|
498
|
+
throw new Error(response.message);
|
|
167
499
|
} catch (error) {
|
|
168
|
-
throw new Error(`Failed to
|
|
500
|
+
throw new Error(`Failed to get user by email: ${error.message}`, { cause: error });
|
|
169
501
|
}
|
|
170
502
|
}
|
|
171
|
-
|
|
172
|
-
|
|
503
|
+
// ==================== PROJECT ROLE METHODS ====================
|
|
504
|
+
/**
|
|
505
|
+
* Get the current user's role for a specific project by project ID
|
|
506
|
+
* Uses caching to avoid repeated API calls
|
|
507
|
+
*/
|
|
508
|
+
async getMyProjectRole(projectId) {
|
|
509
|
+
this._requireReady("getMyProjectRole");
|
|
173
510
|
if (!projectId) {
|
|
174
511
|
throw new Error("Project ID is required");
|
|
175
512
|
}
|
|
176
|
-
if (!this.
|
|
177
|
-
|
|
513
|
+
if (!this.hasValidTokens()) {
|
|
514
|
+
return "guest";
|
|
515
|
+
}
|
|
516
|
+
const cacheKey = `role_${projectId}`;
|
|
517
|
+
const cached = this._projectRoleCache.get(cacheKey);
|
|
518
|
+
if (cached && Date.now() - cached.timestamp < this._roleCacheExpiry) {
|
|
519
|
+
return cached.role;
|
|
520
|
+
}
|
|
521
|
+
try {
|
|
522
|
+
const response = await this._request(`/projects/${projectId}/role`, {
|
|
523
|
+
method: "GET",
|
|
524
|
+
methodName: "getMyProjectRole"
|
|
525
|
+
});
|
|
526
|
+
if (response.success) {
|
|
527
|
+
const { role } = response.data;
|
|
528
|
+
this._projectRoleCache.set(cacheKey, {
|
|
529
|
+
role,
|
|
530
|
+
timestamp: Date.now()
|
|
531
|
+
});
|
|
532
|
+
return role;
|
|
533
|
+
}
|
|
534
|
+
throw new Error(response.message);
|
|
535
|
+
} catch (error) {
|
|
536
|
+
const message = (error == null ? void 0 : error.message) || "";
|
|
537
|
+
if (/401|403|unauthorized|no token|invalid token/iu.test(message)) {
|
|
538
|
+
return "guest";
|
|
539
|
+
}
|
|
540
|
+
throw new Error(`Failed to get project role: ${message}`, { cause: error });
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Get the current user's role for a specific project by project key
|
|
545
|
+
* Uses caching to avoid repeated API calls
|
|
546
|
+
*/
|
|
547
|
+
async getMyProjectRoleByKey(projectKey) {
|
|
548
|
+
this._requireReady("getMyProjectRoleByKey");
|
|
549
|
+
if (!projectKey) {
|
|
550
|
+
throw new Error("Project key is required");
|
|
551
|
+
}
|
|
552
|
+
if (!this.hasValidTokens()) {
|
|
553
|
+
return "guest";
|
|
554
|
+
}
|
|
555
|
+
const cacheKey = `role_key_${projectKey}`;
|
|
556
|
+
const cached = this._projectRoleCache.get(cacheKey);
|
|
557
|
+
if (cached && Date.now() - cached.timestamp < this._roleCacheExpiry) {
|
|
558
|
+
return cached.role;
|
|
178
559
|
}
|
|
179
560
|
try {
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
tier: newTier
|
|
561
|
+
const response = await this._request(`/projects/key/${projectKey}/role`, {
|
|
562
|
+
method: "GET",
|
|
563
|
+
methodName: "getMyProjectRoleByKey"
|
|
184
564
|
});
|
|
565
|
+
if (response.success) {
|
|
566
|
+
const { role } = response.data;
|
|
567
|
+
this._projectRoleCache.set(cacheKey, {
|
|
568
|
+
role,
|
|
569
|
+
timestamp: Date.now()
|
|
570
|
+
});
|
|
571
|
+
return role;
|
|
572
|
+
}
|
|
573
|
+
throw new Error(response.message);
|
|
574
|
+
} catch (error) {
|
|
575
|
+
const message = (error == null ? void 0 : error.message) || "";
|
|
576
|
+
if (/401|403|unauthorized|no token|invalid token/iu.test(message)) {
|
|
577
|
+
return "guest";
|
|
578
|
+
}
|
|
579
|
+
throw new Error(`Failed to get project role by key: ${message}`, { cause: error });
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Clear the project role cache for a specific project or all projects
|
|
584
|
+
*/
|
|
585
|
+
clearProjectRoleCache(projectId = null) {
|
|
586
|
+
if (projectId) {
|
|
587
|
+
this._projectRoleCache.delete(`role_${projectId}`);
|
|
588
|
+
for (const [key] of this._projectRoleCache) {
|
|
589
|
+
if (key.startsWith("role_key_")) {
|
|
590
|
+
this._projectRoleCache.delete(key);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
} else {
|
|
594
|
+
this._projectRoleCache.clear();
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Get project role with fallback to user projects list
|
|
599
|
+
* This method tries to get the role from user projects first,
|
|
600
|
+
* then falls back to API call if not found
|
|
601
|
+
*/
|
|
602
|
+
async getProjectRoleWithFallback(projectId, userProjects = null) {
|
|
603
|
+
this._requireReady("getProjectRoleWithFallback");
|
|
604
|
+
if (!projectId) {
|
|
605
|
+
throw new Error("Project ID is required");
|
|
606
|
+
}
|
|
607
|
+
if (userProjects && Array.isArray(userProjects)) {
|
|
608
|
+
const userProject = userProjects.find((p) => p.id === projectId);
|
|
609
|
+
if (userProject && userProject.role) {
|
|
610
|
+
return userProject.role;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return await this.getMyProjectRole(projectId);
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Get project role with fallback to user projects list (by project key)
|
|
617
|
+
* This method tries to get the role from user projects first,
|
|
618
|
+
* then falls back to API call if not found
|
|
619
|
+
*/
|
|
620
|
+
async getProjectRoleByKeyWithFallback(projectKey, userProjects = null) {
|
|
621
|
+
this._requireReady("getProjectRoleByKeyWithFallback");
|
|
622
|
+
if (!projectKey) {
|
|
623
|
+
throw new Error("Project key is required");
|
|
624
|
+
}
|
|
625
|
+
if (userProjects && Array.isArray(userProjects)) {
|
|
626
|
+
const userProject = userProjects.find((p) => p.key === projectKey);
|
|
627
|
+
if (userProject && userProject.role) {
|
|
628
|
+
return userProject.role;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return await this.getMyProjectRoleByKey(projectKey);
|
|
632
|
+
}
|
|
633
|
+
// ==================== AUTH HELPER METHODS ====================
|
|
634
|
+
/**
|
|
635
|
+
* Debug method to check token status
|
|
636
|
+
*/
|
|
637
|
+
getTokenDebugInfo() {
|
|
638
|
+
if (!this._tokenManager) {
|
|
639
|
+
return {
|
|
640
|
+
tokenManagerExists: false,
|
|
641
|
+
error: "TokenManager not initialized"
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
const tokenStatus = this._tokenManager.getTokenStatus();
|
|
645
|
+
const { tokens } = this._tokenManager;
|
|
646
|
+
return {
|
|
647
|
+
tokenManagerExists: true,
|
|
648
|
+
tokenStatus,
|
|
649
|
+
hasAccessToken: Boolean(tokens.accessToken),
|
|
650
|
+
hasRefreshToken: Boolean(tokens.refreshToken),
|
|
651
|
+
accessTokenPreview: tokens.accessToken ? `${tokens.accessToken.substring(0, 20)}...` : null,
|
|
652
|
+
expiresAt: tokens.expiresAt,
|
|
653
|
+
timeToExpiry: tokenStatus.timeToExpiry,
|
|
654
|
+
authHeader: this._tokenManager.getAuthHeader()
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Helper method to check if user is authenticated
|
|
659
|
+
*/
|
|
660
|
+
isAuthenticated() {
|
|
661
|
+
if (!this._tokenManager) {
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
return this._tokenManager.hasTokens();
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Helper method to check if user has valid tokens
|
|
668
|
+
*/
|
|
669
|
+
hasValidTokens() {
|
|
670
|
+
if (!this._tokenManager) {
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
return this._tokenManager.hasTokens() && this._tokenManager.isAccessTokenValid();
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Helper method to get current user info
|
|
677
|
+
*/
|
|
678
|
+
async getCurrentUser() {
|
|
679
|
+
try {
|
|
680
|
+
return await this.getMe();
|
|
185
681
|
} catch (error) {
|
|
186
|
-
throw new Error(`Failed to
|
|
682
|
+
throw new Error(`Failed to get current user: ${error.message}`, { cause: error });
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Helper method to validate user data for registration
|
|
687
|
+
*/
|
|
688
|
+
validateRegistrationData(userData) {
|
|
689
|
+
const errors = [];
|
|
690
|
+
if (!userData.email || typeof userData.email !== "string") {
|
|
691
|
+
errors.push("Email is required and must be a string");
|
|
692
|
+
} else if (!this._isValidEmail(userData.email)) {
|
|
693
|
+
errors.push("Email must be a valid email address");
|
|
694
|
+
}
|
|
695
|
+
if (!userData.password || typeof userData.password !== "string") {
|
|
696
|
+
errors.push("Password is required and must be a string");
|
|
697
|
+
} else if (userData.password.length < 8) {
|
|
698
|
+
errors.push("Password must be at least 8 characters long");
|
|
699
|
+
}
|
|
700
|
+
if (userData.username && typeof userData.username !== "string") {
|
|
701
|
+
errors.push("Username must be a string");
|
|
702
|
+
} else if (userData.username && userData.username.length < 3) {
|
|
703
|
+
errors.push("Username must be at least 3 characters long");
|
|
704
|
+
}
|
|
705
|
+
return {
|
|
706
|
+
isValid: errors.length === 0,
|
|
707
|
+
errors
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Helper method to register with validation
|
|
712
|
+
*/
|
|
713
|
+
async registerWithValidation(userData, options = {}) {
|
|
714
|
+
const validation = this.validateRegistrationData(userData);
|
|
715
|
+
if (!validation.isValid) {
|
|
716
|
+
throw new Error(`Validation failed: ${validation.errors.join(", ")}`);
|
|
717
|
+
}
|
|
718
|
+
return await this.register(userData, options);
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Helper method to login with validation
|
|
722
|
+
*/
|
|
723
|
+
async loginWithValidation(email, password, options = {}) {
|
|
724
|
+
if (!email || typeof email !== "string") {
|
|
725
|
+
throw new Error("Email is required and must be a string");
|
|
726
|
+
}
|
|
727
|
+
if (!password || typeof password !== "string") {
|
|
728
|
+
throw new Error("Password is required and must be a string");
|
|
187
729
|
}
|
|
730
|
+
if (!this._isValidEmail(email)) {
|
|
731
|
+
throw new Error("Email must be a valid email address");
|
|
732
|
+
}
|
|
733
|
+
return await this.login(email, password, options);
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Private helper to validate email format
|
|
737
|
+
*/
|
|
738
|
+
_isValidEmail(email) {
|
|
739
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u;
|
|
740
|
+
return emailRegex.test(email);
|
|
188
741
|
}
|
|
742
|
+
// ==================== PERMISSION METHODS (Existing) ====================
|
|
189
743
|
hasPermission(requiredPermission) {
|
|
190
744
|
var _a;
|
|
191
745
|
const authState = (_a = this._context) == null ? void 0 : _a.state;
|
|
@@ -234,23 +788,17 @@ class AuthService extends BaseService {
|
|
|
234
788
|
if (!operationConfig) {
|
|
235
789
|
return false;
|
|
236
790
|
}
|
|
237
|
-
if (!operationConfig) {
|
|
238
|
-
return false;
|
|
239
|
-
}
|
|
240
791
|
const { permissions = [], features = [] } = operationConfig;
|
|
241
792
|
try {
|
|
242
793
|
const permissionResults = await Promise.all(
|
|
243
794
|
permissions.map(
|
|
244
|
-
(permission) => this.
|
|
795
|
+
(permission) => this.checkProjectPermission(projectId, permission)
|
|
245
796
|
)
|
|
246
797
|
);
|
|
247
798
|
const hasPermissions = requireAll ? permissionResults.every(Boolean) : permissionResults.some(Boolean);
|
|
248
799
|
if (!hasPermissions) {
|
|
249
800
|
return false;
|
|
250
801
|
}
|
|
251
|
-
if (!hasPermissions) {
|
|
252
|
-
return false;
|
|
253
|
-
}
|
|
254
802
|
if (checkFeatures && features.length > 0) {
|
|
255
803
|
const featureResults = features.map((feature) => {
|
|
256
804
|
const result = this.hasProjectFeature(projectId, feature);
|
|
@@ -260,9 +808,6 @@ class AuthService extends BaseService {
|
|
|
260
808
|
if (!hasFeatures) {
|
|
261
809
|
return false;
|
|
262
810
|
}
|
|
263
|
-
if (!hasFeatures) {
|
|
264
|
-
return false;
|
|
265
|
-
}
|
|
266
811
|
}
|
|
267
812
|
return true;
|
|
268
813
|
} catch (error) {
|
|
@@ -284,205 +829,92 @@ class AuthService extends BaseService {
|
|
|
284
829
|
}
|
|
285
830
|
return action();
|
|
286
831
|
}
|
|
287
|
-
//
|
|
288
|
-
|
|
289
|
-
this.
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
operations.map(async (operation) => {
|
|
296
|
-
const allowed = await this.canPerformOperation(projectId, operation);
|
|
297
|
-
const config = PERMISSION_MAP[operation];
|
|
298
|
-
return {
|
|
299
|
-
operation,
|
|
300
|
-
allowed,
|
|
301
|
-
permissions: config.permissions,
|
|
302
|
-
features: config.features,
|
|
303
|
-
aiTokens: operation.startsWith("ai") ? this._getAITokens(projectId, operation.replace("ai", "")) : null
|
|
304
|
-
};
|
|
305
|
-
})
|
|
306
|
-
);
|
|
307
|
-
return {
|
|
308
|
-
projectId,
|
|
309
|
-
permissions: access.reduce(
|
|
310
|
-
(acc, { operation, ...details }) => ({
|
|
311
|
-
...acc,
|
|
312
|
-
[operation]: details
|
|
313
|
-
}),
|
|
314
|
-
{}
|
|
315
|
-
),
|
|
316
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
317
|
-
};
|
|
832
|
+
// Cleanup
|
|
833
|
+
destroy() {
|
|
834
|
+
if (this._tokenManager) {
|
|
835
|
+
this._tokenManager.destroy();
|
|
836
|
+
this._tokenManager = null;
|
|
837
|
+
}
|
|
838
|
+
this._projectRoleCache.clear();
|
|
839
|
+
this._setReady(false);
|
|
318
840
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
return
|
|
327
|
-
const tokens = this.hasProjectFeature(projectId, feature);
|
|
328
|
-
return total + (typeof tokens === "number" ? tokens : 0);
|
|
329
|
-
}, 0);
|
|
330
|
-
}
|
|
331
|
-
async getProjectMembers(projectId) {
|
|
332
|
-
var _a;
|
|
333
|
-
this._requireReady("getProjectMembers");
|
|
334
|
-
if (!projectId) {
|
|
335
|
-
throw new Error("Project ID is required");
|
|
336
|
-
}
|
|
337
|
-
try {
|
|
338
|
-
const based = this._getBasedService("getProjectMembers");
|
|
339
|
-
return await based.call("projects:get-members", { projectId });
|
|
340
|
-
} catch (error) {
|
|
341
|
-
if ((_a = error.message) == null ? void 0 : _a.includes("Authentication failed. Please try again"))
|
|
342
|
-
window.location.reload();
|
|
343
|
-
throw new Error(`Failed to get project members: ${error.message}`);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
async inviteMember(projectId, email, role, name, callbackUrl) {
|
|
347
|
-
this._requireReady("inviteMember");
|
|
348
|
-
if (!projectId) {
|
|
349
|
-
throw new Error("Project ID is required");
|
|
350
|
-
}
|
|
351
|
-
if (!email) {
|
|
352
|
-
throw new Error("Email is required");
|
|
353
|
-
}
|
|
354
|
-
if (!callbackUrl || Object.keys(callbackUrl).length === 0) {
|
|
355
|
-
throw new Error("Callback Url is required");
|
|
356
|
-
}
|
|
357
|
-
if (!role || !this._userRoles.has(role)) {
|
|
358
|
-
throw new Error(`Invalid role: ${role}`);
|
|
359
|
-
}
|
|
360
|
-
try {
|
|
361
|
-
const based = this._getBasedService("inviteMember");
|
|
362
|
-
return await based.call("projects:invite-member", {
|
|
363
|
-
projectId,
|
|
364
|
-
email,
|
|
365
|
-
role,
|
|
366
|
-
name,
|
|
367
|
-
callbackUrl
|
|
368
|
-
});
|
|
369
|
-
} catch (error) {
|
|
370
|
-
throw new Error(`Failed to invite member: ${error.message}`);
|
|
371
|
-
}
|
|
841
|
+
_preparePluginPayload(payload, sessionOverride = null) {
|
|
842
|
+
const target = payload && typeof payload === "object" ? { ...payload } : {};
|
|
843
|
+
const session = this._resolvePluginSession(sessionOverride);
|
|
844
|
+
if (session && !Object.hasOwn(target, "session")) {
|
|
845
|
+
target.session = session;
|
|
846
|
+
return { payload: target, session };
|
|
847
|
+
}
|
|
848
|
+
return { payload: target, session: null };
|
|
372
849
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
return await based.call("projects:accept-invite", { token });
|
|
378
|
-
} catch (error) {
|
|
379
|
-
throw new Error(`Failed to accept invite: ${error.message}`);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
async updateMemberRole(projectId, userId, role) {
|
|
383
|
-
this._requireReady("updateMemberRole");
|
|
384
|
-
if (!projectId) {
|
|
385
|
-
throw new Error("Project ID is required");
|
|
386
|
-
}
|
|
387
|
-
if (!userId) {
|
|
388
|
-
throw new Error("User ID is required");
|
|
389
|
-
}
|
|
390
|
-
if (!this._userRoles.has(role)) {
|
|
391
|
-
throw new Error(`Invalid role: ${role}`);
|
|
850
|
+
_resolvePluginSession(sessionOverride = null) {
|
|
851
|
+
var _a, _b;
|
|
852
|
+
if (sessionOverride) {
|
|
853
|
+
return this._cachePluginSession(sessionOverride);
|
|
392
854
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
return await based.call("projects:update-member-role", {
|
|
396
|
-
projectId,
|
|
397
|
-
userId,
|
|
398
|
-
role
|
|
399
|
-
});
|
|
400
|
-
} catch (error) {
|
|
401
|
-
throw new Error(`Failed to update member role: ${error.message}`);
|
|
855
|
+
if (this._pluginSession) {
|
|
856
|
+
return this._pluginSession;
|
|
402
857
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
if (!projectId || !userId) {
|
|
407
|
-
throw new Error("Project ID and user ID are required");
|
|
858
|
+
const optionSession = (_a = this._options) == null ? void 0 : _a.pluginSession;
|
|
859
|
+
if (optionSession) {
|
|
860
|
+
return this._cachePluginSession(optionSession);
|
|
408
861
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
return
|
|
412
|
-
} catch (error) {
|
|
413
|
-
throw new Error(`Failed to remove member: ${error.message}`);
|
|
862
|
+
const contextSession = (_b = this._context) == null ? void 0 : _b.pluginSession;
|
|
863
|
+
if (contextSession) {
|
|
864
|
+
return this._cachePluginSession(contextSession);
|
|
414
865
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
866
|
+
if (typeof window !== "undefined") {
|
|
867
|
+
try {
|
|
868
|
+
const sessionFromUrl = new URL(window.location.href).searchParams.get("session");
|
|
869
|
+
if (sessionFromUrl) {
|
|
870
|
+
return this._cachePluginSession(sessionFromUrl);
|
|
871
|
+
}
|
|
872
|
+
} catch {
|
|
873
|
+
}
|
|
874
|
+
try {
|
|
875
|
+
if (window.localStorage) {
|
|
876
|
+
const stored = window.localStorage.getItem(PLUGIN_SESSION_STORAGE_KEY);
|
|
877
|
+
if (stored) {
|
|
878
|
+
this._pluginSession = stored;
|
|
879
|
+
return stored;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
} catch {
|
|
883
|
+
}
|
|
422
884
|
}
|
|
885
|
+
return null;
|
|
423
886
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
887
|
+
_cachePluginSession(session) {
|
|
888
|
+
if (!session) {
|
|
889
|
+
return null;
|
|
890
|
+
}
|
|
891
|
+
this._pluginSession = session;
|
|
892
|
+
if (typeof window !== "undefined") {
|
|
893
|
+
try {
|
|
894
|
+
if (window.localStorage) {
|
|
895
|
+
window.localStorage.setItem(PLUGIN_SESSION_STORAGE_KEY, session);
|
|
896
|
+
}
|
|
897
|
+
} catch {
|
|
898
|
+
}
|
|
430
899
|
}
|
|
900
|
+
return session;
|
|
431
901
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const based = this._getBasedService("confirmPasswordReset");
|
|
435
|
-
return await based.call("users:reset-password-confirm", {
|
|
436
|
-
token,
|
|
437
|
-
newPassword
|
|
438
|
-
});
|
|
439
|
-
} catch (error) {
|
|
440
|
-
throw new Error(`Password reset confirmation failed: ${error.message}`);
|
|
441
|
-
}
|
|
902
|
+
setPluginSession(session) {
|
|
903
|
+
this._cachePluginSession(session);
|
|
442
904
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
error: null
|
|
454
|
-
};
|
|
905
|
+
_clearPluginSession(session = null) {
|
|
906
|
+
if (!session || this._pluginSession === session) {
|
|
907
|
+
this._pluginSession = null;
|
|
908
|
+
}
|
|
909
|
+
if (typeof window !== "undefined") {
|
|
910
|
+
try {
|
|
911
|
+
if (window.localStorage) {
|
|
912
|
+
window.localStorage.removeItem(PLUGIN_SESSION_STORAGE_KEY);
|
|
913
|
+
}
|
|
914
|
+
} catch {
|
|
455
915
|
}
|
|
456
|
-
return {
|
|
457
|
-
userId: false,
|
|
458
|
-
authToken: false
|
|
459
|
-
};
|
|
460
|
-
} catch (error) {
|
|
461
|
-
this._setError(error);
|
|
462
|
-
return {
|
|
463
|
-
userId: false,
|
|
464
|
-
authToken: false,
|
|
465
|
-
error: `Failed to get stored auth state: ${error.message}`
|
|
466
|
-
};
|
|
467
916
|
}
|
|
468
917
|
}
|
|
469
|
-
async subscribeToAuthChanges(callback) {
|
|
470
|
-
const based = this._getBasedService("subscribeToAuthChanges");
|
|
471
|
-
based.on("authstate-change", async (authState) => {
|
|
472
|
-
const formattedState = (authState == null ? void 0 : authState.token) ? {
|
|
473
|
-
userId: authState.userId,
|
|
474
|
-
authToken: authState.token,
|
|
475
|
-
projectRoles: authState.projectRoles,
|
|
476
|
-
globalRole: authState.globalRole,
|
|
477
|
-
error: null
|
|
478
|
-
} : {
|
|
479
|
-
userId: false,
|
|
480
|
-
authToken: false
|
|
481
|
-
};
|
|
482
|
-
await callback(formattedState);
|
|
483
|
-
});
|
|
484
|
-
return () => based.off("authstate-change");
|
|
485
|
-
}
|
|
486
918
|
}
|
|
487
919
|
export {
|
|
488
920
|
AuthService
|