@symbo.ls/sdk 2.33.14 → 2.33.17

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.
@@ -810,7 +810,7 @@ class AuthService extends import_BaseService.BaseService {
810
810
  try {
811
811
  const permissionResults = await Promise.all(
812
812
  permissions.map(
813
- (permission) => this.hasProjectPermission(projectId, permission)
813
+ (permission) => this.checkProjectPermission(projectId, permission)
814
814
  )
815
815
  );
816
816
  const hasPermissions = requireAll ? permissionResults.every(Boolean) : permissionResults.some(Boolean);
@@ -96,32 +96,8 @@ class DnsService extends import_BaseService.BaseService {
96
96
  throw new Error(`Failed to remove DNS record: ${error.message}`, { cause: error });
97
97
  }
98
98
  }
99
- // Deprecated, use addProjectCustomDomains instead
100
- async setProjectDomains(projectKey, customDomain, hasCustomDomainAccess = false) {
101
- this._requireReady("setProjectDomains");
102
- if (!projectKey) {
103
- throw new Error("Project key is required");
104
- }
105
- try {
106
- const response = await this._request("/dns/project-domains", {
107
- method: "POST",
108
- body: JSON.stringify({
109
- projectKey,
110
- customDomain,
111
- hasCustomDomainAccess
112
- }),
113
- methodName: "setProjectDomains"
114
- });
115
- if (response.success) {
116
- return response.data;
117
- }
118
- throw new Error(response.message);
119
- } catch (error) {
120
- throw new Error(`Failed to set project domains: ${error.message}`, { cause: error });
121
- }
122
- }
123
99
  // customDomains could be a string or an array of strings
124
- async addProjectCustomDomains(projectId, customDomains) {
100
+ async addProjectCustomDomains(projectId, customDomains, options = {}) {
125
101
  this._requireReady("addProjectCustomDomains");
126
102
  if (!projectId) {
127
103
  throw new Error("Project ID is required");
@@ -131,10 +107,15 @@ class DnsService extends import_BaseService.BaseService {
131
107
  "customDomains is required and must be a non-empty string or array"
132
108
  );
133
109
  }
110
+ const { envKey, headers } = options;
134
111
  try {
135
112
  const response = await this._request(`/projects/${projectId}/domains`, {
136
113
  method: "PATCH",
137
- body: JSON.stringify({ customDomains }),
114
+ body: JSON.stringify({
115
+ customDomains,
116
+ ...envKey ? { envKey } : {}
117
+ }),
118
+ ...headers ? { headers } : {},
138
119
  methodName: "addProjectCustomDomains"
139
120
  });
140
121
  if (response.success) {
@@ -208,25 +189,10 @@ class DnsService extends import_BaseService.BaseService {
208
189
  }
209
190
  return await this.removeDnsRecord(domain);
210
191
  }
211
- /**
212
- * Helper method to set project domains with validation
213
- */
214
- async setProjectDomainsWithValidation(projectKey, customDomain, hasCustomDomainAccess = false) {
215
- if (!projectKey || typeof projectKey !== "string") {
216
- throw new Error("Project key must be a valid string");
217
- }
218
- if (customDomain) {
219
- const validation = this.validateDomain(customDomain);
220
- if (!validation.isValid) {
221
- throw new Error(validation.error);
222
- }
223
- }
224
- return await this.setProjectDomains(projectKey, customDomain, hasCustomDomainAccess);
225
- }
226
192
  /**
227
193
  * Helper method to add project custom domains with validation
228
194
  */
229
- async addProjectCustomDomainsWithValidation(projectId, customDomains) {
195
+ async addProjectCustomDomainsWithValidation(projectId, customDomains, options = {}) {
230
196
  if (!projectId || typeof projectId !== "string") {
231
197
  throw new Error("Project ID must be a valid string");
232
198
  }
@@ -243,7 +209,7 @@ class DnsService extends import_BaseService.BaseService {
243
209
  throw new Error(`Invalid domain '${domain}': ${validation.error}`);
244
210
  }
245
211
  }
246
- return await this.addProjectCustomDomains(projectId, customDomains);
212
+ return await this.addProjectCustomDomains(projectId, customDomains, options);
247
213
  }
248
214
  /**
249
215
  * Helper method to check if domain is available
@@ -280,6 +280,62 @@ class ProjectService extends import_BaseService.BaseService {
280
280
  throw new Error(`Failed to update project name: ${error.message}`, { cause: error });
281
281
  }
282
282
  }
283
+ async setProjectAccess(projectId, access) {
284
+ this._requireReady("setProjectAccess");
285
+ if (!projectId) {
286
+ throw new Error("Project ID is required");
287
+ }
288
+ if (!access) {
289
+ throw new Error("Access level is required");
290
+ }
291
+ const allowedAccessValues = ["account", "team", "organization", "public"];
292
+ if (!allowedAccessValues.includes(access)) {
293
+ throw new Error(
294
+ `Invalid access value: ${access}. Must be one of: ${allowedAccessValues.join(", ")}`
295
+ );
296
+ }
297
+ try {
298
+ const response = await this._request(`/projects/${projectId}`, {
299
+ method: "PATCH",
300
+ body: JSON.stringify({ access }),
301
+ methodName: "setProjectAccess"
302
+ });
303
+ if (response.success) {
304
+ return response.data;
305
+ }
306
+ throw new Error(response.message);
307
+ } catch (error) {
308
+ throw new Error(`Failed to set project access: ${error.message}`, { cause: error });
309
+ }
310
+ }
311
+ async setProjectVisibility(projectId, visibility) {
312
+ this._requireReady("setProjectVisibility");
313
+ if (!projectId) {
314
+ throw new Error("Project ID is required");
315
+ }
316
+ if (!visibility) {
317
+ throw new Error("Visibility is required");
318
+ }
319
+ const allowedVisibilityValues = ["public", "private", "password-protected"];
320
+ if (!allowedVisibilityValues.includes(visibility)) {
321
+ throw new Error(
322
+ `Invalid visibility value: ${visibility}. Must be one of: ${allowedVisibilityValues.join(", ")}`
323
+ );
324
+ }
325
+ try {
326
+ const response = await this._request(`/projects/${projectId}`, {
327
+ method: "PATCH",
328
+ body: JSON.stringify({ visibility }),
329
+ methodName: "setProjectVisibility"
330
+ });
331
+ if (response.success) {
332
+ return response.data;
333
+ }
334
+ throw new Error(response.message);
335
+ } catch (error) {
336
+ throw new Error(`Failed to set project visibility: ${error.message}`, { cause: error });
337
+ }
338
+ }
283
339
  async updateProjectPackage(projectId, pkg) {
284
340
  this._requireReady("updateProjectPackage");
285
341
  if (!projectId) {
@@ -357,6 +413,65 @@ class ProjectService extends import_BaseService.BaseService {
357
413
  );
358
414
  }
359
415
  }
416
+ // ==================== PROJECT PERMISSION CONFIG METHODS ====================
417
+ /**
418
+ * Fetch effective role → permissions configuration for a project.
419
+ * Mirrors ProjectController.getProjectRolePermissionsConfig.
420
+ */
421
+ async getProjectRolePermissionsConfig(projectId, options = {}) {
422
+ this._requireReady("getProjectRolePermissionsConfig");
423
+ if (!projectId) {
424
+ throw new Error("Project ID is required");
425
+ }
426
+ const { headers } = options;
427
+ try {
428
+ const response = await this._request(`/projects/${projectId}/permissions`, {
429
+ method: "GET",
430
+ ...headers ? { headers } : {},
431
+ methodName: "getProjectRolePermissionsConfig"
432
+ });
433
+ if (response && response.success) {
434
+ return response.data;
435
+ }
436
+ throw new Error(response.message);
437
+ } catch (error) {
438
+ throw new Error(
439
+ `Failed to get project role permissions config: ${error.message}`,
440
+ { cause: error }
441
+ );
442
+ }
443
+ }
444
+ /**
445
+ * Update project-level role → permissions overrides.
446
+ * Mirrors ProjectController.updateProjectRolePermissionsConfig.
447
+ */
448
+ async updateProjectRolePermissionsConfig(projectId, rolePermissions, options = {}) {
449
+ this._requireReady("updateProjectRolePermissionsConfig");
450
+ if (!projectId) {
451
+ throw new Error("Project ID is required");
452
+ }
453
+ if (!rolePermissions || typeof rolePermissions !== "object") {
454
+ throw new Error("rolePermissions object is required");
455
+ }
456
+ const { headers } = options;
457
+ try {
458
+ const response = await this._request(`/projects/${projectId}/permissions`, {
459
+ method: "PATCH",
460
+ body: JSON.stringify({ rolePermissions }),
461
+ ...headers ? { headers } : {},
462
+ methodName: "updateProjectRolePermissionsConfig"
463
+ });
464
+ if (response && response.success) {
465
+ return response.data;
466
+ }
467
+ throw new Error(response.message);
468
+ } catch (error) {
469
+ throw new Error(
470
+ `Failed to update project role permissions config: ${error.message}`,
471
+ { cause: error }
472
+ );
473
+ }
474
+ }
360
475
  // ==================== PROJECT MEMBER METHODS ====================
361
476
  async getProjectMembers(projectId) {
362
477
  this._requireReady("getProjectMembers");
@@ -406,6 +521,30 @@ class ProjectService extends import_BaseService.BaseService {
406
521
  throw new Error(`Failed to invite member: ${error.message}`, { cause: error });
407
522
  }
408
523
  }
524
+ /**
525
+ * Create a magic invite link for a project.
526
+ * The backend returns a token and URL that can be shared directly.
527
+ */
528
+ async createMagicInviteLink(projectId, options = {}) {
529
+ this._requireReady("createMagicInviteLink");
530
+ if (!projectId) {
531
+ throw new Error("Project ID is required");
532
+ }
533
+ const { headers } = options;
534
+ try {
535
+ const response = await this._request(`/projects/${projectId}/invite-link`, {
536
+ method: "POST",
537
+ ...headers ? { headers } : {},
538
+ methodName: "createMagicInviteLink"
539
+ });
540
+ if (response.success) {
541
+ return response.data;
542
+ }
543
+ throw new Error(response.message);
544
+ } catch (error) {
545
+ throw new Error(`Failed to create magic invite link: ${error.message}`, { cause: error });
546
+ }
547
+ }
409
548
  async acceptInvite(token) {
410
549
  this._requireReady("acceptInvite");
411
550
  if (!token) {
@@ -652,6 +791,220 @@ class ProjectService extends import_BaseService.BaseService {
652
791
  throw new Error(`Failed to get project versions: ${error.message}`, { cause: error });
653
792
  }
654
793
  }
794
+ // ==================== PROJECT ENVIRONMENT METHODS ====================
795
+ /**
796
+ * List all environments for a project along with plan limits and activation state.
797
+ * Mirrors ProjectController.listEnvironments.
798
+ */
799
+ async listEnvironments(projectId, options = {}) {
800
+ this._requireReady("listEnvironments");
801
+ if (!projectId) {
802
+ throw new Error("Project ID is required");
803
+ }
804
+ const { headers } = options;
805
+ try {
806
+ const response = await this._request(`/projects/${projectId}/environments`, {
807
+ method: "GET",
808
+ ...headers ? { headers } : {},
809
+ methodName: "listEnvironments"
810
+ });
811
+ if (response && response.success) {
812
+ return response.data;
813
+ }
814
+ throw new Error(response.message);
815
+ } catch (error) {
816
+ throw new Error(`Failed to list environments: ${error.message}`, { cause: error });
817
+ }
818
+ }
819
+ /**
820
+ * Activate multi-environment support for a project.
821
+ * Optional `force` will reconfigure DNS/TLS even if already active.
822
+ * Mirrors ProjectController.activateMultipleEnvironments.
823
+ */
824
+ async activateMultipleEnvironments(projectId, options = {}) {
825
+ this._requireReady("activateMultipleEnvironments");
826
+ if (!projectId) {
827
+ throw new Error("Project ID is required");
828
+ }
829
+ const { force = false, headers } = options;
830
+ try {
831
+ const response = await this._request(`/projects/${projectId}/environments/activate`, {
832
+ method: "POST",
833
+ body: JSON.stringify({ ...force ? { force: true } : {} }),
834
+ ...headers ? { headers } : {},
835
+ methodName: "activateMultipleEnvironments"
836
+ });
837
+ if (response && response.success) {
838
+ return response.data;
839
+ }
840
+ throw new Error(response.message);
841
+ } catch (error) {
842
+ throw new Error(
843
+ `Failed to activate multiple environments: ${error.message}`,
844
+ { cause: error }
845
+ );
846
+ }
847
+ }
848
+ /**
849
+ * Create or update (upsert) an environment config for a project.
850
+ * Mirrors ProjectController.upsertEnvironment.
851
+ */
852
+ async upsertEnvironment(projectId, envKey, config, options = {}) {
853
+ this._requireReady("upsertEnvironment");
854
+ if (!projectId) {
855
+ throw new Error("Project ID is required");
856
+ }
857
+ if (!envKey) {
858
+ throw new Error("Environment key is required");
859
+ }
860
+ if (!config || typeof config !== "object") {
861
+ throw new Error("Environment config object is required");
862
+ }
863
+ const { headers } = options;
864
+ try {
865
+ const response = await this._request(`/projects/${projectId}/environments`, {
866
+ method: "POST",
867
+ body: JSON.stringify({ envKey, config }),
868
+ ...headers ? { headers } : {},
869
+ methodName: "upsertEnvironment"
870
+ });
871
+ if (response && response.success) {
872
+ return response.data;
873
+ }
874
+ throw new Error(response.message);
875
+ } catch (error) {
876
+ throw new Error(`Failed to upsert environment: ${error.message}`, { cause: error });
877
+ }
878
+ }
879
+ /**
880
+ * Update an existing environment config.
881
+ * Mirrors ProjectController.updateEnvironment.
882
+ */
883
+ async updateEnvironment(projectId, envKey, updates, options = {}) {
884
+ this._requireReady("updateEnvironment");
885
+ if (!projectId) {
886
+ throw new Error("Project ID is required");
887
+ }
888
+ if (!envKey) {
889
+ throw new Error("Environment key is required");
890
+ }
891
+ if (!updates || typeof updates !== "object") {
892
+ throw new Error("Environment updates object is required");
893
+ }
894
+ const { headers } = options;
895
+ try {
896
+ const response = await this._request(
897
+ `/projects/${projectId}/environments/${encodeURIComponent(envKey)}`,
898
+ {
899
+ method: "PATCH",
900
+ body: JSON.stringify(updates),
901
+ ...headers ? { headers } : {},
902
+ methodName: "updateEnvironment"
903
+ }
904
+ );
905
+ if (response && response.success) {
906
+ return response.data;
907
+ }
908
+ throw new Error(response.message);
909
+ } catch (error) {
910
+ throw new Error(`Failed to update environment: ${error.message}`, { cause: error });
911
+ }
912
+ }
913
+ /**
914
+ * Publish a project to a specific environment (set its effective mode/version/branch).
915
+ * Mirrors ProjectController.publishToEnvironment.
916
+ */
917
+ async publishToEnvironment(projectId, envKey, payload, options = {}) {
918
+ this._requireReady("publishToEnvironment");
919
+ if (!projectId) {
920
+ throw new Error("Project ID is required");
921
+ }
922
+ if (!envKey) {
923
+ throw new Error("Environment key is required");
924
+ }
925
+ if (!payload || typeof payload !== "object") {
926
+ throw new Error("Publish payload is required");
927
+ }
928
+ const { headers } = options;
929
+ try {
930
+ const response = await this._request(
931
+ `/projects/${projectId}/environments/${encodeURIComponent(envKey)}/publish`,
932
+ {
933
+ method: "POST",
934
+ body: JSON.stringify(payload),
935
+ ...headers ? { headers } : {},
936
+ methodName: "publishToEnvironment"
937
+ }
938
+ );
939
+ if (response && response.success) {
940
+ return response.data;
941
+ }
942
+ throw new Error(response.message);
943
+ } catch (error) {
944
+ throw new Error(`Failed to publish to environment: ${error.message}`, { cause: error });
945
+ }
946
+ }
947
+ /**
948
+ * Delete an environment from a project.
949
+ * Mirrors ProjectController.deleteEnvironment.
950
+ */
951
+ async deleteEnvironment(projectId, envKey, options = {}) {
952
+ this._requireReady("deleteEnvironment");
953
+ if (!projectId) {
954
+ throw new Error("Project ID is required");
955
+ }
956
+ if (!envKey) {
957
+ throw new Error("Environment key is required");
958
+ }
959
+ const { headers } = options;
960
+ try {
961
+ const response = await this._request(
962
+ `/projects/${projectId}/environments/${encodeURIComponent(envKey)}`,
963
+ {
964
+ method: "DELETE",
965
+ ...headers ? { headers } : {},
966
+ methodName: "deleteEnvironment"
967
+ }
968
+ );
969
+ if (response && response.success) {
970
+ return response.data;
971
+ }
972
+ throw new Error(response.message);
973
+ } catch (error) {
974
+ throw new Error(`Failed to delete environment: ${error.message}`, { cause: error });
975
+ }
976
+ }
977
+ /**
978
+ * Promote content between environments (simple pipeline).
979
+ * Mirrors ProjectController.promoteEnvironment.
980
+ */
981
+ async promoteEnvironment(projectId, fromEnvKey, toEnvKey, options = {}) {
982
+ this._requireReady("promoteEnvironment");
983
+ if (!projectId) {
984
+ throw new Error("Project ID is required");
985
+ }
986
+ if (!fromEnvKey || !toEnvKey) {
987
+ throw new Error("Both fromEnvKey and toEnvKey are required");
988
+ }
989
+ if (fromEnvKey === toEnvKey) {
990
+ throw new Error("fromEnvKey and toEnvKey must be different");
991
+ }
992
+ const { headers } = options;
993
+ try {
994
+ const response = await this._request(`/projects/${projectId}/pipeline/promote`, {
995
+ method: "POST",
996
+ body: JSON.stringify({ from: fromEnvKey, to: toEnvKey }),
997
+ ...headers ? { headers } : {},
998
+ methodName: "promoteEnvironment"
999
+ });
1000
+ if (response && response.success) {
1001
+ return response.data;
1002
+ }
1003
+ throw new Error(response.message);
1004
+ } catch (error) {
1005
+ throw new Error(`Failed to promote environment: ${error.message}`, { cause: error });
1006
+ }
1007
+ }
655
1008
  /**
656
1009
  * Restore project to a previous version
657
1010
  * Replaces: SymstoryService.restoreVersion()
@@ -83,10 +83,20 @@ const SERVICE_METHODS = {
83
83
  duplicateProject: "project",
84
84
  removeProject: "project",
85
85
  checkProjectKeyAvailability: "project",
86
+ getProjectRolePermissionsConfig: "project",
87
+ updateProjectRolePermissionsConfig: "project",
88
+ listEnvironments: "project",
89
+ activateMultipleEnvironments: "project",
90
+ upsertEnvironment: "project",
91
+ updateEnvironment: "project",
92
+ publishToEnvironment: "project",
93
+ deleteEnvironment: "project",
94
+ promoteEnvironment: "project",
86
95
  // Project member methods (moved to project service)
87
96
  getProjectMembers: "project",
88
97
  inviteMember: "project",
89
98
  acceptInvite: "project",
99
+ createMagicInviteLink: "project",
90
100
  updateMemberRole: "project",
91
101
  removeMember: "project",
92
102
  // Project library methods (moved to project service)
@@ -104,6 +114,8 @@ const SERVICE_METHODS = {
104
114
  setProjectValue: "project",
105
115
  addProjectItems: "project",
106
116
  getProjectItemByPath: "project",
117
+ setProjectAccess: "project",
118
+ setProjectVisibility: "project",
107
119
  // Favorite project methods (moved to project service)
108
120
  getFavoriteProjects: "project",
109
121
  addFavoriteProject: "project",
@@ -169,7 +181,6 @@ const SERVICE_METHODS = {
169
181
  getDnsRecord: "dns",
170
182
  removeDnsRecord: "dns",
171
183
  getCustomHost: "dns",
172
- setProjectDomains: "dns",
173
184
  addProjectCustomDomains: "dns",
174
185
  validateDomain: "dns",
175
186
  createDnsRecordWithValidation: "dns",