@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.
Files changed (183) hide show
  1. package/README.md +141 -0
  2. package/dist/cjs/config/environment.js +94 -10
  3. package/dist/cjs/index.js +152 -12
  4. package/dist/cjs/services/AdminService.js +351 -0
  5. package/dist/cjs/services/AuthService.js +738 -305
  6. package/dist/cjs/services/BaseService.js +158 -6
  7. package/dist/cjs/services/BranchService.js +484 -0
  8. package/dist/cjs/services/CollabService.js +439 -116
  9. package/dist/cjs/services/DnsService.js +340 -0
  10. package/dist/cjs/services/FeatureFlagService.js +175 -0
  11. package/dist/cjs/services/FileService.js +201 -0
  12. package/dist/cjs/services/IntegrationService.js +538 -0
  13. package/dist/cjs/services/MetricsService.js +62 -0
  14. package/dist/cjs/services/PaymentService.js +271 -0
  15. package/dist/cjs/services/PlanService.js +426 -0
  16. package/dist/cjs/services/ProjectService.js +1207 -0
  17. package/dist/cjs/services/PullRequestService.js +503 -0
  18. package/dist/cjs/services/ScreenshotService.js +304 -0
  19. package/dist/cjs/services/SubscriptionService.js +396 -0
  20. package/dist/cjs/services/TrackingService.js +661 -0
  21. package/dist/cjs/services/WaitlistService.js +148 -0
  22. package/dist/cjs/services/index.js +60 -4
  23. package/dist/cjs/state/RootStateManager.js +2 -23
  24. package/dist/cjs/state/rootEventBus.js +9 -0
  25. package/dist/cjs/utils/CollabClient.js +78 -12
  26. package/dist/cjs/utils/TokenManager.js +16 -3
  27. package/dist/cjs/utils/changePreprocessor.js +199 -0
  28. package/dist/cjs/utils/jsonDiff.js +46 -4
  29. package/dist/cjs/utils/ordering.js +309 -0
  30. package/dist/cjs/utils/services.js +285 -128
  31. package/dist/cjs/utils/validation.js +0 -3
  32. package/dist/esm/config/environment.js +94 -10
  33. package/dist/esm/index.js +47862 -18248
  34. package/dist/esm/services/AdminService.js +1132 -0
  35. package/dist/esm/services/AuthService.js +1493 -386
  36. package/dist/esm/services/BaseService.js +757 -6
  37. package/dist/esm/services/BranchService.js +1265 -0
  38. package/dist/esm/services/CollabService.js +24956 -16089
  39. package/dist/esm/services/DnsService.js +1121 -0
  40. package/dist/esm/services/FeatureFlagService.js +956 -0
  41. package/dist/esm/services/FileService.js +982 -0
  42. package/dist/esm/services/IntegrationService.js +1319 -0
  43. package/dist/esm/services/MetricsService.js +843 -0
  44. package/dist/esm/services/PaymentService.js +1052 -0
  45. package/dist/esm/services/PlanService.js +1207 -0
  46. package/dist/esm/services/ProjectService.js +2526 -0
  47. package/dist/esm/services/PullRequestService.js +1284 -0
  48. package/dist/esm/services/ScreenshotService.js +1085 -0
  49. package/dist/esm/services/SubscriptionService.js +1177 -0
  50. package/dist/esm/services/TrackingService.js +18454 -0
  51. package/dist/esm/services/WaitlistService.js +929 -0
  52. package/dist/esm/services/index.js +47373 -18027
  53. package/dist/esm/state/RootStateManager.js +11 -23
  54. package/dist/esm/state/rootEventBus.js +9 -0
  55. package/dist/esm/utils/CollabClient.js +17526 -16120
  56. package/dist/esm/utils/TokenManager.js +16 -3
  57. package/dist/esm/utils/changePreprocessor.js +542 -0
  58. package/dist/esm/utils/jsonDiff.js +958 -43
  59. package/dist/esm/utils/ordering.js +291 -0
  60. package/dist/esm/utils/services.js +285 -128
  61. package/dist/esm/utils/validation.js +116 -50
  62. package/dist/node/config/environment.js +94 -10
  63. package/dist/node/index.js +183 -16
  64. package/dist/node/services/AdminService.js +332 -0
  65. package/dist/node/services/AuthService.js +742 -310
  66. package/dist/node/services/BaseService.js +148 -6
  67. package/dist/node/services/BranchService.js +465 -0
  68. package/dist/node/services/CollabService.js +439 -116
  69. package/dist/node/services/DnsService.js +321 -0
  70. package/dist/node/services/FeatureFlagService.js +156 -0
  71. package/dist/node/services/FileService.js +182 -0
  72. package/dist/node/services/IntegrationService.js +519 -0
  73. package/dist/node/services/MetricsService.js +43 -0
  74. package/dist/node/services/PaymentService.js +252 -0
  75. package/dist/node/services/PlanService.js +407 -0
  76. package/dist/node/services/ProjectService.js +1188 -0
  77. package/dist/node/services/PullRequestService.js +484 -0
  78. package/dist/node/services/ScreenshotService.js +285 -0
  79. package/dist/node/services/SubscriptionService.js +377 -0
  80. package/dist/node/services/TrackingService.js +632 -0
  81. package/dist/node/services/WaitlistService.js +129 -0
  82. package/dist/node/services/index.js +60 -4
  83. package/dist/node/state/RootStateManager.js +2 -23
  84. package/dist/node/state/rootEventBus.js +9 -0
  85. package/dist/node/utils/CollabClient.js +77 -11
  86. package/dist/node/utils/TokenManager.js +16 -3
  87. package/dist/node/utils/changePreprocessor.js +180 -0
  88. package/dist/node/utils/jsonDiff.js +46 -4
  89. package/dist/node/utils/ordering.js +290 -0
  90. package/dist/node/utils/services.js +285 -128
  91. package/dist/node/utils/validation.js +0 -3
  92. package/package.json +30 -18
  93. package/src/config/environment.js +95 -10
  94. package/src/index.js +190 -23
  95. package/src/services/AdminService.js +374 -0
  96. package/src/services/AuthService.js +874 -328
  97. package/src/services/BaseService.js +166 -6
  98. package/src/services/BranchService.js +536 -0
  99. package/src/services/CollabService.js +557 -148
  100. package/src/services/DnsService.js +366 -0
  101. package/src/services/FeatureFlagService.js +174 -0
  102. package/src/services/FileService.js +213 -0
  103. package/src/services/IntegrationService.js +548 -0
  104. package/src/services/MetricsService.js +40 -0
  105. package/src/services/PaymentService.js +287 -0
  106. package/src/services/PlanService.js +468 -0
  107. package/src/services/ProjectService.js +1366 -0
  108. package/src/services/PullRequestService.js +537 -0
  109. package/src/services/ScreenshotService.js +258 -0
  110. package/src/services/SubscriptionService.js +425 -0
  111. package/src/services/TrackingService.js +853 -0
  112. package/src/services/WaitlistService.js +130 -0
  113. package/src/services/index.js +79 -5
  114. package/src/services/tests/BranchService/createBranch.test.js +153 -0
  115. package/src/services/tests/BranchService/deleteBranch.test.js +173 -0
  116. package/src/services/tests/BranchService/getBranchChanges.test.js +146 -0
  117. package/src/services/tests/BranchService/listBranches.test.js +87 -0
  118. package/src/services/tests/BranchService/mergeBranch.test.js +210 -0
  119. package/src/services/tests/BranchService/publishVersion.test.js +183 -0
  120. package/src/services/tests/BranchService/renameBranch.test.js +240 -0
  121. package/src/services/tests/BranchService/resetBranch.test.js +152 -0
  122. package/src/services/tests/FeatureFlagService/adminFeatureFlags.test.js +67 -0
  123. package/src/services/tests/FeatureFlagService/getFeatureFlags.test.js +75 -0
  124. package/src/services/tests/FileService/createFileFormData.test.js +74 -0
  125. package/src/services/tests/FileService/getFileUrl.test.js +69 -0
  126. package/src/services/tests/FileService/updateProjectIcon.test.js +109 -0
  127. package/src/services/tests/FileService/uploadDocument.test.js +36 -0
  128. package/src/services/tests/FileService/uploadFile.test.js +78 -0
  129. package/src/services/tests/FileService/uploadFileWithValidation.test.js +114 -0
  130. package/src/services/tests/FileService/uploadImage.test.js +36 -0
  131. package/src/services/tests/FileService/uploadMultipleFiles.test.js +111 -0
  132. package/src/services/tests/FileService/validateFile.test.js +63 -0
  133. package/src/services/tests/PlanService/createPlan.test.js +104 -0
  134. package/src/services/tests/PlanService/createPlanWithValidation.test.js +523 -0
  135. package/src/services/tests/PlanService/deletePlan.test.js +92 -0
  136. package/src/services/tests/PlanService/getActivePlans.test.js +123 -0
  137. package/src/services/tests/PlanService/getAdminPlans.test.js +84 -0
  138. package/src/services/tests/PlanService/getPlan.test.js +50 -0
  139. package/src/services/tests/PlanService/getPlanByKey.test.js +109 -0
  140. package/src/services/tests/PlanService/getPlanWithValidation.test.js +85 -0
  141. package/src/services/tests/PlanService/getPlans.test.js +53 -0
  142. package/src/services/tests/PlanService/getPlansByPriceRange.test.js +109 -0
  143. package/src/services/tests/PlanService/getPlansWithValidation.test.js +48 -0
  144. package/src/services/tests/PlanService/initializePlans.test.js +75 -0
  145. package/src/services/tests/PlanService/updatePlan.test.js +111 -0
  146. package/src/services/tests/PlanService/updatePlanWithValidation.test.js +556 -0
  147. package/src/state/RootStateManager.js +37 -32
  148. package/src/state/rootEventBus.js +19 -0
  149. package/src/utils/CollabClient.js +99 -12
  150. package/src/utils/TokenManager.js +20 -3
  151. package/src/utils/changePreprocessor.js +239 -0
  152. package/src/utils/jsonDiff.js +40 -5
  153. package/src/utils/ordering.js +271 -0
  154. package/src/utils/services.js +306 -139
  155. package/src/utils/validation.js +0 -3
  156. package/dist/cjs/services/AIService.js +0 -155
  157. package/dist/cjs/services/BasedService.js +0 -1185
  158. package/dist/cjs/services/CoreService.js +0 -2295
  159. package/dist/cjs/services/SocketService.js +0 -309
  160. package/dist/cjs/services/SymstoryService.js +0 -571
  161. package/dist/cjs/utils/basedQuerys.js +0 -181
  162. package/dist/cjs/utils/symstoryClient.js +0 -259
  163. package/dist/esm/services/AIService.js +0 -185
  164. package/dist/esm/services/BasedService.js +0 -5262
  165. package/dist/esm/services/CoreService.js +0 -2827
  166. package/dist/esm/services/SocketService.js +0 -456
  167. package/dist/esm/services/SymstoryService.js +0 -7025
  168. package/dist/esm/utils/basedQuerys.js +0 -163
  169. package/dist/esm/utils/symstoryClient.js +0 -354
  170. package/dist/node/services/AIService.js +0 -136
  171. package/dist/node/services/BasedService.js +0 -1156
  172. package/dist/node/services/CoreService.js +0 -2266
  173. package/dist/node/services/SocketService.js +0 -280
  174. package/dist/node/services/SymstoryService.js +0 -542
  175. package/dist/node/utils/basedQuerys.js +0 -162
  176. package/dist/node/utils/symstoryClient.js +0 -230
  177. package/src/services/AIService.js +0 -150
  178. package/src/services/BasedService.js +0 -1302
  179. package/src/services/CoreService.js +0 -2548
  180. package/src/services/SocketService.js +0 -336
  181. package/src/services/SymstoryService.js +0 -649
  182. package/src/utils/basedQuerys.js +0 -164
  183. package/src/utils/symstoryClient.js +0 -252
@@ -1,1302 +0,0 @@
1
- import { BaseService } from './BaseService.js'
2
- import { buildProjectQuery, buildUserQuery, buildGetProjectsByKeysQuery, buildGetUserDataQuery, buildGetProjectDataQuery, buildGetProjectByKeyDataQuery } from '../utils/basedQuerys.js'
3
- import Based from '@based/client'
4
- import { isFunction, isString } from '@domql/utils'
5
- import environment from '../config/environment.js'
6
-
7
- // DEPRECATED
8
- export class BasedService extends BaseService {
9
- constructor (config) {
10
- super(config)
11
- this._client = null
12
- this._subscriptions = new Map()
13
- }
14
-
15
- init ({ context }) {
16
- try {
17
- const { env, org, project } = context.based || {
18
- env: environment.basedEnv,
19
- org: environment.basedOrg,
20
- project: environment.basedProject
21
- }
22
-
23
- if (!env || !org || !project) {
24
- throw new Error('Based configuration missing required parameters')
25
- }
26
-
27
- this._client = new Based({
28
- env,
29
- org,
30
- project
31
- })
32
-
33
- this._info = {
34
- config: {
35
- env,
36
- org: this._maskString(org),
37
- project: this._maskString(project)
38
- }
39
- }
40
-
41
- this._setReady()
42
- } catch (error) {
43
- this._setError(error)
44
- throw error
45
- }
46
- }
47
-
48
- // Helper method to mask sensitive strings
49
-
50
- _maskString (str) {
51
- if (!str) {
52
- return ''
53
- }
54
- return `${str.substr(0, 4)}...${str.substr(-4)}`
55
- }
56
-
57
- updateContext (context) {
58
- this._context = { ...this._context, ...context }
59
- if (this._context.authToken && this._context.user?.id) {
60
- this.setAuthState(this._context.authToken, this._context.user.id)
61
- }
62
- }
63
-
64
- async setAuthState (authState) {
65
- this._requireReady()
66
- const newAuthState = {
67
- ...authState,
68
- persistent: true
69
- }
70
- try {
71
- return await this._client.setAuthState(newAuthState)
72
- } catch (error) {
73
- throw new Error(`Failed to set auth state: ${error.message}`)
74
- }
75
- }
76
-
77
- async setBucket (bucketId, callback) {
78
- this._requireReady()
79
-
80
- if (!isString(bucketId)) {
81
- throw new Error('Invalid type of bucket ID', bucketId)
82
- }
83
- if (!this._context.project) {
84
- throw new Error('Project is undefined')
85
- }
86
- try {
87
- const obj = {
88
- $id: this._context.project.id, // TODO: change to getProjectId
89
- bucket: bucketId
90
- }
91
- if (isFunction(callback)) {
92
- const data = await this._client.call('db:set', obj)
93
- return callback(data)
94
- }
95
- return await this._client.call('db:set', obj)
96
- } catch (error) {
97
- throw new Error(`Failed to set bucket: ${error.message}`)
98
- }
99
- }
100
-
101
- async setUserForced (userId, obj) {
102
- this._requireReady()
103
-
104
- try {
105
- await this._client
106
- .query('db', {
107
- $id: obj.projectId,
108
- members: {
109
- $list: true,
110
- user: {
111
- id: true
112
- }
113
- }
114
- })
115
- .get()
116
-
117
- // Create ProjectMember entry
118
- const { id: membershipId } = await this._client.call('db:set', {
119
- type: 'projectMember',
120
- user: userId,
121
- project: obj.projectId,
122
- role: obj.role,
123
- joinedAt: Date.now()
124
- })
125
-
126
- return await Promise.all([
127
- this._client.call('db:set', {
128
- $id: userId,
129
- memberProjects: { $add: membershipId }
130
- }),
131
- this._client.call('db:set', {
132
- $id: obj.projectId,
133
- members: { $add: membershipId }
134
- })
135
- ])
136
- } catch (error) {
137
- throw new Error(`Failed to set bucket: ${error.message}`)
138
- }
139
- }
140
-
141
- async query (collection, query, options = {}) {
142
- this._requireReady()
143
- try {
144
- return await this._client
145
- .query(collection, query, {
146
- ...options,
147
- context: this._context
148
- })
149
- .get()
150
- } catch (error) {
151
- throw new Error(`Query failed: ${error.message}`)
152
- }
153
- }
154
-
155
- async setProject (params) {
156
- this._requireReady()
157
- try {
158
- return await this._client.call('db:set', {
159
- type: 'project',
160
- ...params
161
- })
162
- } catch (error) {
163
- throw new Error(`Query failed: ${error.message}`)
164
- }
165
- }
166
-
167
- async setUser (params) {
168
- this._requireReady()
169
- try {
170
- return await this._client.call('db:set', {
171
- type: 'user',
172
- ...params
173
- })
174
- } catch (error) {
175
- throw new Error(`Query failed: ${error.message}`)
176
- }
177
- }
178
-
179
- // DEPRECATED
180
- async fetchUser (userId) {
181
- if (!userId) {
182
- throw new Error('User Id is required')
183
- }
184
- return await this.query('db', buildUserQuery(userId))
185
- }
186
-
187
- async getUser (userId) {
188
- if (!userId) {
189
- throw new Error("UserId is required")
190
- }
191
-
192
- // Get user data and memberProjects in a single query
193
- const userData = await this._client
194
- .query("db", buildGetUserDataQuery(userId))
195
- .get()
196
-
197
- // Extract user data
198
- const user = {
199
- id: userData.id,
200
- name: userData.name,
201
- email: userData.email,
202
- username: userData.username,
203
- globalRole: userData.globalRole,
204
- createdAt: userData.createdAt,
205
- updatedAt: userData.updatedAt
206
- }
207
-
208
- if (!user) {
209
- throw new Error("User not found")
210
- }
211
-
212
- let memberProjects = []
213
-
214
- if (userData.memberProjects && userData.memberProjects.length > 0) {
215
- // Extract project keys from the direct query
216
- const projectKeys = userData.memberProjects
217
- .filter(membership => membership.project && membership.project.key)
218
- .map(membership => membership.project.key)
219
-
220
- if (projectKeys.length > 0) {
221
- // Fetch projects in chunks to avoid PayloadTooLarge errors
222
- const allProjects = await this._fetchProjectsByKeysInChunks(projectKeys)
223
-
224
- // Map the project data with original membership data
225
- memberProjects = userData.memberProjects
226
- .filter(membership => membership.project && membership.project.key)
227
- .map(membership => {
228
- const projectKey = membership.project.key
229
- const correctProject = allProjects.find(
230
- p => p.key === projectKey
231
- )
232
-
233
- return {
234
- project: correctProject || membership.project,
235
- role: membership.role,
236
- updatedAt: membership.updatedAt,
237
- createdAt: membership.createdAt
238
- }
239
- })
240
- }
241
- } else {
242
- console.log(`[getUser] No member projects found with ID: ${userId}`)
243
- }
244
-
245
- // Format projects data
246
- const formattedProjects =
247
- memberProjects
248
- .filter(membership => membership.project)
249
- .map(membership => ({
250
- id: membership.project.id,
251
- name: membership.project.name,
252
- key: membership.project.key,
253
- thumbnail: membership.project.thumbnail,
254
- icon: membership.project.icon,
255
- tier: membership.project.tier,
256
- visibility: membership.project.visibility,
257
- access: membership.project.access,
258
- role: membership.role,
259
- joinedAt: membership.createdAt,
260
- updatedAt: membership.updatedAt,
261
- members: membership.project.members
262
- })) || []
263
-
264
- return {
265
- id: userId,
266
- name: user.name,
267
- email: user.email,
268
- username: user.username,
269
- globalRole: user.globalRole,
270
- projects: formattedProjects,
271
- createdAt: user.createdAt,
272
- updatedAt: user.updatedAt
273
- }
274
- }
275
-
276
- /**
277
- * Fetches projects by keys in chunks with adaptive chunk sizing
278
- * @param {Array<string>} allKeys - All project keys to fetch
279
- * @returns {Promise<Array>} - All projects found
280
- */
281
- async _fetchProjectsByKeysInChunks(allKeys) {
282
- if (!allKeys.length) {return []}
283
-
284
- // Initial chunk size and limits
285
- const INITIAL_CHUNK_SIZE = 50
286
- const MAX_CHUNK_SIZE = 1000
287
- const MIN_CHUNK_SIZE = 10
288
-
289
- // Track the optimal chunk size as we learn from responses
290
- const optimalChunkSize = INITIAL_CHUNK_SIZE
291
-
292
- /**
293
- * Recursively process chunks of keys with adaptive sizing
294
- * @param {Array<string>} keys - Keys to process
295
- * @param {number} size - Current chunk size
296
- * @returns {Promise<Array>} - Projects found
297
- */
298
- const processChunks = async (keys, size) => {
299
- if (!keys.length) {return []}
300
-
301
- const chunks = []
302
- for (let i = 0; i < keys.length; i += size) {
303
- chunks.push(keys.slice(i, i + size))
304
- }
305
-
306
- try {
307
- const result = await this._client
308
- .query("db", buildGetProjectsByKeysQuery(chunks[0]))
309
- .get()
310
-
311
- const newSize = Math.min(Math.floor(size * 1.5), MAX_CHUNK_SIZE)
312
-
313
- const firstChunkProjects = result.projects || []
314
-
315
- const remainingKeys = keys.slice(chunks[0].length)
316
- const remainingProjects = await processChunks(remainingKeys, newSize)
317
-
318
- return [...firstChunkProjects, ...remainingProjects]
319
- } catch (error) {
320
- if (error.message && error.message.includes('PayloadTooLarge')) {
321
- const newSize = Math.max(Math.floor(size / 2), MIN_CHUNK_SIZE)
322
- console.warn(`Reducing chunk size to ${newSize} due to PayloadTooLarge error`)
323
-
324
- if (newSize === MIN_CHUNK_SIZE && chunks[0].length <= MIN_CHUNK_SIZE) {
325
- console.error(`Cannot process chunk, skipping ${chunks[0].length} keys`)
326
- const remainingKeys = keys.slice(chunks[0].length)
327
- return processChunks(remainingKeys, newSize)
328
- }
329
-
330
- return processChunks(keys, newSize)
331
- }
332
- console.error(`Error fetching projects: ${error.message}`)
333
- const remainingKeys = keys.slice(chunks[0].length)
334
- return processChunks(remainingKeys, size)
335
-
336
- }
337
- }
338
-
339
- return await processChunks(allKeys, optimalChunkSize)
340
- }
341
-
342
- async getUserByEmail (email) {
343
- this._requireReady()
344
- if (!email) {
345
- throw new Error('Email is required')
346
- }
347
- try {
348
- return await this.call('users:get-by', { email })
349
- } catch (error) {
350
- throw new Error(`Failed to get user: ${error.message}`)
351
- }
352
- }
353
-
354
- async setProjectDomains (projectId, domains) {
355
- this._requireReady()
356
- if (!projectId) {
357
- throw new Error('Project ID is required')
358
- }
359
- try {
360
- return await this.call('projects:update-domains', { projectId, domains })
361
- } catch (error) {
362
- throw new Error(`Failed to set project domains: ${error.message}`)
363
- }
364
- }
365
-
366
- async checkProjectKeyAvailability (key) {
367
- this._requireReady()
368
- try {
369
- return await this.call('projects:check-key', { key })
370
- } catch (error) {
371
- throw new Error(
372
- `Failed to check project key availability: ${error.message}`
373
- )
374
- }
375
- }
376
-
377
- async removeProject (projectId) {
378
- this._requireReady()
379
- if (!projectId) {
380
- throw new Error('Project ID is required')
381
- }
382
- try {
383
- return await this.call('projects:remove', { projectId })
384
- } catch (error) {
385
- throw new Error(`Failed to remove project: ${error.message}`)
386
- }
387
- }
388
-
389
- async getAvailableLibraries (params) {
390
- this._requireReady()
391
- const defaultParams = {
392
- page: 1,
393
- limit: 20,
394
- search: '',
395
- framework: '',
396
- language: ''
397
- }
398
- try {
399
- return await this.call('projects:get-available-libraries', {
400
- ...defaultParams,
401
- ...params
402
- })
403
- } catch (error) {
404
- throw new Error(`Failed to get available libraries: ${error.message}`)
405
- }
406
- }
407
-
408
- async addProjectLibraries (projectId, libraryIds) {
409
- this._requireReady()
410
- if (!projectId) {
411
- throw new Error('Project ID is required')
412
- }
413
- try {
414
- return await this.call('projects:add-libraries', {
415
- projectId,
416
- libraryIds
417
- })
418
- } catch (error) {
419
- throw new Error(`Failed to add project libraries: ${error.message}`)
420
- }
421
- }
422
-
423
- async removeProjectLibraries (projectId, libraryIds) {
424
- this._requireReady()
425
- if (!projectId) {
426
- throw new Error('Project ID is required')
427
- }
428
- try {
429
- return await this.call('projects:remove-libraries', {
430
- projectId,
431
- libraryIds
432
- })
433
- } catch (error) {
434
- throw new Error(`Failed to remove project libraries: ${error.message}`)
435
- }
436
- }
437
-
438
- async getProjectLibraries (projectId) {
439
- this._requireReady()
440
- if (!projectId) {
441
- throw new Error('Project ID is required')
442
- }
443
- try {
444
- return await this.call('projects:get-libraries', { projectId })
445
- } catch (error) {
446
- throw new Error(`Failed to get project libraries: ${error.message}`)
447
- }
448
- }
449
-
450
- subscribe (collection, query, callback, options = {}) {
451
- this._requireReady()
452
- const subscriptionKey = JSON.stringify({ collection, query })
453
-
454
- if (this._subscriptions.has(subscriptionKey)) {
455
- return this._subscriptions.get(subscriptionKey)
456
- }
457
-
458
- try {
459
- const unsubscribe = this._client
460
- .query(collection, query, {
461
- ...options,
462
- context: this._context
463
- })
464
- .subscribe(callback)
465
-
466
- this._subscriptions.set(subscriptionKey, unsubscribe)
467
-
468
- return () => {
469
- unsubscribe()
470
- this._subscriptions.delete(subscriptionKey)
471
- }
472
- } catch (error) {
473
- throw new Error(`Subscription failed: ${error.message}`)
474
- }
475
- }
476
-
477
- subscribeChannel (name, params, callback) {
478
- this._requireReady()
479
- try {
480
- return this._client.channel(name, params).subscribe(callback)
481
- } catch (error) {
482
- throw new Error(`Channel subscription failed: ${error.message}`)
483
- }
484
- }
485
-
486
- publishToChannel (name, params, data) {
487
- this._requireReady()
488
- try {
489
- return this._client.channel(name, params).publish(data)
490
- } catch (error) {
491
- throw new Error(`Channel publish failed: ${error.message}`)
492
- }
493
- }
494
-
495
- async call (functionName, params = {}) {
496
- this._requireReady()
497
- try {
498
- return await this._client.call(functionName, params)
499
- } catch (error) {
500
- throw new Error(`Function call failed: ${error.message}`)
501
- }
502
- }
503
-
504
- async updateSchema (schema) {
505
- this._requireReady()
506
- try {
507
- return await this._client.call('db:update-schema', schema)
508
- } catch (error) {
509
- throw new Error(`Schema update failed: ${error.message}`)
510
- }
511
- }
512
-
513
- async createProject (projectData) {
514
- this._requireReady()
515
-
516
- try {
517
- return await this.call('projects:create', projectData)
518
- } catch (error) {
519
- throw new Error(`Failed to create project: ${error.message}`)
520
- }
521
- }
522
-
523
- async getProject (projectId) {
524
- this._requireReady()
525
- if (!projectId) {
526
- throw new Error('Project ID is required')
527
- }
528
- try {
529
- return await this._client
530
- .query("db", buildGetProjectDataQuery(projectId))
531
- .get()
532
- } catch (error) {
533
- throw new Error(`Failed to get project: ${error.message}`)
534
- }
535
- }
536
-
537
- async getProjectByKey (key) {
538
- this._requireReady()
539
- try {
540
- return await this._client
541
- .query("db", buildGetProjectByKeyDataQuery(key))
542
- .get()
543
- } catch (error) {
544
- throw new Error(`Failed to get project by key: ${error.message}`)
545
- }
546
- }
547
-
548
- // DEPRECATED
549
- async fetchProject (projectId) {
550
- this._requireReady()
551
- if (!projectId) {
552
- throw new Error('Project ID is required')
553
- }
554
- return await this.query('db', buildProjectQuery(projectId))
555
- }
556
-
557
- async chooseProject ({
558
- username = this._context.user?.username,
559
- projectId,
560
- activeProject
561
- }) {
562
- this._requireReady()
563
- try {
564
- await this.call('fetchProject', {
565
- username,
566
- projectId,
567
- activeProject
568
- })
569
- await this._client.call('setCookie', 'activeProject', activeProject)
570
- } catch (error) {
571
- throw new Error(`Failed to choose project: ${error.message}`)
572
- }
573
- }
574
-
575
- destroy () {
576
- for (const unsubscribe of this._subscriptions.values()) {
577
- unsubscribe()
578
- }
579
- this._subscriptions.clear()
580
- this._client = null
581
- this._setReady(false)
582
- }
583
-
584
- // New helper methods for state management
585
- async updateState (changes) {
586
- if (!changes || Object.keys(changes).length === 0) {
587
- return
588
- }
589
-
590
- try {
591
- await this._client.call('state:update', changes)
592
- } catch (error) {
593
- throw new Error(`Failed to update state: ${error.message}`)
594
- }
595
- }
596
-
597
- async getState () {
598
- try {
599
- return await this._client.call('state:get')
600
- } catch (error) {
601
- throw new Error(`Failed to get state: ${error.message}`)
602
- }
603
- }
604
-
605
- /**
606
- * Upload a file to the database
607
- * @param {File} file - The file to upload
608
- * @param {Object} options - The options for the upload
609
- * @returns {Promise<string>} The source of the uploaded file
610
- * @example
611
- * const fileInput = document.querySelector('input[type="file"]')
612
- * const file = fileInput.files[0]
613
- * const { id, src } = await basedService.uploadFile(file)
614
- */
615
- async uploadFile (file, options = {}) {
616
- this._requireReady()
617
- if (!file) {
618
- throw new Error('File is required for upload')
619
- }
620
- try {
621
- const { id, src } = await this._client.stream('db:file-upload', {
622
- contents: file,
623
- ...options
624
- })
625
- return { id, src }
626
- } catch (error) {
627
- throw new Error(`File upload failed: ${error.message}`)
628
- }
629
- }
630
-
631
- async checkout ({
632
- projectId,
633
- pkg = 2,
634
- seats = 1,
635
- interval = 'monthly',
636
- plan = 'startup',
637
- successUrl = `${window.location.origin}/success`,
638
- cancelUrl = `${window.location.origin}/pricing`
639
- }) {
640
- this._requireReady()
641
-
642
- const prices = {
643
- 999: { startup: 'unlimited_startup', agency: 'unlimited_agency' },
644
- 2: { monthly: 'starter_monthly', yearly: 'starter_yearly' },
645
- 3: { monthly: 'growth_monthly', yearly: 'growth_yearly' }
646
- }
647
-
648
- if (!projectId) {
649
- throw new Error('Project ID is required for checkout')
650
- }
651
-
652
- if (!prices[pkg]) {
653
- throw new Error(`Invalid package type: ${pkg}`)
654
- }
655
-
656
- try {
657
- const price = prices[pkg][interval] || prices[pkg][plan]
658
- if (!price) {
659
- throw new Error(`Invalid interval/plan combination for package ${pkg}`)
660
- }
661
-
662
- return await this.call('checkout', {
663
- price,
664
- seats,
665
- projectId,
666
- successUrl,
667
- cancelUrl
668
- })
669
- } catch (error) {
670
- throw new Error(`Failed to checkout: ${error.message}`)
671
- }
672
- }
673
-
674
- async updateProject (projectId, data) {
675
- this._requireReady()
676
- try {
677
- return await this.call('projects:update', { projectId, data })
678
- } catch (error) {
679
- throw new Error(`Failed to update project: ${error.message}`)
680
- }
681
- }
682
-
683
- async updateProjectComponents (projectId, components) {
684
- this._requireReady()
685
- try {
686
- return await this.call('projects:update-components', {
687
- projectId,
688
- components
689
- })
690
- } catch (error) {
691
- throw new Error(`Failed to update project components: ${error.message}`)
692
- }
693
- }
694
-
695
- async updateProjectSettings (projectId, settings) {
696
- this._requireReady()
697
- try {
698
- return await this.call('projects:update-settings', {
699
- projectId,
700
- settings
701
- })
702
- } catch (error) {
703
- throw new Error(`Failed to update project settings: ${error.message}`)
704
- }
705
- }
706
-
707
- async updateProjectName (projectId, name) {
708
- this._requireReady()
709
- try {
710
- return await this.call('projects:update', { projectId, name })
711
- } catch (error) {
712
- throw new Error(`Failed to update project name: ${error.message}`)
713
- }
714
- }
715
-
716
- async updateProjectPackage (projectId, pkg) {
717
- this._requireReady()
718
- try {
719
- return await this.call('projects:update', {
720
- projectId,
721
- data: { package: pkg }
722
- })
723
- } catch (error) {
724
- throw new Error(`Failed to update project package: ${error.message}`)
725
- }
726
- }
727
-
728
- /**
729
- * Update the icon of a project
730
- * @param {string} projectId - The ID of the project to update
731
- * @param {id, src} icon - The icon to update the project with
732
- * @returns {Promise<Object>} The updated project
733
- */
734
- async updateProjectIcon (projectId, icon) {
735
- this._requireReady()
736
- try {
737
- return await this.call('projects:update', {
738
- projectId,
739
- data: {
740
- icon: {
741
- $id: icon.id,
742
- src: icon.src
743
- }
744
- }
745
- })
746
- } catch (error) {
747
- throw new Error(`Failed to update project icon: ${error.message}`)
748
- }
749
- }
750
-
751
- async createDnsRecord (domain) {
752
- this._requireReady()
753
- try {
754
- return await this.call('dns:create-record', { domain })
755
- } catch (error) {
756
- throw new Error(`Failed to create DNS record: ${error.message}`)
757
- }
758
- }
759
-
760
- async getDnsRecord (domain) {
761
- this._requireReady()
762
- try {
763
- return await this.call('dns:get-record', { domain })
764
- } catch (error) {
765
- throw new Error(`Failed to get DNS records: ${error.message}`)
766
- }
767
- }
768
-
769
- async removeDnsRecord (domain) {
770
- this._requireReady()
771
- try {
772
- return await this.call('dns:remove-record', { domain })
773
- } catch (error) {
774
- throw new Error(`Failed to delete DNS record: ${error.message}`)
775
- }
776
- }
777
-
778
- async createStorageBucket (key) {
779
- this._requireReady()
780
- try {
781
- const randomString = Math.random().toString(36).slice(2, 15)
782
- const bucket = `symbols-bucket-${key}-${randomString}`
783
- return await this.call('storage:create-bucket', {
784
- bucketName: bucket,
785
- clientName: key.split('.')[0]
786
- })
787
- } catch (error) {
788
- throw new Error(`Failed to create storage bucket: ${error.message}`)
789
- }
790
- }
791
-
792
- async getStorageBucket (bucketName) {
793
- this._requireReady()
794
- try {
795
- return await this.call('storage:get-bucket', { bucketName })
796
- } catch (error) {
797
- throw new Error(`Failed to get storage bucket: ${error.message}`)
798
- }
799
- }
800
-
801
- async removeStorageBucket (bucketName) {
802
- this._requireReady()
803
- try {
804
- return await this.call('storage:remove-bucket', { bucketName })
805
- } catch (error) {
806
- throw new Error(`Failed to remove storage bucket: ${error.message}`)
807
- }
808
- }
809
-
810
- /**
811
- * Request a password change
812
- * @returns {Promise<boolean>} True if the request was successful, false otherwise
813
- */
814
- async requestPasswordChange () {
815
- this._requireReady()
816
- try {
817
- return await this.call('users:request-password-change', {})
818
- } catch (error) {
819
- throw new Error(`Failed to request password change: ${error.message}`)
820
- }
821
- }
822
-
823
- /**
824
- * Confirm a password change
825
- * @param {string} verificationCode - The verification code
826
- * @param {string} newPassword - The new password
827
- * @param {string} confirmPassword - The confirmation password
828
- * @returns {Promise<boolean>} True if the password was changed, false otherwise
829
- */
830
- async confirmPasswordChange (verificationCode, newPassword, confirmPassword) {
831
- try {
832
- return await this.call('users:confirm-password-change', {
833
- verificationCode,
834
- newPassword,
835
- confirmPassword
836
- })
837
- } catch (error) {
838
- throw new Error(`Failed to confirm password change: ${error.message}`)
839
- }
840
- }
841
-
842
- async updateUserProfile (profileData) {
843
- this._requireReady()
844
- try {
845
- return await this.call('users:update-profile', profileData)
846
- } catch (error) {
847
- throw new Error(`Failed to update user profile: ${error.message}`)
848
- }
849
- }
850
-
851
- /**
852
- * Duplicate a project
853
- * @param {string} projectId - The ID of the project to duplicate
854
- * @param {string} newName - The new name of the project (optional)
855
- * @param {string} newKey - The new key of the project (optional)
856
- * @returns {Promise<Object>} The duplicated project
857
- */
858
- async duplicateProject (projectId, newName, newKey, targetUserId) {
859
- this._requireReady()
860
- try {
861
- return await this.call('projects:duplicate', {
862
- projectId,
863
- newName,
864
- newKey,
865
- targetUserId
866
- })
867
- } catch (error) {
868
- throw new Error(`Failed to duplicate project: ${error.message}`)
869
- }
870
- }
871
-
872
- /**
873
- * List available subscription plans
874
- * @param {Object} options - Options for filtering plans
875
- * @param {number} options.page - Page number (default: 1)
876
- * @param {number} options.limit - Number of plans per page (default: 20)
877
- * @param {string} options.status - Filter plans by status (admin only)
878
- * @param {boolean} options.includeSubscriptionCounts - Include subscription counts (admin only)
879
- * @param {string} options.sortBy - Field to sort by (default: 'displayOrder')
880
- * @param {string} options.sortOrder - Sort order ('asc' or 'desc', default: 'asc')
881
- * @returns {Promise<Object>} List of plans with pagination info
882
- */
883
- async listPlans(options = {}) {
884
- this._requireReady();
885
- try {
886
- return await this.call('plans:list', options);
887
- } catch (error) {
888
- throw new Error(`Failed to list plans: ${error.message}`);
889
- }
890
- }
891
-
892
- /**
893
- * Subscribe to a plan
894
- * @param {string} planId - ID of the plan to subscribe to
895
- * @param {Object} options - Options for the subscription
896
- * @param {string} options.paymentMethod - Payment method
897
- * @param {Object} options.billingAddress - Billing address
898
- * @param {string} options.stripeCustomerId - Stripe customer ID
899
- * @param {string} options.stripeSubscriptionId - Stripe subscription ID
900
- * @returns {Promise<Object>} Subscription details
901
- */
902
- async subscribeToPlan(planId, options = {}) {
903
- this._requireReady()
904
- try {
905
- return await this.call('subscriptions:create', { planId, ...options })
906
- } catch (error) {
907
- throw new Error(`Failed to subscribe to plan: ${error.message}`);
908
- }
909
- }
910
-
911
- /**
912
- * Get details of user's current subscription
913
- * @param {string} subscriptionId - ID of the subscription to get details for
914
- * @returns {Promise<Object>} Subscription details
915
- */
916
- async getSubscriptionDetails(subscriptionId) {
917
- this._requireReady();
918
- try {
919
- return await this.call('subscriptions:details', {
920
- subscriptionId
921
- });
922
- } catch (error) {
923
- throw new Error(`Failed to get subscription details: ${error.message}`);
924
- }
925
- }
926
-
927
- /**
928
- * Check if the current subscription is active
929
- * @param {string} subscriptionId - ID of the subscription to check
930
- * @returns {Promise<Object>} Subscription status info
931
- */
932
- async checkSubscriptionStatus(subscriptionId) {
933
- this._requireReady();
934
- try {
935
- return await this.call('subscriptions:check-status', {
936
- subscriptionId
937
- });
938
- } catch (error) {
939
- throw new Error(`Failed to check subscription status: ${error.message}`);
940
- }
941
- }
942
-
943
- /**
944
- * Upgrade the current subscription to a new plan
945
- * @param {string} planId - ID of the plan to upgrade to
946
- * @param {string} stripeSubscriptionId - ID of the Stripe subscription to upgrade
947
- * @returns {Promise<Object>} Updated subscription details
948
- */
949
- async upgradeSubscription(planId, stripeSubscriptionId) {
950
- this._requireReady();
951
- try {
952
- return await this.call('subscriptions:upgrade', {
953
- planId,
954
- stripeSubscriptionId
955
- });
956
- } catch (error) {
957
- throw new Error(`Failed to upgrade subscription: ${error.message}`);
958
- }
959
- }
960
-
961
- /**
962
- * Downgrade the current subscription to a new plan
963
- * @param {string} planId - ID of the plan to downgrade to
964
- * @param {boolean} applyImmediately - Whether to apply the downgrade immediately
965
- * @param {string} stripeSubscriptionId - ID of the Stripe subscription to downgrade
966
- * @returns {Promise<Object>} Updated subscription details
967
- */
968
- async downgradeSubscription(planId, stripeSubscriptionId, applyImmediately = false) {
969
- this._requireReady();
970
- try {
971
- return await this.call('subscriptions:downgrade', {
972
- planId,
973
- applyImmediately,
974
- stripeSubscriptionId
975
- });
976
- } catch (error) {
977
- throw new Error(`Failed to downgrade subscription: ${error.message}`);
978
- }
979
- }
980
-
981
- /**
982
- * Cancel the current subscription
983
- * @param {boolean} cancelImmediately - Whether to cancel immediately or at period end
984
- * @param {string} reason - Reason for cancellation
985
- * @returns {Promise<Object>} Result of cancellation
986
- */
987
- async cancelSubscription(cancelImmediately = false, reason = '') {
988
- this._requireReady();
989
- try {
990
- return await this.call('subscriptions:cancel', {
991
- cancelImmediately,
992
- reason
993
- });
994
- } catch (error) {
995
- throw new Error(`Failed to cancel subscription: ${error.message}`);
996
- }
997
- }
998
-
999
- /**
1000
- * Reactivate a subscription that was scheduled for cancellation
1001
- * @returns {Promise<Object>} Updated subscription details
1002
- */
1003
- async reactivateSubscription(stripeSubscriptionId) {
1004
- this._requireReady();
1005
- try {
1006
- return await this.call('subscriptions:reactivate', {
1007
- stripeSubscriptionId
1008
- });
1009
- } catch (error) {
1010
- throw new Error(`Failed to reactivate subscription: ${error.message}`);
1011
- }
1012
- }
1013
-
1014
- /**
1015
- * Generate an invoice for the current subscription
1016
- * @param {string} subscriptionId - ID of the subscription to generate the invoice for
1017
- * @param {boolean} forceGenerate - Whether to force the generation of the invoice
1018
- * @param {Array} customItems - Custom items to add to the invoice
1019
- * @returns {Promise<Object>} Generated invoice
1020
- */
1021
- async generateInvoice(subscriptionId, forceGenerate = false, customItems = []) {
1022
- this._requireReady();
1023
- try {
1024
- return await this.call('billing:generate-invoice', {
1025
- subscriptionId,
1026
- forceGenerate,
1027
- customItems
1028
- });
1029
- } catch (error) {
1030
- throw new Error(`Failed to generate invoice: ${error.message}`);
1031
- }
1032
- }
1033
-
1034
- /**
1035
- * Get usage report for the current subscription
1036
- * @param {string} subscriptionId - ID of the subscription to get the usage report for
1037
- * @param {boolean} forceRefresh - Whether to force the refresh of the usage report
1038
- * @returns {Promise<Object>} Usage report
1039
- */
1040
- async getUsageReport(subscriptionId, forceRefresh = false) {
1041
- this._requireReady();
1042
- try {
1043
- return await this.call('subscriptions:get-usage-report', {
1044
- subscriptionId,
1045
- forceRefresh
1046
- });
1047
- } catch (error) {
1048
- throw new Error(`Failed to get usage report: ${error.message}`);
1049
- }
1050
- }
1051
-
1052
- /**
1053
- * Invite a user to be an account owner for the current subscription
1054
- * @param {string} email - Email of the user to invite
1055
- * @param {string} name - Name of the user to invite
1056
- * @param {string} callbackUrl - URL to redirect the user to after accepting the invitation
1057
- * @returns {Promise<Object>} Result of invitation
1058
- */
1059
- async inviteAccountOwner(email, name, callbackUrl) {
1060
- this._requireReady();
1061
- try {
1062
- return await this.call('subscriptions:invite', {
1063
- email,
1064
- name,
1065
- callbackUrl
1066
- });
1067
- } catch (error) {
1068
- throw new Error(`Failed to invite account owner: ${error.message}`);
1069
- }
1070
- }
1071
-
1072
- /**
1073
- * Accept an invitation to become an account owner
1074
- * @param {string} token - Invitation token
1075
- * @returns {Promise<Object>} Result of accepting invitation
1076
- */
1077
- async acceptOwnerInvitation(token) {
1078
- this._requireReady();
1079
- try {
1080
- return await this.call('subscriptions:accept-owner-invitation', {
1081
- token
1082
- });
1083
- } catch (error) {
1084
- throw new Error(`Failed to accept owner invitation: ${error.message}`);
1085
- }
1086
- }
1087
-
1088
- /**
1089
- * Remove an account owner from the current subscription
1090
- * @param {string} userId - ID of the user to remove
1091
- * @returns {Promise<Object>} Result of removal
1092
- */
1093
- async removeAccountOwner(userId) {
1094
- this._requireReady();
1095
- try {
1096
- return await this.call('subscriptions:remove-account-owner', {
1097
- targetUserId: userId
1098
- });
1099
- } catch (error) {
1100
- throw new Error(`Failed to remove account owner: ${error.message}`);
1101
- }
1102
- }
1103
-
1104
- /**
1105
- * Check if a resource limit has been reached
1106
- * @param {string} resourceType - Type of resource to check
1107
- * @param {string} projectId - ID of the project to check the resource limit for
1108
- * @param {number} quantity - Amount being requested
1109
- * @param {string} userId - ID of user to check (admin only, defaults to current user)
1110
- * @returns {Promise<Object>} Result of check
1111
- */
1112
- async checkResourceLimit(resourceType, projectId, quantity = 1, userId = '') {
1113
- this._requireReady();
1114
- try {
1115
- return await this.call('subscriptions:check-resource-limit', {
1116
- resourceType,
1117
- projectId,
1118
- quantity,
1119
- userId
1120
- });
1121
- } catch (error) {
1122
- throw new Error(`Failed to check resource limit: ${error.message}`);
1123
- }
1124
- }
1125
-
1126
- /**
1127
- * Check if a user has access to a feature
1128
- * @param {string} featureKey - Key of the feature to check
1129
- * @param {string} userId - ID of user to check (admin only, defaults to current user)
1130
- * @returns {Promise<Object>} Access check result
1131
- */
1132
- async checkFeatureAccess(featureKey, userId) {
1133
- this._requireReady();
1134
- try {
1135
- return await this.call('features:check-access', {
1136
- featureKey,
1137
- userId
1138
- });
1139
- } catch (error) {
1140
- throw new Error(`Failed to check feature access: ${error.message}`);
1141
- }
1142
- }
1143
-
1144
- /**
1145
- * Get all features available to the current user
1146
- * @returns {Promise<Object>} Available features
1147
- */
1148
- async getUserFeatures() {
1149
- this._requireReady();
1150
- try {
1151
- return await this.call('subscriptions:get-user-features', {});
1152
- } catch (error) {
1153
- throw new Error(`Failed to get user features: ${error.message}`);
1154
- }
1155
- }
1156
-
1157
- /**
1158
- * Get all available features across all plans
1159
- * @param {string} subscriptionId - ID of the subscription to get the available features for
1160
- * @param {string} userId - ID of user to get the available features for (admin only, defaults to current user)
1161
- * @param {boolean} includeDetails - Whether to include details about the features
1162
- * @returns {Promise<Object>} Available features
1163
- */
1164
- async getAvailableFeatures(subscriptionId, userId = '', includeDetails = false) {
1165
- this._requireReady();
1166
- try {
1167
- return await this.call('features:get-available', {
1168
- subscriptionId,
1169
- userId,
1170
- includeDetails
1171
- });
1172
- } catch (error) {
1173
- throw new Error(`Failed to get available features: ${error.message}`);
1174
- }
1175
- }
1176
-
1177
- /**
1178
- * List all feature flags (admin only)
1179
- * @param {Object} options - Options for listing feature flags
1180
- * @param {number} options.page - Page number
1181
- * @param {number} options.limit - Number of items per page
1182
- * @param {string} options.status - Filter by status
1183
- * @returns {Promise<Object>} List of feature flags
1184
- */
1185
- async listFeatureFlags(options = {}) {
1186
- this._requireReady();
1187
- try {
1188
- return await this.call('features:list', options);
1189
- } catch (error) {
1190
- throw new Error(`Failed to list feature flags: ${error.message}`);
1191
- }
1192
- }
1193
-
1194
- /**
1195
- * Update a feature flag (admin only)
1196
- * @param {string} flagId - ID of the feature flag to update
1197
- * @param {Object} options - Update data
1198
- * @param {string} options.key - Key of the feature flag
1199
- * @param {string} options.name - Name of the feature flag
1200
- * @param {string} options.description - Description of the feature flag
1201
- * @param {string} options.defaultValue - Default value of the feature flag
1202
- * @param {Object} options.planOverrides - Plan overrides for the feature flag
1203
- * @param {Object} options.userOverrides - User overrides for the feature flag
1204
- * @param {string} options.status - Status of the feature flag
1205
- * @returns {Promise<Object>} Updated feature flag
1206
- */
1207
- async updateFeatureFlag(flagId, options) {
1208
- this._requireReady();
1209
- try {
1210
- return await this.call('features:update', {
1211
- flagId,
1212
- ...options
1213
- });
1214
- } catch (error) {
1215
- throw new Error(`Failed to update feature flag: ${error.message}`);
1216
- }
1217
- }
1218
-
1219
- /**
1220
- * Remove a feature flag (admin only)
1221
- * @param {string} flagId - ID of the feature flag to remove
1222
- * @returns {Promise<Object>} Result of removal
1223
- */
1224
- async removeFeatureFlag(flagId) {
1225
- this._requireReady();
1226
- try {
1227
- return await this.call('features:remove', {
1228
- flagId
1229
- });
1230
- } catch (error) {
1231
- throw new Error(`Failed to remove feature flag: ${error.message}`);
1232
- }
1233
- }
1234
-
1235
- /**
1236
- * Batch update feature flags (admin only)
1237
- * @param {Array} operations - Array of feature flag operations
1238
- * @param {string} operations.flagId - ID of the feature flag to update
1239
- * @param {string} operations.key - Key of the feature flag
1240
- * @param {string} operations.name - Name of the feature flag
1241
- * @param {string} operations.description - Description of the feature flag
1242
- * @param {boolean} operations.defaultValue - Default value of the feature flag
1243
- * @param {Object} operations.planOverrides - Plan overrides for the feature flag
1244
- * @param {Object} operations.userOverrides - User overrides for the feature flag
1245
- * @param {string} operations.status - Status of the feature flag
1246
- * @returns {Promise<Object>} Result of batch update
1247
- */
1248
- async batchUpdateFeatureFlags(operations) {
1249
- this._requireReady();
1250
- try {
1251
- return await this.call('features:batch-update', {
1252
- operations
1253
- });
1254
- } catch (error) {
1255
- throw new Error(`Failed to batch update feature flags: ${error.message}`);
1256
- }
1257
- }
1258
-
1259
- /**
1260
- * Update plan details (admin only)
1261
- * @param {string} planId - ID of the plan to update
1262
- * @param {Object} data - Update data
1263
- * @param {string} data.name - Display name (e.g., "Pro", "Team")
1264
- * @param {string} data.description - Marketing description
1265
- * @param {number} data.price - Monthly price in cents
1266
- * @param {number} data.annualPrice - Annual price in cents (discounted)
1267
- * @param {number} data.lifetimePrice - One-time lifetime price in cents
1268
- * @param {string} data.billingType - Payment type
1269
- * @param {string} data.status - Status
1270
- * @param {Object} data.features - Detailed feature configuration
1271
- * @returns {Promise<Object>} Updated plan
1272
- */
1273
- async updatePlanDetails(planId, data) {
1274
- this._requireReady();
1275
- try {
1276
- return await this.call('plans:update-details', {
1277
- planId,
1278
- data
1279
- });
1280
- } catch (error) {
1281
- throw new Error(`Failed to update plan details: ${error.message}`);
1282
- }
1283
- }
1284
-
1285
- /**
1286
- * Update plan status (admin only)
1287
- * @param {string} planId - ID of the plan to update
1288
- * @param {string} status - New status
1289
- * @returns {Promise<Object>} Updated plan
1290
- */
1291
- async updatePlanStatus(planId, status) {
1292
- this._requireReady();
1293
- try {
1294
- return await this.call('plans:update-status', {
1295
- planId,
1296
- status
1297
- });
1298
- } catch (error) {
1299
- throw new Error(`Failed to update plan status: ${error.message}`);
1300
- }
1301
- }
1302
- }