@symbo.ls/sdk 3.1.1 → 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.
- package/README.md +174 -13
- package/dist/cjs/config/environment.js +32 -42
- package/dist/cjs/index.js +31 -24
- package/dist/cjs/services/AIService.js +3 -3
- package/dist/cjs/services/AuthService.js +44 -3
- package/dist/cjs/services/BasedService.js +530 -24
- package/dist/cjs/services/CollabService.js +420 -0
- package/dist/cjs/services/CoreService.js +2295 -0
- package/dist/cjs/services/SocketService.js +207 -59
- package/dist/cjs/services/SymstoryService.js +135 -49
- package/dist/cjs/services/index.js +8 -16
- package/dist/cjs/state/RootStateManager.js +86 -0
- package/dist/cjs/state/rootEventBus.js +65 -0
- package/dist/cjs/utils/CollabClient.js +157 -0
- package/dist/cjs/utils/TokenManager.js +409 -0
- package/dist/cjs/utils/basedQuerys.js +120 -0
- package/dist/cjs/utils/jsonDiff.js +103 -0
- package/dist/cjs/utils/permission.js +4 -4
- package/dist/cjs/utils/services.js +133 -69
- package/dist/cjs/utils/symstoryClient.js +33 -2
- package/dist/esm/config/environment.js +32 -42
- package/dist/esm/index.js +20586 -11525
- package/dist/esm/services/AIService.js +3 -3
- package/dist/esm/services/AuthService.js +48 -7
- package/dist/esm/services/BasedService.js +676 -65
- package/dist/esm/services/CollabService.js +18028 -0
- package/dist/esm/services/CoreService.js +2827 -0
- package/dist/esm/services/SocketService.js +323 -58
- package/dist/esm/services/SymstoryService.js +287 -111
- package/dist/esm/services/index.js +20456 -11470
- package/dist/esm/state/RootStateManager.js +102 -0
- package/dist/esm/state/rootEventBus.js +47 -0
- package/dist/esm/utils/CollabClient.js +17483 -0
- package/dist/esm/utils/TokenManager.js +395 -0
- package/dist/esm/utils/basedQuerys.js +120 -0
- package/dist/esm/utils/jsonDiff.js +6096 -0
- package/dist/esm/utils/permission.js +4 -4
- package/dist/esm/utils/services.js +133 -69
- package/dist/esm/utils/symstoryClient.js +63 -43
- package/dist/esm/utils/validation.js +89 -19
- package/dist/node/config/environment.js +32 -42
- package/dist/node/index.js +37 -28
- package/dist/node/services/AIService.js +3 -3
- package/dist/node/services/AuthService.js +44 -3
- package/dist/node/services/BasedService.js +531 -25
- package/dist/node/services/CollabService.js +401 -0
- package/dist/node/services/CoreService.js +2266 -0
- package/dist/node/services/SocketService.js +197 -59
- package/dist/node/services/SymstoryService.js +135 -49
- package/dist/node/services/index.js +8 -16
- package/dist/node/state/RootStateManager.js +57 -0
- package/dist/node/state/rootEventBus.js +46 -0
- package/dist/node/utils/CollabClient.js +128 -0
- package/dist/node/utils/TokenManager.js +390 -0
- package/dist/node/utils/basedQuerys.js +120 -0
- package/dist/node/utils/jsonDiff.js +74 -0
- package/dist/node/utils/permission.js +4 -4
- package/dist/node/utils/services.js +133 -69
- package/dist/node/utils/symstoryClient.js +33 -2
- package/package.json +23 -14
- package/src/config/environment.js +33 -42
- package/src/index.js +45 -28
- package/src/services/AIService.js +3 -3
- package/src/services/AuthService.js +52 -3
- package/src/services/BasedService.js +603 -23
- package/src/services/CollabService.js +491 -0
- package/src/services/CoreService.js +2548 -0
- package/src/services/SocketService.js +227 -59
- package/src/services/SymstoryService.js +150 -64
- package/src/services/index.js +7 -14
- package/src/state/RootStateManager.js +71 -0
- package/src/state/rootEventBus.js +48 -0
- package/src/utils/CollabClient.js +161 -0
- package/src/utils/TokenManager.js +462 -0
- package/src/utils/basedQuerys.js +123 -0
- package/src/utils/jsonDiff.js +109 -0
- package/src/utils/permission.js +4 -4
- package/src/utils/services.js +144 -69
- package/src/utils/symstoryClient.js +36 -2
- package/dist/cjs/services/SocketIOService.js +0 -309
- package/dist/esm/services/SocketIOService.js +0 -467
- package/dist/node/services/SocketIOService.js +0 -280
- package/src/services/SocketIOService.js +0 -356
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { BaseService } from './BaseService.js'
|
|
2
|
-
import { buildProjectQuery, buildUserQuery } from '../utils/basedQuerys.js'
|
|
2
|
+
import { buildProjectQuery, buildUserQuery, buildGetProjectsByKeysQuery, buildGetUserDataQuery, buildGetProjectDataQuery, buildGetProjectByKeyDataQuery } from '../utils/basedQuerys.js'
|
|
3
3
|
import Based from '@based/client'
|
|
4
4
|
import { isFunction, isString } from '@domql/utils'
|
|
5
5
|
import environment from '../config/environment.js'
|
|
6
6
|
|
|
7
|
+
// DEPRECATED
|
|
7
8
|
export class BasedService extends BaseService {
|
|
8
9
|
constructor (config) {
|
|
9
10
|
super(config)
|
|
@@ -122,7 +123,7 @@ export class BasedService extends BaseService {
|
|
|
122
123
|
joinedAt: Date.now()
|
|
123
124
|
})
|
|
124
125
|
|
|
125
|
-
await Promise.all([
|
|
126
|
+
return await Promise.all([
|
|
126
127
|
this._client.call('db:set', {
|
|
127
128
|
$id: userId,
|
|
128
129
|
memberProjects: { $add: membershipId }
|
|
@@ -132,7 +133,6 @@ export class BasedService extends BaseService {
|
|
|
132
133
|
members: { $add: membershipId }
|
|
133
134
|
})
|
|
134
135
|
])
|
|
135
|
-
return await this._client.call('db:set', obj)
|
|
136
136
|
} catch (error) {
|
|
137
137
|
throw new Error(`Failed to set bucket: ${error.message}`)
|
|
138
138
|
}
|
|
@@ -176,6 +176,7 @@ export class BasedService extends BaseService {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
// DEPRECATED
|
|
179
180
|
async fetchUser (userId) {
|
|
180
181
|
if (!userId) {
|
|
181
182
|
throw new Error('User Id is required')
|
|
@@ -184,15 +185,158 @@ export class BasedService extends BaseService {
|
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
async getUser (userId) {
|
|
187
|
-
this._requireReady()
|
|
188
188
|
if (!userId) {
|
|
189
|
-
throw new Error(
|
|
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
|
|
190
273
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
+
}
|
|
195
337
|
}
|
|
338
|
+
|
|
339
|
+
return await processChunks(allKeys, optimalChunkSize)
|
|
196
340
|
}
|
|
197
341
|
|
|
198
342
|
async getUserByEmail (email) {
|
|
@@ -368,6 +512,7 @@ export class BasedService extends BaseService {
|
|
|
368
512
|
|
|
369
513
|
async createProject (projectData) {
|
|
370
514
|
this._requireReady()
|
|
515
|
+
|
|
371
516
|
try {
|
|
372
517
|
return await this.call('projects:create', projectData)
|
|
373
518
|
} catch (error) {
|
|
@@ -375,33 +520,32 @@ export class BasedService extends BaseService {
|
|
|
375
520
|
}
|
|
376
521
|
}
|
|
377
522
|
|
|
378
|
-
async getProject (projectId
|
|
523
|
+
async getProject (projectId) {
|
|
379
524
|
this._requireReady()
|
|
380
525
|
if (!projectId) {
|
|
381
526
|
throw new Error('Project ID is required')
|
|
382
527
|
}
|
|
383
528
|
try {
|
|
384
|
-
return await this.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
})
|
|
529
|
+
return await this._client
|
|
530
|
+
.query("db", buildGetProjectDataQuery(projectId))
|
|
531
|
+
.get()
|
|
388
532
|
} catch (error) {
|
|
389
533
|
throw new Error(`Failed to get project: ${error.message}`)
|
|
390
534
|
}
|
|
391
535
|
}
|
|
392
536
|
|
|
393
|
-
async getProjectByKey (key
|
|
537
|
+
async getProjectByKey (key) {
|
|
394
538
|
this._requireReady()
|
|
395
539
|
try {
|
|
396
|
-
return await this.
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
})
|
|
540
|
+
return await this._client
|
|
541
|
+
.query("db", buildGetProjectByKeyDataQuery(key))
|
|
542
|
+
.get()
|
|
400
543
|
} catch (error) {
|
|
401
544
|
throw new Error(`Failed to get project by key: ${error.message}`)
|
|
402
545
|
}
|
|
403
546
|
}
|
|
404
547
|
|
|
548
|
+
// DEPRECATED
|
|
405
549
|
async fetchProject (projectId) {
|
|
406
550
|
this._requireReady()
|
|
407
551
|
if (!projectId) {
|
|
@@ -489,7 +633,9 @@ export class BasedService extends BaseService {
|
|
|
489
633
|
pkg = 2,
|
|
490
634
|
seats = 1,
|
|
491
635
|
interval = 'monthly',
|
|
492
|
-
plan = 'startup'
|
|
636
|
+
plan = 'startup',
|
|
637
|
+
successUrl = `${window.location.origin}/success`,
|
|
638
|
+
cancelUrl = `${window.location.origin}/pricing`
|
|
493
639
|
}) {
|
|
494
640
|
this._requireReady()
|
|
495
641
|
|
|
@@ -516,7 +662,9 @@ export class BasedService extends BaseService {
|
|
|
516
662
|
return await this.call('checkout', {
|
|
517
663
|
price,
|
|
518
664
|
seats,
|
|
519
|
-
projectId
|
|
665
|
+
projectId,
|
|
666
|
+
successUrl,
|
|
667
|
+
cancelUrl
|
|
520
668
|
})
|
|
521
669
|
} catch (error) {
|
|
522
670
|
throw new Error(`Failed to checkout: ${error.message}`)
|
|
@@ -707,16 +855,448 @@ export class BasedService extends BaseService {
|
|
|
707
855
|
* @param {string} newKey - The new key of the project (optional)
|
|
708
856
|
* @returns {Promise<Object>} The duplicated project
|
|
709
857
|
*/
|
|
710
|
-
async duplicateProject (projectId, newName, newKey) {
|
|
858
|
+
async duplicateProject (projectId, newName, newKey, targetUserId) {
|
|
711
859
|
this._requireReady()
|
|
712
860
|
try {
|
|
713
861
|
return await this.call('projects:duplicate', {
|
|
714
862
|
projectId,
|
|
715
863
|
newName,
|
|
716
|
-
newKey
|
|
864
|
+
newKey,
|
|
865
|
+
targetUserId
|
|
717
866
|
})
|
|
718
867
|
} catch (error) {
|
|
719
868
|
throw new Error(`Failed to duplicate project: ${error.message}`)
|
|
720
869
|
}
|
|
721
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
|
+
}
|
|
722
1302
|
}
|