@symbo.ls/sdk 3.1.2 → 3.2.3

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.
Files changed (65) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/config/environment.js +5 -21
  3. package/dist/cjs/index.js +6 -26
  4. package/dist/cjs/services/AIService.js +3 -3
  5. package/dist/cjs/services/CollabService.js +420 -0
  6. package/dist/cjs/services/CoreService.js +651 -107
  7. package/dist/cjs/services/SocketService.js +207 -59
  8. package/dist/cjs/services/index.js +5 -13
  9. package/dist/cjs/state/RootStateManager.js +86 -0
  10. package/dist/cjs/state/rootEventBus.js +65 -0
  11. package/dist/cjs/utils/CollabClient.js +157 -0
  12. package/dist/cjs/utils/TokenManager.js +62 -27
  13. package/dist/cjs/utils/jsonDiff.js +103 -0
  14. package/dist/cjs/utils/services.js +129 -88
  15. package/dist/cjs/utils/symstoryClient.js +5 -5
  16. package/dist/esm/config/environment.js +5 -21
  17. package/dist/esm/index.js +20459 -9286
  18. package/dist/esm/services/AIService.js +3 -3
  19. package/dist/esm/services/BasedService.js +5 -21
  20. package/dist/esm/services/CollabService.js +18028 -0
  21. package/dist/esm/services/CoreService.js +718 -155
  22. package/dist/esm/services/SocketService.js +323 -58
  23. package/dist/esm/services/SymstoryService.js +10 -26
  24. package/dist/esm/services/index.js +20305 -9158
  25. package/dist/esm/state/RootStateManager.js +102 -0
  26. package/dist/esm/state/rootEventBus.js +47 -0
  27. package/dist/esm/utils/CollabClient.js +17483 -0
  28. package/dist/esm/utils/TokenManager.js +62 -27
  29. package/dist/esm/utils/jsonDiff.js +6096 -0
  30. package/dist/esm/utils/services.js +129 -88
  31. package/dist/esm/utils/symstoryClient.js +10 -26
  32. package/dist/node/config/environment.js +5 -21
  33. package/dist/node/index.js +10 -34
  34. package/dist/node/services/AIService.js +3 -3
  35. package/dist/node/services/CollabService.js +401 -0
  36. package/dist/node/services/CoreService.js +651 -107
  37. package/dist/node/services/SocketService.js +197 -59
  38. package/dist/node/services/index.js +5 -13
  39. package/dist/node/state/RootStateManager.js +57 -0
  40. package/dist/node/state/rootEventBus.js +46 -0
  41. package/dist/node/utils/CollabClient.js +128 -0
  42. package/dist/node/utils/TokenManager.js +62 -27
  43. package/dist/node/utils/jsonDiff.js +74 -0
  44. package/dist/node/utils/services.js +129 -88
  45. package/dist/node/utils/symstoryClient.js +5 -5
  46. package/package.json +12 -6
  47. package/src/config/environment.js +5 -19
  48. package/src/index.js +9 -31
  49. package/src/services/AIService.js +3 -3
  50. package/src/services/BasedService.js +1 -0
  51. package/src/services/CollabService.js +491 -0
  52. package/src/services/CoreService.js +715 -110
  53. package/src/services/SocketService.js +227 -59
  54. package/src/services/index.js +6 -13
  55. package/src/state/RootStateManager.js +71 -0
  56. package/src/state/rootEventBus.js +48 -0
  57. package/src/utils/CollabClient.js +161 -0
  58. package/src/utils/TokenManager.js +68 -30
  59. package/src/utils/jsonDiff.js +109 -0
  60. package/src/utils/services.js +140 -88
  61. package/src/utils/symstoryClient.js +5 -5
  62. package/dist/cjs/services/SocketIOService.js +0 -307
  63. package/dist/esm/services/SocketIOService.js +0 -470
  64. package/dist/node/services/SocketIOService.js +0 -278
  65. package/src/services/SocketIOService.js +0 -334
@@ -6,18 +6,18 @@ class CoreService extends BaseService {
6
6
  super(config);
7
7
  this._client = null;
8
8
  this._initialized = false;
9
- this._baseUrl = null;
9
+ this._apiUrl = null;
10
10
  this._tokenManager = null;
11
11
  }
12
12
  init({ context }) {
13
13
  try {
14
14
  const { appKey, authToken } = context || this._context;
15
- this._baseUrl = environment.apiUrl || environment.baseUrl;
16
- if (!this._baseUrl) {
15
+ this._apiUrl = environment.apiUrl;
16
+ if (!this._apiUrl) {
17
17
  throw new Error("Core service base URL not configured");
18
18
  }
19
19
  this._tokenManager = getTokenManager({
20
- apiUrl: this._baseUrl,
20
+ apiUrl: this._apiUrl,
21
21
  onTokenRefresh: (tokens) => {
22
22
  this.updateContext({ authToken: tokens.accessToken });
23
23
  },
@@ -28,12 +28,12 @@ class CoreService extends BaseService {
28
28
  console.error("Token management error:", error);
29
29
  }
30
30
  });
31
- if (authToken) {
31
+ if (authToken && !this._tokenManager.hasTokens()) {
32
32
  this._tokenManager.setTokens({ access_token: authToken });
33
33
  }
34
34
  this._info = {
35
35
  config: {
36
- baseUrl: this._baseUrl,
36
+ apiUrl: this._apiUrl,
37
37
  appKey: appKey ? `${appKey.substr(0, 4)}...${appKey.substr(-4)}` : null,
38
38
  hasToken: Boolean(authToken)
39
39
  }
@@ -51,11 +51,15 @@ class CoreService extends BaseService {
51
51
  "register",
52
52
  "login",
53
53
  "googleAuth",
54
+ "googleAuthCallback",
54
55
  "githubAuth",
55
56
  "requestPasswordReset",
56
57
  "confirmPasswordReset",
57
58
  "confirmRegistration",
58
- "verifyEmail"
59
+ "verifyEmail",
60
+ "listPublicProjects",
61
+ "getPublicProject",
62
+ "getHealthStatus"
59
63
  ]);
60
64
  return !noInitMethods.has(methodName);
61
65
  }
@@ -86,24 +90,34 @@ class CoreService extends BaseService {
86
90
  authHeader: this._tokenManager.getAuthHeader()
87
91
  };
88
92
  }
93
+ // Helper method to check if user is authenticated
94
+ isAuthenticated() {
95
+ if (!this._tokenManager) {
96
+ return false;
97
+ }
98
+ return this._tokenManager.hasTokens();
99
+ }
100
+ // Helper method to check if user has valid tokens
101
+ hasValidTokens() {
102
+ if (!this._tokenManager) {
103
+ return false;
104
+ }
105
+ return this._tokenManager.hasTokens() && this._tokenManager.isAccessTokenValid();
106
+ }
89
107
  // Helper method to make HTTP requests
90
108
  async _request(endpoint, options = {}) {
91
- const url = `${this._baseUrl}/core${endpoint}`;
92
- const defaultHeaders = {
93
- "Content-Type": "application/json"
94
- };
109
+ const url = `${this._apiUrl}/core${endpoint}`;
110
+ const defaultHeaders = {};
111
+ if (!(options.body instanceof FormData)) {
112
+ defaultHeaders["Content-Type"] = "application/json";
113
+ }
95
114
  if (this._requiresInit(options.methodName) && this._tokenManager) {
96
115
  try {
97
116
  const validToken = await this._tokenManager.ensureValidToken();
98
- console.log(`[CoreService] Token check for ${options.methodName}:`, {
99
- hasValidToken: Boolean(validToken),
100
- tokenPreview: validToken ? `${validToken.substring(0, 20)}...` : null
101
- });
102
117
  if (validToken) {
103
118
  const authHeader = this._tokenManager.getAuthHeader();
104
119
  if (authHeader) {
105
120
  defaultHeaders.Authorization = authHeader;
106
- console.log(`[CoreService] Added auth header for ${options.methodName}`);
107
121
  }
108
122
  }
109
123
  } catch (error) {
@@ -113,7 +127,6 @@ class CoreService extends BaseService {
113
127
  const { authToken } = this._context;
114
128
  if (authToken) {
115
129
  defaultHeaders.Authorization = `Bearer ${authToken}`;
116
- console.log(`[CoreService] Using context token for ${options.methodName}`);
117
130
  }
118
131
  }
119
132
  try {
@@ -140,11 +153,15 @@ class CoreService extends BaseService {
140
153
  // ==================== AUTH METHODS ====================
141
154
  async register(userData) {
142
155
  try {
143
- return await this._request("/auth/register", {
156
+ const response = await this._request("/auth/register", {
144
157
  method: "POST",
145
158
  body: JSON.stringify(userData),
146
159
  methodName: "register"
147
160
  });
161
+ if (response.success) {
162
+ return response.data;
163
+ }
164
+ throw new Error(response.message);
148
165
  } catch (error) {
149
166
  throw new Error(`Registration failed: ${error.message}`);
150
167
  }
@@ -170,7 +187,10 @@ class CoreService extends BaseService {
170
187
  }
171
188
  this.updateContext({ authToken: tokens.accessToken });
172
189
  }
173
- return response;
190
+ if (response.success) {
191
+ return response.data;
192
+ }
193
+ throw new Error(response.message);
174
194
  } catch (error) {
175
195
  throw new Error(`Login failed: ${error.message}`);
176
196
  }
@@ -196,11 +216,15 @@ class CoreService extends BaseService {
196
216
  }
197
217
  async refreshToken(refreshToken) {
198
218
  try {
199
- return await this._request("/auth/refresh", {
219
+ const response = await this._request("/auth/refresh", {
200
220
  method: "POST",
201
221
  body: JSON.stringify({ refreshToken }),
202
222
  methodName: "refreshToken"
203
223
  });
224
+ if (response.success) {
225
+ return response.data;
226
+ }
227
+ throw new Error(response.message);
204
228
  } catch (error) {
205
229
  throw new Error(`Token refresh failed: ${error.message}`);
206
230
  }
@@ -226,7 +250,10 @@ class CoreService extends BaseService {
226
250
  }
227
251
  this.updateContext({ authToken: tokens.accessToken });
228
252
  }
229
- return response;
253
+ if (response.success) {
254
+ return response.data;
255
+ }
256
+ throw new Error(response.message);
230
257
  } catch (error) {
231
258
  throw new Error(`Google auth failed: ${error.message}`);
232
259
  }
@@ -252,40 +279,84 @@ class CoreService extends BaseService {
252
279
  }
253
280
  this.updateContext({ authToken: tokens.accessToken });
254
281
  }
255
- return response;
282
+ if (response.success) {
283
+ return response.data;
284
+ }
285
+ throw new Error(response.message);
256
286
  } catch (error) {
257
287
  throw new Error(`GitHub auth failed: ${error.message}`);
258
288
  }
259
289
  }
290
+ async googleAuthCallback(code, redirectUri) {
291
+ var _a;
292
+ try {
293
+ const response = await this._request("/auth/google/callback", {
294
+ method: "POST",
295
+ body: JSON.stringify({ code, redirectUri }),
296
+ methodName: "googleAuthCallback"
297
+ });
298
+ if (response.success && response.data && response.data.tokens) {
299
+ const { tokens } = response.data;
300
+ const tokenData = {
301
+ access_token: tokens.accessToken,
302
+ refresh_token: tokens.refreshToken,
303
+ expires_in: (_a = tokens.accessTokenExp) == null ? void 0 : _a.expiresIn,
304
+ token_type: "Bearer"
305
+ };
306
+ if (this._tokenManager) {
307
+ this._tokenManager.setTokens(tokenData);
308
+ }
309
+ this.updateContext({ authToken: tokens.accessToken });
310
+ }
311
+ if (response.success) {
312
+ return response.data;
313
+ }
314
+ throw new Error(response.message);
315
+ } catch (error) {
316
+ throw new Error(`Google auth callback failed: ${error.message}`);
317
+ }
318
+ }
260
319
  async requestPasswordReset(email) {
261
320
  try {
262
- return await this._request("/auth/request-password-reset", {
321
+ const response = await this._request("/auth/request-password-reset", {
263
322
  method: "POST",
264
323
  body: JSON.stringify({ email }),
265
324
  methodName: "requestPasswordReset"
266
325
  });
326
+ if (response.success) {
327
+ return response.data;
328
+ }
329
+ throw new Error(response.message);
267
330
  } catch (error) {
268
331
  throw new Error(`Password reset request failed: ${error.message}`);
269
332
  }
270
333
  }
271
334
  async confirmPasswordReset(token, password) {
272
335
  try {
273
- return await this._request("/auth/reset-password-confirm", {
336
+ const response = await this._request("/auth/reset-password-confirm", {
274
337
  method: "POST",
275
338
  body: JSON.stringify({ token, password }),
276
339
  methodName: "confirmPasswordReset"
277
340
  });
341
+ if (response.success) {
342
+ return response.data;
343
+ }
344
+ throw new Error(response.message);
278
345
  } catch (error) {
279
346
  throw new Error(`Password reset confirmation failed: ${error.message}`);
280
347
  }
281
348
  }
282
349
  async confirmRegistration(token) {
283
350
  try {
284
- return await this._request("/auth/register-confirmation", {
351
+ const response = await this._request("/auth/register-confirmation", {
285
352
  method: "POST",
286
353
  body: JSON.stringify({ token }),
287
354
  methodName: "confirmRegistration"
288
355
  });
356
+ if (response.success) {
357
+ return response.data;
358
+ }
359
+ throw new Error(response.message);
289
360
  } catch (error) {
290
361
  throw new Error(`Registration confirmation failed: ${error.message}`);
291
362
  }
@@ -293,10 +364,14 @@ class CoreService extends BaseService {
293
364
  async requestPasswordChange() {
294
365
  this._requireReady("requestPasswordChange");
295
366
  try {
296
- return await this._request("/auth/request-password-change", {
367
+ const response = await this._request("/auth/request-password-change", {
297
368
  method: "POST",
298
369
  methodName: "requestPasswordChange"
299
370
  });
371
+ if (response.success) {
372
+ return response.data;
373
+ }
374
+ throw new Error(response.message);
300
375
  } catch (error) {
301
376
  throw new Error(`Password change request failed: ${error.message}`);
302
377
  }
@@ -304,11 +379,15 @@ class CoreService extends BaseService {
304
379
  async confirmPasswordChange(currentPassword, newPassword, code) {
305
380
  this._requireReady("confirmPasswordChange");
306
381
  try {
307
- return await this._request("/auth/confirm-password-change", {
382
+ const response = await this._request("/auth/confirm-password-change", {
308
383
  method: "POST",
309
384
  body: JSON.stringify({ currentPassword, newPassword, code }),
310
385
  methodName: "confirmPasswordChange"
311
386
  });
387
+ if (response.success) {
388
+ return response.data;
389
+ }
390
+ throw new Error(response.message);
312
391
  } catch (error) {
313
392
  throw new Error(`Password change confirmation failed: ${error.message}`);
314
393
  }
@@ -316,10 +395,14 @@ class CoreService extends BaseService {
316
395
  async getMe() {
317
396
  this._requireReady("getMe");
318
397
  try {
319
- return await this._request("/auth/me", {
398
+ const response = await this._request("/auth/me", {
320
399
  method: "GET",
321
400
  methodName: "getMe"
322
401
  });
402
+ if (response.success) {
403
+ return response.data;
404
+ }
405
+ throw new Error(response.message);
323
406
  } catch (error) {
324
407
  throw new Error(`Failed to get user profile: ${error.message}`);
325
408
  }
@@ -347,35 +430,57 @@ class CoreService extends BaseService {
347
430
  try {
348
431
  await this._tokenManager.ensureValidToken();
349
432
  } catch (error) {
350
- this._tokenManager.clearTokens();
433
+ console.warn("[CoreService] Token refresh failed:", error.message);
434
+ if (error.message.includes("401") || error.message.includes("403") || error.message.includes("invalid") || error.message.includes("expired")) {
435
+ this._tokenManager.clearTokens();
436
+ return {
437
+ userId: false,
438
+ authToken: false,
439
+ error: `Authentication failed: ${error.message}`
440
+ };
441
+ }
351
442
  return {
352
443
  userId: false,
353
- authToken: false,
354
- error: `Token refresh failed: ${error.message}`
444
+ authToken: this._tokenManager.getAccessToken(),
445
+ error: `Network error during token refresh: ${error.message}`,
446
+ hasTokens: true
355
447
  };
356
448
  }
357
449
  }
450
+ const currentAccessToken = this._tokenManager.getAccessToken();
451
+ if (!currentAccessToken) {
452
+ return {
453
+ userId: false,
454
+ authToken: false
455
+ };
456
+ }
358
457
  try {
359
458
  const currentUser = await this.getMe();
360
- const userProjects = await this.getUserProjects();
361
459
  return {
362
- userId: currentUser.data.id,
363
- authToken: this._tokenManager.getAccessToken(),
364
- user: {
365
- ...currentUser.data,
366
- projects: (userProjects == null ? void 0 : userProjects.data) || []
367
- },
460
+ userId: currentUser.user.id,
461
+ authToken: currentAccessToken,
462
+ ...currentUser,
368
463
  error: null
369
464
  };
370
465
  } catch (error) {
371
- this._tokenManager.clearTokens();
466
+ console.warn("[CoreService] Failed to get user data:", error.message);
467
+ if (error.message.includes("401") || error.message.includes("403")) {
468
+ this._tokenManager.clearTokens();
469
+ return {
470
+ userId: false,
471
+ authToken: false,
472
+ error: `Authentication failed: ${error.message}`
473
+ };
474
+ }
372
475
  return {
373
476
  userId: false,
374
- authToken: false,
375
- error: `Failed to get user data: ${error.message}`
477
+ authToken: currentAccessToken,
478
+ error: `Failed to get user data: ${error.message}`,
479
+ hasTokens: true
376
480
  };
377
481
  }
378
482
  } catch (error) {
483
+ console.error("[CoreService] Unexpected error in getStoredAuthState:", error);
379
484
  return {
380
485
  userId: false,
381
486
  authToken: false,
@@ -387,10 +492,14 @@ class CoreService extends BaseService {
387
492
  async getUserProfile() {
388
493
  this._requireReady("getUserProfile");
389
494
  try {
390
- return await this._request("/users/profile", {
495
+ const response = await this._request("/users/profile", {
391
496
  method: "GET",
392
497
  methodName: "getUserProfile"
393
498
  });
499
+ if (response.success) {
500
+ return response.data;
501
+ }
502
+ throw new Error(response.message);
394
503
  } catch (error) {
395
504
  throw new Error(`Failed to get user profile: ${error.message}`);
396
505
  }
@@ -398,11 +507,15 @@ class CoreService extends BaseService {
398
507
  async updateUserProfile(profileData) {
399
508
  this._requireReady("updateUserProfile");
400
509
  try {
401
- return await this._request("/users/profile", {
510
+ const response = await this._request("/users/profile", {
402
511
  method: "PATCH",
403
512
  body: JSON.stringify(profileData),
404
513
  methodName: "updateUserProfile"
405
514
  });
515
+ if (response.success) {
516
+ return response.data;
517
+ }
518
+ throw new Error(response.message);
406
519
  } catch (error) {
407
520
  throw new Error(`Failed to update user profile: ${error.message}`);
408
521
  }
@@ -410,10 +523,17 @@ class CoreService extends BaseService {
410
523
  async getUserProjects() {
411
524
  this._requireReady("getUserProjects");
412
525
  try {
413
- return await this._request("/users/projects", {
526
+ const response = await this._request("/users/projects", {
414
527
  method: "GET",
415
528
  methodName: "getUserProjects"
416
529
  });
530
+ if (response.success) {
531
+ return response.data.map((project) => ({
532
+ ...project,
533
+ ...project.icon && { icon: { src: `${this._apiUrl}/core/files/public/${project.icon.id}/download`, ...project.icon } }
534
+ }));
535
+ }
536
+ throw new Error(response.message);
417
537
  } catch (error) {
418
538
  throw new Error(`Failed to get user projects: ${error.message}`);
419
539
  }
@@ -424,10 +544,14 @@ class CoreService extends BaseService {
424
544
  throw new Error("User ID is required");
425
545
  }
426
546
  try {
427
- return await this._request(`/users/${userId}`, {
547
+ const response = await this._request(`/users/${userId}`, {
428
548
  method: "GET",
429
549
  methodName: "getUser"
430
550
  });
551
+ if (response.success) {
552
+ return response.data;
553
+ }
554
+ throw new Error(response.message);
431
555
  } catch (error) {
432
556
  throw new Error(`Failed to get user: ${error.message}`);
433
557
  }
@@ -438,13 +562,17 @@ class CoreService extends BaseService {
438
562
  throw new Error("Email is required");
439
563
  }
440
564
  try {
441
- return await this._request("/auth/user", {
565
+ const response = await this._request("/auth/user", {
442
566
  method: "GET",
443
567
  headers: {
444
568
  "X-User-Email": email
445
569
  },
446
570
  methodName: "getUserByEmail"
447
571
  });
572
+ if (response.success) {
573
+ return response.data;
574
+ }
575
+ throw new Error(response.message);
448
576
  } catch (error) {
449
577
  throw new Error(`Failed to get user by email: ${error.message}`);
450
578
  }
@@ -453,50 +581,134 @@ class CoreService extends BaseService {
453
581
  async createProject(projectData) {
454
582
  this._requireReady("createProject");
455
583
  try {
456
- return await this._request("/projects", {
584
+ const response = await this._request("/projects", {
457
585
  method: "POST",
458
586
  body: JSON.stringify(projectData),
459
587
  methodName: "createProject"
460
588
  });
589
+ if (response.success) {
590
+ return response.data;
591
+ }
592
+ throw new Error(response.message);
461
593
  } catch (error) {
462
594
  throw new Error(`Failed to create project: ${error.message}`);
463
595
  }
464
596
  }
465
- async getProjects() {
597
+ async getProjects(params = {}) {
466
598
  this._requireReady("getProjects");
467
599
  try {
468
- return await this._request("/projects", {
600
+ const queryParams = new URLSearchParams();
601
+ Object.keys(params).forEach((key) => {
602
+ if (params[key] != null) {
603
+ queryParams.append(key, params[key]);
604
+ }
605
+ });
606
+ const queryString = queryParams.toString();
607
+ const url = `/projects${queryString ? `?${queryString}` : ""}`;
608
+ const response = await this._request(url, {
469
609
  method: "GET",
470
610
  methodName: "getProjects"
471
611
  });
612
+ if (response.success) {
613
+ return response;
614
+ }
615
+ throw new Error(response.message);
472
616
  } catch (error) {
473
617
  throw new Error(`Failed to get projects: ${error.message}`);
474
618
  }
475
619
  }
620
+ /**
621
+ * Alias for getProjects for consistency with API naming
622
+ */
623
+ async listProjects(params = {}) {
624
+ return await this.getProjects(params);
625
+ }
626
+ /**
627
+ * List only public projects (no authentication required)
628
+ */
629
+ async listPublicProjects(params = {}) {
630
+ try {
631
+ const queryParams = new URLSearchParams();
632
+ Object.keys(params).forEach((key) => {
633
+ if (params[key] != null) {
634
+ queryParams.append(key, params[key]);
635
+ }
636
+ });
637
+ const queryString = queryParams.toString();
638
+ const url = `/projects/public${queryString ? `?${queryString}` : ""}`;
639
+ const response = await this._request(url, {
640
+ method: "GET",
641
+ methodName: "listPublicProjects"
642
+ });
643
+ if (response.success) {
644
+ return response.data;
645
+ }
646
+ throw new Error(response.message);
647
+ } catch (error) {
648
+ throw new Error(`Failed to list public projects: ${error.message}`);
649
+ }
650
+ }
476
651
  async getProject(projectId) {
477
652
  this._requireReady("getProject");
478
653
  if (!projectId) {
479
654
  throw new Error("Project ID is required");
480
655
  }
481
656
  try {
482
- return await this._request(`/projects/${projectId}`, {
657
+ const response = await this._request(`/projects/${projectId}`, {
483
658
  method: "GET",
484
659
  methodName: "getProject"
485
660
  });
661
+ if (response.success) {
662
+ const iconSrc = response.data.icon ? `${this._apiUrl}/core/files/public/${response.data.icon.id}/download` : null;
663
+ return {
664
+ ...response.data,
665
+ icon: { src: iconSrc, ...response.data.icon }
666
+ };
667
+ }
668
+ throw new Error(response.message);
486
669
  } catch (error) {
487
670
  throw new Error(`Failed to get project: ${error.message}`);
488
671
  }
489
672
  }
673
+ /**
674
+ * Get a public project by ID (no authentication required)
675
+ * Corresponds to router.get('/public/:projectId', ProjectController.getPublicProject)
676
+ */
677
+ async getPublicProject(projectId) {
678
+ if (!projectId) {
679
+ throw new Error("Project ID is required");
680
+ }
681
+ try {
682
+ const response = await this._request(`/projects/public/${projectId}`, {
683
+ method: "GET",
684
+ methodName: "getPublicProject"
685
+ });
686
+ if (response.success) {
687
+ const iconSrc = response.data.icon ? `${this._apiUrl}/core/files/public/${response.data.icon.id}/download` : null;
688
+ return {
689
+ ...response.data,
690
+ icon: { src: iconSrc, ...response.data.icon }
691
+ };
692
+ }
693
+ throw new Error(response.message);
694
+ } catch (error) {
695
+ throw new Error(`Failed to get public project: ${error.message}`);
696
+ }
697
+ }
490
698
  async getProjectByKey(key) {
491
699
  this._requireReady("getProjectByKey");
492
700
  if (!key) {
493
701
  throw new Error("Project key is required");
494
702
  }
495
703
  try {
496
- return await this._request(`/projects/check-key/${key}`, {
704
+ const response = await this._request(`/projects/check-key/${key}`, {
497
705
  method: "GET",
498
706
  methodName: "getProjectByKey"
499
707
  });
708
+ if (response.success) {
709
+ return response.data;
710
+ }
711
+ throw new Error(response.message);
500
712
  } catch (error) {
501
713
  throw new Error(`Failed to get project by key: ${error.message}`);
502
714
  }
@@ -507,11 +719,15 @@ class CoreService extends BaseService {
507
719
  throw new Error("Project ID is required");
508
720
  }
509
721
  try {
510
- return await this._request(`/projects/${projectId}`, {
722
+ const response = await this._request(`/projects/${projectId}`, {
511
723
  method: "PATCH",
512
724
  body: JSON.stringify(data),
513
725
  methodName: "updateProject"
514
726
  });
727
+ if (response.success) {
728
+ return response.data;
729
+ }
730
+ throw new Error(response.message);
515
731
  } catch (error) {
516
732
  throw new Error(`Failed to update project: ${error.message}`);
517
733
  }
@@ -522,11 +738,15 @@ class CoreService extends BaseService {
522
738
  throw new Error("Project ID is required");
523
739
  }
524
740
  try {
525
- return await this._request(`/projects/${projectId}/components`, {
741
+ const response = await this._request(`/projects/${projectId}/components`, {
526
742
  method: "PATCH",
527
743
  body: JSON.stringify({ components }),
528
744
  methodName: "updateProjectComponents"
529
745
  });
746
+ if (response.success) {
747
+ return response.data;
748
+ }
749
+ throw new Error(response.message);
530
750
  } catch (error) {
531
751
  throw new Error(`Failed to update project components: ${error.message}`);
532
752
  }
@@ -537,11 +757,15 @@ class CoreService extends BaseService {
537
757
  throw new Error("Project ID is required");
538
758
  }
539
759
  try {
540
- return await this._request(`/projects/${projectId}/settings`, {
760
+ const response = await this._request(`/projects/${projectId}/settings`, {
541
761
  method: "PATCH",
542
762
  body: JSON.stringify({ settings }),
543
763
  methodName: "updateProjectSettings"
544
764
  });
765
+ if (response.success) {
766
+ return response.data;
767
+ }
768
+ throw new Error(response.message);
545
769
  } catch (error) {
546
770
  throw new Error(`Failed to update project settings: ${error.message}`);
547
771
  }
@@ -552,11 +776,15 @@ class CoreService extends BaseService {
552
776
  throw new Error("Project ID is required");
553
777
  }
554
778
  try {
555
- return await this._request(`/projects/${projectId}`, {
779
+ const response = await this._request(`/projects/${projectId}`, {
556
780
  method: "PATCH",
557
781
  body: JSON.stringify({ name }),
558
782
  methodName: "updateProjectName"
559
783
  });
784
+ if (response.success) {
785
+ return response.data;
786
+ }
787
+ throw new Error(response.message);
560
788
  } catch (error) {
561
789
  throw new Error(`Failed to update project name: ${error.message}`);
562
790
  }
@@ -567,26 +795,34 @@ class CoreService extends BaseService {
567
795
  throw new Error("Project ID is required");
568
796
  }
569
797
  try {
570
- return await this._request(`/projects/${projectId}/tier`, {
798
+ const response = await this._request(`/projects/${projectId}/tier`, {
571
799
  method: "PATCH",
572
800
  body: JSON.stringify({ tier: pkg }),
573
801
  methodName: "updateProjectPackage"
574
802
  });
803
+ if (response.success) {
804
+ return response.data;
805
+ }
806
+ throw new Error(response.message);
575
807
  } catch (error) {
576
808
  throw new Error(`Failed to update project package: ${error.message}`);
577
809
  }
578
810
  }
579
- async duplicateProject(projectId, newName, newKey) {
811
+ async duplicateProject(projectId, newName, newKey, targetUserId) {
580
812
  this._requireReady("duplicateProject");
581
813
  if (!projectId) {
582
814
  throw new Error("Project ID is required");
583
815
  }
584
816
  try {
585
- return await this._request(`/projects/${projectId}/duplicate`, {
817
+ const response = await this._request(`/projects/${projectId}/duplicate`, {
586
818
  method: "POST",
587
- body: JSON.stringify({ name: newName, key: newKey }),
819
+ body: JSON.stringify({ name: newName, key: newKey, targetUserId }),
588
820
  methodName: "duplicateProject"
589
821
  });
822
+ if (response.success) {
823
+ return response.data;
824
+ }
825
+ throw new Error(response.message);
590
826
  } catch (error) {
591
827
  throw new Error(`Failed to duplicate project: ${error.message}`);
592
828
  }
@@ -597,10 +833,14 @@ class CoreService extends BaseService {
597
833
  throw new Error("Project ID is required");
598
834
  }
599
835
  try {
600
- return await this._request(`/projects/${projectId}`, {
836
+ const response = await this._request(`/projects/${projectId}`, {
601
837
  method: "DELETE",
602
838
  methodName: "removeProject"
603
839
  });
840
+ if (response.success) {
841
+ return response.data;
842
+ }
843
+ throw new Error(response.message);
604
844
  } catch (error) {
605
845
  throw new Error(`Failed to remove project: ${error.message}`);
606
846
  }
@@ -611,10 +851,14 @@ class CoreService extends BaseService {
611
851
  throw new Error("Project key is required");
612
852
  }
613
853
  try {
614
- return await this._request(`/projects/check-key/${key}`, {
854
+ const response = await this._request(`/projects/check-key/${key}`, {
615
855
  method: "GET",
616
856
  methodName: "checkProjectKeyAvailability"
617
857
  });
858
+ if (response.success) {
859
+ return response.data;
860
+ }
861
+ throw new Error(response.message);
618
862
  } catch (error) {
619
863
  throw new Error(`Failed to check project key availability: ${error.message}`);
620
864
  }
@@ -626,40 +870,62 @@ class CoreService extends BaseService {
626
870
  throw new Error("Project ID is required");
627
871
  }
628
872
  try {
629
- return await this._request(`/projects/${projectId}/members`, {
873
+ const response = await this._request(`/projects/${projectId}/members`, {
630
874
  method: "GET",
631
875
  methodName: "getProjectMembers"
632
876
  });
877
+ if (response.success) {
878
+ return response.data;
879
+ }
880
+ throw new Error(response.message);
633
881
  } catch (error) {
634
882
  throw new Error(`Failed to get project members: ${error.message}`);
635
883
  }
636
884
  }
637
- async inviteMember(projectId, email, message, role = "guest") {
885
+ async inviteMember(projectId, email, role = "guest", options = {}) {
638
886
  this._requireReady("inviteMember");
639
- if (!projectId || !email) {
640
- throw new Error("Project ID and email are required");
887
+ if (!projectId || !email || !role) {
888
+ throw new Error("Project ID, email, and role are required");
641
889
  }
890
+ const { name, callbackUrl } = options;
891
+ const defaultCallbackUrl = typeof window === "undefined" ? "https://app.symbols.com/accept-invite" : `${window.location.origin}/accept-invite`;
642
892
  try {
643
- return await this._request(`/projects/${projectId}/invite`, {
893
+ const requestBody = {
894
+ email,
895
+ role,
896
+ callbackUrl: callbackUrl || defaultCallbackUrl
897
+ };
898
+ if (name) {
899
+ requestBody.name = name;
900
+ }
901
+ const response = await this._request(`/projects/${projectId}/invite`, {
644
902
  method: "POST",
645
- body: JSON.stringify({ email, role, message }),
903
+ body: JSON.stringify(requestBody),
646
904
  methodName: "inviteMember"
647
905
  });
906
+ if (response.success) {
907
+ return response.data;
908
+ }
909
+ throw new Error(response.message);
648
910
  } catch (error) {
649
911
  throw new Error(`Failed to invite member: ${error.message}`);
650
912
  }
651
913
  }
652
- async acceptInvite(projectId, token) {
914
+ async acceptInvite(token) {
653
915
  this._requireReady("acceptInvite");
654
- if (!projectId || !token) {
655
- throw new Error("Project ID and token are required");
916
+ if (!token) {
917
+ throw new Error("Invitation token is required");
656
918
  }
657
919
  try {
658
- return await this._request(`/projects/${projectId}/accept-invite`, {
920
+ const response = await this._request("/projects/accept-invite", {
659
921
  method: "POST",
660
922
  body: JSON.stringify({ token }),
661
923
  methodName: "acceptInvite"
662
924
  });
925
+ if (response.success) {
926
+ return response.data;
927
+ }
928
+ throw new Error(response.message);
663
929
  } catch (error) {
664
930
  throw new Error(`Failed to accept invite: ${error.message}`);
665
931
  }
@@ -670,11 +936,15 @@ class CoreService extends BaseService {
670
936
  throw new Error("Project ID, member ID, and role are required");
671
937
  }
672
938
  try {
673
- return await this._request(`/projects/${projectId}/members/${memberId}`, {
939
+ const response = await this._request(`/projects/${projectId}/members/${memberId}`, {
674
940
  method: "PATCH",
675
941
  body: JSON.stringify({ role }),
676
942
  methodName: "updateMemberRole"
677
943
  });
944
+ if (response.success) {
945
+ return response.data;
946
+ }
947
+ throw new Error(response.message);
678
948
  } catch (error) {
679
949
  throw new Error(`Failed to update member role: ${error.message}`);
680
950
  }
@@ -685,10 +955,14 @@ class CoreService extends BaseService {
685
955
  throw new Error("Project ID and member ID are required");
686
956
  }
687
957
  try {
688
- return await this._request(`/projects/${projectId}/members/${memberId}`, {
958
+ const response = await this._request(`/projects/${projectId}/members/${memberId}`, {
689
959
  method: "DELETE",
690
960
  methodName: "removeMember"
691
961
  });
962
+ if (response.success) {
963
+ return response.data;
964
+ }
965
+ throw new Error(response.message);
692
966
  } catch (error) {
693
967
  throw new Error(`Failed to remove member: ${error.message}`);
694
968
  }
@@ -698,10 +972,14 @@ class CoreService extends BaseService {
698
972
  this._requireReady("getAvailableLibraries");
699
973
  const queryParams = new URLSearchParams(params).toString();
700
974
  try {
701
- return await this._request(`/projects/libraries/available?${queryParams}`, {
975
+ const response = await this._request(`/projects/libraries/available?${queryParams}`, {
702
976
  method: "GET",
703
977
  methodName: "getAvailableLibraries"
704
978
  });
979
+ if (response.success) {
980
+ return response.data;
981
+ }
982
+ throw new Error(response.message);
705
983
  } catch (error) {
706
984
  throw new Error(`Failed to get available libraries: ${error.message}`);
707
985
  }
@@ -712,10 +990,14 @@ class CoreService extends BaseService {
712
990
  throw new Error("Project ID is required");
713
991
  }
714
992
  try {
715
- return await this._request(`/projects/${projectId}/libraries`, {
993
+ const response = await this._request(`/projects/${projectId}/libraries`, {
716
994
  method: "GET",
717
995
  methodName: "getProjectLibraries"
718
996
  });
997
+ if (response.success) {
998
+ return response.data;
999
+ }
1000
+ throw new Error(response.message);
719
1001
  } catch (error) {
720
1002
  throw new Error(`Failed to get project libraries: ${error.message}`);
721
1003
  }
@@ -726,11 +1008,15 @@ class CoreService extends BaseService {
726
1008
  throw new Error("Project ID and library IDs are required");
727
1009
  }
728
1010
  try {
729
- return await this._request(`/projects/${projectId}/libraries`, {
1011
+ const response = await this._request(`/projects/${projectId}/libraries`, {
730
1012
  method: "POST",
731
1013
  body: JSON.stringify({ libraryIds }),
732
1014
  methodName: "addProjectLibraries"
733
1015
  });
1016
+ if (response.success) {
1017
+ return response.data;
1018
+ }
1019
+ throw new Error(response.message);
734
1020
  } catch (error) {
735
1021
  throw new Error(`Failed to add project libraries: ${error.message}`);
736
1022
  }
@@ -741,11 +1027,15 @@ class CoreService extends BaseService {
741
1027
  throw new Error("Project ID and library IDs are required");
742
1028
  }
743
1029
  try {
744
- return await this._request(`/projects/${projectId}/libraries`, {
1030
+ const response = await this._request(`/projects/${projectId}/libraries`, {
745
1031
  method: "DELETE",
746
1032
  body: JSON.stringify({ libraryIds }),
747
1033
  methodName: "removeProjectLibraries"
748
1034
  });
1035
+ if (response.success) {
1036
+ return response.data;
1037
+ }
1038
+ throw new Error(response.message);
749
1039
  } catch (error) {
750
1040
  throw new Error(`Failed to remove project libraries: ${error.message}`);
751
1041
  }
@@ -765,19 +1055,28 @@ class CoreService extends BaseService {
765
1055
  formData.append("tags", JSON.stringify(options.tags));
766
1056
  }
767
1057
  if (options.visibility) {
768
- formData.append("visibility", options.visibility);
1058
+ formData.append("visibility", options.visibility || "public");
769
1059
  }
770
1060
  if (options.metadata) {
771
1061
  formData.append("metadata", JSON.stringify(options.metadata));
772
1062
  }
773
1063
  try {
774
- return await this._request("/files/upload", {
1064
+ const response = await this._request("/files/upload", {
775
1065
  method: "POST",
776
1066
  body: formData,
777
1067
  headers: {},
778
1068
  // Let browser set Content-Type for FormData
779
1069
  methodName: "uploadFile"
780
1070
  });
1071
+ if (!response.success) {
1072
+ throw new Error(response.message);
1073
+ }
1074
+ return {
1075
+ id: response.data.id,
1076
+ src: `${this._apiUrl}/core/files/public/${response.data.id}/download`,
1077
+ success: true,
1078
+ message: response.message
1079
+ };
781
1080
  } catch (error) {
782
1081
  throw new Error(`File upload failed: ${error.message}`);
783
1082
  }
@@ -791,13 +1090,17 @@ class CoreService extends BaseService {
791
1090
  formData.append("icon", iconFile);
792
1091
  formData.append("projectId", projectId);
793
1092
  try {
794
- return await this._request("/files/upload-project-icon", {
1093
+ const response = await this._request("/files/upload-project-icon", {
795
1094
  method: "POST",
796
1095
  body: formData,
797
1096
  headers: {},
798
1097
  // Let browser set Content-Type for FormData
799
1098
  methodName: "updateProjectIcon"
800
1099
  });
1100
+ if (response.success) {
1101
+ return response.data;
1102
+ }
1103
+ throw new Error(response.message);
801
1104
  } catch (error) {
802
1105
  throw new Error(`Failed to update project icon: ${error.message}`);
803
1106
  }
@@ -816,7 +1119,7 @@ class CoreService extends BaseService {
816
1119
  throw new Error("Project ID is required for checkout");
817
1120
  }
818
1121
  try {
819
- return await this._request("/payments/checkout", {
1122
+ const response = await this._request("/payments/checkout", {
820
1123
  method: "POST",
821
1124
  body: JSON.stringify({
822
1125
  projectId,
@@ -827,6 +1130,10 @@ class CoreService extends BaseService {
827
1130
  }),
828
1131
  methodName: "checkout"
829
1132
  });
1133
+ if (response.success) {
1134
+ return response.data;
1135
+ }
1136
+ throw new Error(response.message);
830
1137
  } catch (error) {
831
1138
  throw new Error(`Failed to checkout: ${error.message}`);
832
1139
  }
@@ -837,10 +1144,14 @@ class CoreService extends BaseService {
837
1144
  throw new Error("Project ID is required");
838
1145
  }
839
1146
  try {
840
- return await this._request(`/payments/subscription/${projectId}`, {
1147
+ const response = await this._request(`/payments/subscription/${projectId}`, {
841
1148
  method: "GET",
842
1149
  methodName: "getSubscriptionStatus"
843
1150
  });
1151
+ if (response.success) {
1152
+ return response.data;
1153
+ }
1154
+ throw new Error(response.message);
844
1155
  } catch (error) {
845
1156
  throw new Error(`Failed to get subscription status: ${error.message}`);
846
1157
  }
@@ -852,11 +1163,15 @@ class CoreService extends BaseService {
852
1163
  throw new Error("Domain is required");
853
1164
  }
854
1165
  try {
855
- return await this._request("/dns/records", {
1166
+ const response = await this._request("/dns/records", {
856
1167
  method: "POST",
857
1168
  body: JSON.stringify({ domain, ...options }),
858
1169
  methodName: "createDnsRecord"
859
1170
  });
1171
+ if (response.success) {
1172
+ return response.data;
1173
+ }
1174
+ throw new Error(response.message);
860
1175
  } catch (error) {
861
1176
  throw new Error(`Failed to create DNS record: ${error.message}`);
862
1177
  }
@@ -867,10 +1182,14 @@ class CoreService extends BaseService {
867
1182
  throw new Error("Domain is required");
868
1183
  }
869
1184
  try {
870
- return await this._request(`/dns/records/${domain}`, {
1185
+ const response = await this._request(`/dns/records/${domain}`, {
871
1186
  method: "GET",
872
1187
  methodName: "getDnsRecord"
873
1188
  });
1189
+ if (response.success) {
1190
+ return response.data;
1191
+ }
1192
+ throw new Error(response.message);
874
1193
  } catch (error) {
875
1194
  throw new Error(`Failed to get DNS record: ${error.message}`);
876
1195
  }
@@ -881,10 +1200,14 @@ class CoreService extends BaseService {
881
1200
  throw new Error("Domain is required");
882
1201
  }
883
1202
  try {
884
- return await this._request(`/dns/records/${domain}`, {
1203
+ const response = await this._request(`/dns/records/${domain}`, {
885
1204
  method: "DELETE",
886
1205
  methodName: "removeDnsRecord"
887
1206
  });
1207
+ if (response.success) {
1208
+ return response.data;
1209
+ }
1210
+ throw new Error(response.message);
888
1211
  } catch (error) {
889
1212
  throw new Error(`Failed to remove DNS record: ${error.message}`);
890
1213
  }
@@ -895,7 +1218,7 @@ class CoreService extends BaseService {
895
1218
  throw new Error("Project key is required");
896
1219
  }
897
1220
  try {
898
- return await this._request("/dns/project-domains", {
1221
+ const response = await this._request("/dns/project-domains", {
899
1222
  method: "POST",
900
1223
  body: JSON.stringify({
901
1224
  projectKey,
@@ -904,6 +1227,10 @@ class CoreService extends BaseService {
904
1227
  }),
905
1228
  methodName: "setProjectDomains"
906
1229
  });
1230
+ if (response.success) {
1231
+ return response.data;
1232
+ }
1233
+ throw new Error(response.message);
907
1234
  } catch (error) {
908
1235
  throw new Error(`Failed to set project domains: ${error.message}`);
909
1236
  }
@@ -911,10 +1238,14 @@ class CoreService extends BaseService {
911
1238
  // ==================== UTILITY METHODS ====================
912
1239
  async getHealthStatus() {
913
1240
  try {
914
- return await this._request("/health", {
1241
+ const response = await this._request("/health", {
915
1242
  method: "GET",
916
1243
  methodName: "getHealthStatus"
917
1244
  });
1245
+ if (response.success) {
1246
+ return response.data;
1247
+ }
1248
+ throw new Error(response.message);
918
1249
  } catch (error) {
919
1250
  throw new Error(`Failed to get health status: ${error.message}`);
920
1251
  }
@@ -948,7 +1279,10 @@ class CoreService extends BaseService {
948
1279
  }),
949
1280
  methodName: "applyProjectChanges"
950
1281
  });
951
- return response;
1282
+ if (response.success) {
1283
+ return response.data;
1284
+ }
1285
+ throw new Error(response.message);
952
1286
  } catch (error) {
953
1287
  throw new Error(`Failed to apply project changes: ${error.message}`);
954
1288
  }
@@ -964,17 +1298,23 @@ class CoreService extends BaseService {
964
1298
  }
965
1299
  const {
966
1300
  branch = "main",
1301
+ version = "latest",
967
1302
  includeHistory = false
968
1303
  } = options;
969
1304
  const queryParams = new URLSearchParams({
970
1305
  branch,
1306
+ version,
971
1307
  includeHistory: includeHistory.toString()
972
1308
  }).toString();
973
1309
  try {
974
- return await this._request(`/projects/${projectId}/data?${queryParams}`, {
1310
+ const response = await this._request(`/projects/${projectId}/data?${queryParams}`, {
975
1311
  method: "GET",
976
1312
  methodName: "getProjectData"
977
1313
  });
1314
+ if (response.success) {
1315
+ return response.data;
1316
+ }
1317
+ throw new Error(response.message);
978
1318
  } catch (error) {
979
1319
  throw new Error(`Failed to get project data: ${error.message}`);
980
1320
  }
@@ -998,10 +1338,14 @@ class CoreService extends BaseService {
998
1338
  limit: limit.toString()
999
1339
  }).toString();
1000
1340
  try {
1001
- return await this._request(`/projects/${projectId}/versions?${queryParams}`, {
1341
+ const response = await this._request(`/projects/${projectId}/versions?${queryParams}`, {
1002
1342
  method: "GET",
1003
1343
  methodName: "getProjectVersions"
1004
1344
  });
1345
+ if (response.success) {
1346
+ return response.data;
1347
+ }
1348
+ throw new Error(response.message);
1005
1349
  } catch (error) {
1006
1350
  throw new Error(`Failed to get project versions: ${error.message}`);
1007
1351
  }
@@ -1024,7 +1368,7 @@ class CoreService extends BaseService {
1024
1368
  type = "patch"
1025
1369
  } = options;
1026
1370
  try {
1027
- return await this._request(`/projects/${projectId}/restore`, {
1371
+ const response = await this._request(`/projects/${projectId}/restore`, {
1028
1372
  method: "POST",
1029
1373
  body: JSON.stringify({
1030
1374
  version,
@@ -1034,6 +1378,10 @@ class CoreService extends BaseService {
1034
1378
  }),
1035
1379
  methodName: "restoreProjectVersion"
1036
1380
  });
1381
+ if (response.success) {
1382
+ return response.data;
1383
+ }
1384
+ throw new Error(response.message);
1037
1385
  } catch (error) {
1038
1386
  throw new Error(`Failed to restore project version: ${error.message}`);
1039
1387
  }
@@ -1126,11 +1474,15 @@ class CoreService extends BaseService {
1126
1474
  throw new Error("Source branch, target branch, and title are required");
1127
1475
  }
1128
1476
  try {
1129
- return await this._request(`/projects/${projectId}/pull-requests`, {
1477
+ const response = await this._request(`/projects/${projectId}/pull-requests`, {
1130
1478
  method: "POST",
1131
1479
  body: JSON.stringify(pullRequestData),
1132
1480
  methodName: "createPullRequest"
1133
1481
  });
1482
+ if (response.success) {
1483
+ return response.data;
1484
+ }
1485
+ throw new Error(response.message);
1134
1486
  } catch (error) {
1135
1487
  throw new Error(`Failed to create pull request: ${error.message}`);
1136
1488
  }
@@ -1162,10 +1514,14 @@ class CoreService extends BaseService {
1162
1514
  queryParams.append("target", target);
1163
1515
  }
1164
1516
  try {
1165
- return await this._request(`/projects/${projectId}/pull-requests?${queryParams.toString()}`, {
1517
+ const response = await this._request(`/projects/${projectId}/pull-requests?${queryParams.toString()}`, {
1166
1518
  method: "GET",
1167
1519
  methodName: "listPullRequests"
1168
1520
  });
1521
+ if (response.success) {
1522
+ return response.data;
1523
+ }
1524
+ throw new Error(response.message);
1169
1525
  } catch (error) {
1170
1526
  throw new Error(`Failed to list pull requests: ${error.message}`);
1171
1527
  }
@@ -1182,10 +1538,14 @@ class CoreService extends BaseService {
1182
1538
  throw new Error("Pull request ID is required");
1183
1539
  }
1184
1540
  try {
1185
- return await this._request(`/projects/${projectId}/pull-requests/${prId}`, {
1541
+ const response = await this._request(`/projects/${projectId}/pull-requests/${prId}`, {
1186
1542
  method: "GET",
1187
1543
  methodName: "getPullRequest"
1188
1544
  });
1545
+ if (response.success) {
1546
+ return response.data;
1547
+ }
1548
+ throw new Error(response.message);
1189
1549
  } catch (error) {
1190
1550
  throw new Error(`Failed to get pull request: ${error.message}`);
1191
1551
  }
@@ -1206,11 +1566,15 @@ class CoreService extends BaseService {
1206
1566
  throw new Error(`Invalid review status. Must be one of: ${validStatuses.join(", ")}`);
1207
1567
  }
1208
1568
  try {
1209
- return await this._request(`/projects/${projectId}/pull-requests/${prId}/review`, {
1569
+ const response = await this._request(`/projects/${projectId}/pull-requests/${prId}/review`, {
1210
1570
  method: "POST",
1211
1571
  body: JSON.stringify(reviewData),
1212
1572
  methodName: "reviewPullRequest"
1213
1573
  });
1574
+ if (response.success) {
1575
+ return response.data;
1576
+ }
1577
+ throw new Error(response.message);
1214
1578
  } catch (error) {
1215
1579
  throw new Error(`Failed to review pull request: ${error.message}`);
1216
1580
  }
@@ -1230,11 +1594,15 @@ class CoreService extends BaseService {
1230
1594
  throw new Error("Comment value is required");
1231
1595
  }
1232
1596
  try {
1233
- return await this._request(`/projects/${projectId}/pull-requests/${prId}/comment`, {
1597
+ const response = await this._request(`/projects/${projectId}/pull-requests/${prId}/comment`, {
1234
1598
  method: "POST",
1235
1599
  body: JSON.stringify(commentData),
1236
1600
  methodName: "addPullRequestComment"
1237
1601
  });
1602
+ if (response.success) {
1603
+ return response.data;
1604
+ }
1605
+ throw new Error(response.message);
1238
1606
  } catch (error) {
1239
1607
  throw new Error(`Failed to add pull request comment: ${error.message}`);
1240
1608
  }
@@ -1255,7 +1623,10 @@ class CoreService extends BaseService {
1255
1623
  method: "POST",
1256
1624
  methodName: "mergePullRequest"
1257
1625
  });
1258
- return response;
1626
+ if (response.success) {
1627
+ return response.data;
1628
+ }
1629
+ throw new Error(response.message);
1259
1630
  } catch (error) {
1260
1631
  if (error.message.includes("conflicts") || error.message.includes("409")) {
1261
1632
  throw new Error(`Pull request has merge conflicts: ${error.message}`);
@@ -1275,10 +1646,14 @@ class CoreService extends BaseService {
1275
1646
  throw new Error("Pull request ID is required");
1276
1647
  }
1277
1648
  try {
1278
- return await this._request(`/projects/${projectId}/pull-requests/${prId}/diff`, {
1649
+ const response = await this._request(`/projects/${projectId}/pull-requests/${prId}/diff`, {
1279
1650
  method: "GET",
1280
1651
  methodName: "getPullRequestDiff"
1281
1652
  });
1653
+ if (response.success) {
1654
+ return response.data;
1655
+ }
1656
+ throw new Error(response.message);
1282
1657
  } catch (error) {
1283
1658
  throw new Error(`Failed to get pull request diff: ${error.message}`);
1284
1659
  }
@@ -1392,10 +1767,14 @@ class CoreService extends BaseService {
1392
1767
  throw new Error("Project ID is required");
1393
1768
  }
1394
1769
  try {
1395
- return await this._request(`/projects/${projectId}/branches`, {
1770
+ const response = await this._request(`/projects/${projectId}/branches`, {
1396
1771
  method: "GET",
1397
1772
  methodName: "listBranches"
1398
1773
  });
1774
+ if (response.success) {
1775
+ return response.data;
1776
+ }
1777
+ throw new Error(response.message);
1399
1778
  } catch (error) {
1400
1779
  throw new Error(`Failed to list branches: ${error.message}`);
1401
1780
  }
@@ -1413,11 +1792,15 @@ class CoreService extends BaseService {
1413
1792
  }
1414
1793
  const { name, source = "main" } = branchData;
1415
1794
  try {
1416
- return await this._request(`/projects/${projectId}/branches`, {
1795
+ const response = await this._request(`/projects/${projectId}/branches`, {
1417
1796
  method: "POST",
1418
1797
  body: JSON.stringify({ name, source }),
1419
1798
  methodName: "createBranch"
1420
1799
  });
1800
+ if (response.success) {
1801
+ return response.data;
1802
+ }
1803
+ throw new Error(response.message);
1421
1804
  } catch (error) {
1422
1805
  throw new Error(`Failed to create branch: ${error.message}`);
1423
1806
  }
@@ -1437,10 +1820,14 @@ class CoreService extends BaseService {
1437
1820
  throw new Error("Cannot delete main branch");
1438
1821
  }
1439
1822
  try {
1440
- return await this._request(`/projects/${projectId}/branches/${encodeURIComponent(branchName)}`, {
1823
+ const response = await this._request(`/projects/${projectId}/branches/${encodeURIComponent(branchName)}`, {
1441
1824
  method: "DELETE",
1442
1825
  methodName: "deleteBranch"
1443
1826
  });
1827
+ if (response.success) {
1828
+ return response.data;
1829
+ }
1830
+ throw new Error(response.message);
1444
1831
  } catch (error) {
1445
1832
  throw new Error(`Failed to delete branch: ${error.message}`);
1446
1833
  }
@@ -1463,11 +1850,15 @@ class CoreService extends BaseService {
1463
1850
  throw new Error("Cannot rename main branch");
1464
1851
  }
1465
1852
  try {
1466
- return await this._request(`/projects/${projectId}/branches/${encodeURIComponent(branchName)}/rename`, {
1853
+ const response = await this._request(`/projects/${projectId}/branches/${encodeURIComponent(branchName)}/rename`, {
1467
1854
  method: "POST",
1468
1855
  body: JSON.stringify({ newName }),
1469
1856
  methodName: "renameBranch"
1470
1857
  });
1858
+ if (response.success) {
1859
+ return response.data;
1860
+ }
1861
+ throw new Error(response.message);
1471
1862
  } catch (error) {
1472
1863
  throw new Error(`Failed to rename branch: ${error.message}`);
1473
1864
  }
@@ -1475,7 +1866,7 @@ class CoreService extends BaseService {
1475
1866
  /**
1476
1867
  * Get changes/diff for a branch compared to another version
1477
1868
  */
1478
- async getBranchChanges(projectId, branchName, options = {}) {
1869
+ async getBranchChanges(projectId, branchName = "main", options = {}) {
1479
1870
  this._requireReady("getBranchChanges");
1480
1871
  if (!projectId) {
1481
1872
  throw new Error("Project ID is required");
@@ -1497,10 +1888,14 @@ class CoreService extends BaseService {
1497
1888
  const queryString = queryParams.toString();
1498
1889
  const url = `/projects/${projectId}/branches/${encodeURIComponent(branchName)}/changes${queryString ? `?${queryString}` : ""}`;
1499
1890
  try {
1500
- return await this._request(url, {
1891
+ const response = await this._request(url, {
1501
1892
  method: "GET",
1502
1893
  methodName: "getBranchChanges"
1503
1894
  });
1895
+ if (response.success) {
1896
+ return response.data;
1897
+ }
1898
+ throw new Error(response.message);
1504
1899
  } catch (error) {
1505
1900
  throw new Error(`Failed to get branch changes: ${error.message}`);
1506
1901
  }
@@ -1531,11 +1926,15 @@ class CoreService extends BaseService {
1531
1926
  ...changes && { changes }
1532
1927
  };
1533
1928
  try {
1534
- return await this._request(`/projects/${projectId}/branches/${encodeURIComponent(branchName)}/merge`, {
1929
+ const response = await this._request(`/projects/${projectId}/branches/${encodeURIComponent(branchName)}/merge`, {
1535
1930
  method: "POST",
1536
1931
  body: JSON.stringify(requestBody),
1537
1932
  methodName: "mergeBranch"
1538
1933
  });
1934
+ if (response.success) {
1935
+ return response.data;
1936
+ }
1937
+ throw new Error(response.message);
1539
1938
  } catch (error) {
1540
1939
  if (error.message.includes("conflicts") || error.message.includes("409")) {
1541
1940
  throw new Error(`Merge conflicts detected: ${error.message}`);
@@ -1555,10 +1954,14 @@ class CoreService extends BaseService {
1555
1954
  throw new Error("Branch name is required");
1556
1955
  }
1557
1956
  try {
1558
- return await this._request(`/projects/${projectId}/branches/${encodeURIComponent(branchName)}/reset`, {
1957
+ const response = await this._request(`/projects/${projectId}/branches/${encodeURIComponent(branchName)}/reset`, {
1559
1958
  method: "POST",
1560
1959
  methodName: "resetBranch"
1561
1960
  });
1961
+ if (response.success) {
1962
+ return response.data;
1963
+ }
1964
+ throw new Error(response.message);
1562
1965
  } catch (error) {
1563
1966
  throw new Error(`Failed to reset branch: ${error.message}`);
1564
1967
  }
@@ -1576,11 +1979,15 @@ class CoreService extends BaseService {
1576
1979
  }
1577
1980
  const { version, branch = "main" } = publishData;
1578
1981
  try {
1579
- return await this._request(`/projects/${projectId}/publish`, {
1982
+ const response = await this._request(`/projects/${projectId}/publish`, {
1580
1983
  method: "POST",
1581
1984
  body: JSON.stringify({ version, branch }),
1582
1985
  methodName: "publishVersion"
1583
1986
  });
1987
+ if (response.success) {
1988
+ return response.data;
1989
+ }
1990
+ throw new Error(response.message);
1584
1991
  } catch (error) {
1585
1992
  throw new Error(`Failed to publish version: ${error.message}`);
1586
1993
  }
@@ -1706,6 +2113,143 @@ class CoreService extends BaseService {
1706
2113
  }
1707
2114
  return await this.deleteBranch(projectId, branchName);
1708
2115
  }
2116
+ // ==================== ADMIN METHODS ====================
2117
+ /**
2118
+ * Get admin users list with comprehensive filtering and search capabilities
2119
+ * Requires admin or super_admin global role
2120
+ */
2121
+ async getAdminUsers(params = {}) {
2122
+ this._requireReady("getAdminUsers");
2123
+ const {
2124
+ emails,
2125
+ ids,
2126
+ query,
2127
+ status,
2128
+ page = 1,
2129
+ limit = 50,
2130
+ sort = { field: "createdAt", order: "desc" }
2131
+ } = params;
2132
+ const queryParams = new URLSearchParams();
2133
+ if (emails) {
2134
+ queryParams.append("emails", emails);
2135
+ }
2136
+ if (ids) {
2137
+ queryParams.append("ids", ids);
2138
+ }
2139
+ if (query) {
2140
+ queryParams.append("query", query);
2141
+ }
2142
+ if (status) {
2143
+ queryParams.append("status", status);
2144
+ }
2145
+ if (page) {
2146
+ queryParams.append("page", page.toString());
2147
+ }
2148
+ if (limit) {
2149
+ queryParams.append("limit", limit.toString());
2150
+ }
2151
+ if (sort && sort.field) {
2152
+ queryParams.append("sort[field]", sort.field);
2153
+ queryParams.append("sort[order]", sort.order || "desc");
2154
+ }
2155
+ const queryString = queryParams.toString();
2156
+ const url = `/users/admin/users${queryString ? `?${queryString}` : ""}`;
2157
+ try {
2158
+ const response = await this._request(url, {
2159
+ method: "GET",
2160
+ methodName: "getAdminUsers"
2161
+ });
2162
+ if (response.success) {
2163
+ return response.data;
2164
+ }
2165
+ throw new Error(response.message);
2166
+ } catch (error) {
2167
+ throw new Error(`Failed to get admin users: ${error.message}`);
2168
+ }
2169
+ }
2170
+ /**
2171
+ * Assign projects to a specific user
2172
+ * Requires admin or super_admin global role
2173
+ */
2174
+ async assignProjectsToUser(userId, options = {}) {
2175
+ this._requireReady("assignProjectsToUser");
2176
+ if (!userId) {
2177
+ throw new Error("User ID is required");
2178
+ }
2179
+ const {
2180
+ projectIds,
2181
+ role = "guest"
2182
+ } = options;
2183
+ const requestBody = {
2184
+ userId,
2185
+ role
2186
+ };
2187
+ if (projectIds && Array.isArray(projectIds)) {
2188
+ requestBody.projectIds = projectIds;
2189
+ }
2190
+ try {
2191
+ const response = await this._request("/assign-projects", {
2192
+ method: "POST",
2193
+ body: JSON.stringify(requestBody),
2194
+ methodName: "assignProjectsToUser"
2195
+ });
2196
+ if (response.success) {
2197
+ return response.data;
2198
+ }
2199
+ throw new Error(response.message);
2200
+ } catch (error) {
2201
+ throw new Error(`Failed to assign projects to user: ${error.message}`);
2202
+ }
2203
+ }
2204
+ /**
2205
+ * Helper method for admin users search
2206
+ */
2207
+ async searchAdminUsers(searchQuery, options = {}) {
2208
+ return await this.getAdminUsers({
2209
+ query: searchQuery,
2210
+ ...options
2211
+ });
2212
+ }
2213
+ /**
2214
+ * Helper method to get admin users by email list
2215
+ */
2216
+ async getAdminUsersByEmails(emails, options = {}) {
2217
+ const emailList = Array.isArray(emails) ? emails.join(",") : emails;
2218
+ return await this.getAdminUsers({
2219
+ emails: emailList,
2220
+ ...options
2221
+ });
2222
+ }
2223
+ /**
2224
+ * Helper method to get admin users by ID list
2225
+ */
2226
+ async getAdminUsersByIds(ids, options = {}) {
2227
+ const idList = Array.isArray(ids) ? ids.join(",") : ids;
2228
+ return await this.getAdminUsers({
2229
+ ids: idList,
2230
+ ...options
2231
+ });
2232
+ }
2233
+ /**
2234
+ * Helper method to assign specific projects to a user with a specific role
2235
+ */
2236
+ async assignSpecificProjectsToUser(userId, projectIds, role = "guest") {
2237
+ if (!Array.isArray(projectIds) || projectIds.length === 0) {
2238
+ throw new Error("Project IDs must be a non-empty array");
2239
+ }
2240
+ return await this.assignProjectsToUser(userId, {
2241
+ projectIds,
2242
+ role
2243
+ });
2244
+ }
2245
+ /**
2246
+ * Helper method to assign all projects to a user with a specific role
2247
+ */
2248
+ async assignAllProjectsToUser(userId, role = "guest") {
2249
+ return await this.assignProjectsToUser(userId, {
2250
+ role
2251
+ });
2252
+ }
1709
2253
  // Cleanup
1710
2254
  destroy() {
1711
2255
  if (this._tokenManager) {