@symbo.ls/sdk 3.4.9 → 3.4.11
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 +529 -732
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @symbo.ls/sdk
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@symbo.ls/sdk)
|
|
4
|
+
[](https://www.npmjs.com/package/@symbo.ls/sdk)
|
|
5
|
+
[](https://bundlephobia.com/package/@symbo.ls/sdk)
|
|
6
|
+
[](https://github.com/nicholasgasior/symbo.ls/blob/main/LICENSE)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
[](https://www.npmjs.com/package/@symbo.ls/sdk)
|
|
9
|
+
|
|
10
|
+
> Official SDK for the [Symbols](https://symbols.app) design platform — manage projects, collaborate in real-time, handle branches, pull requests, and more.
|
|
11
|
+
|
|
2
12
|
## Installation
|
|
13
|
+
|
|
3
14
|
```bash
|
|
4
15
|
npm install @symbo.ls/sdk
|
|
5
16
|
```
|
|
@@ -7,11 +18,11 @@ npm install @symbo.ls/sdk
|
|
|
7
18
|
## Basic Usage
|
|
8
19
|
|
|
9
20
|
### Initialize SDK
|
|
21
|
+
|
|
10
22
|
```javascript
|
|
11
23
|
import { SDK } from '@symbo.ls/sdk'
|
|
12
24
|
|
|
13
25
|
const sdk = new SDK({
|
|
14
|
-
useNewServices: true, // Use new service implementations
|
|
15
26
|
apiUrl: 'https://api.symbols.app',
|
|
16
27
|
socketUrl: 'https://api.symbols.app',
|
|
17
28
|
timeout: 30000,
|
|
@@ -19,902 +30,688 @@ const sdk = new SDK({
|
|
|
19
30
|
debug: false
|
|
20
31
|
})
|
|
21
32
|
|
|
22
|
-
// Initialize with context
|
|
23
33
|
await sdk.initialize({
|
|
24
34
|
authToken: 'your-auth-token',
|
|
25
|
-
appKey: 'your-app-key'
|
|
35
|
+
appKey: 'your-app-key'
|
|
26
36
|
})
|
|
27
37
|
```
|
|
28
38
|
|
|
29
39
|
### Service Access
|
|
40
|
+
|
|
30
41
|
```javascript
|
|
31
|
-
// Get service instances
|
|
32
42
|
const auth = sdk.getService('auth')
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
const
|
|
43
|
+
const project = sdk.getService('project')
|
|
44
|
+
const branch = sdk.getService('branch')
|
|
45
|
+
const pullRequest = sdk.getService('pullRequest')
|
|
46
|
+
const collab = sdk.getService('collab')
|
|
47
|
+
const file = sdk.getService('file')
|
|
48
|
+
const payment = sdk.getService('payment')
|
|
49
|
+
const plan = sdk.getService('plan')
|
|
50
|
+
const subscription = sdk.getService('subscription')
|
|
51
|
+
const dns = sdk.getService('dns')
|
|
52
|
+
const admin = sdk.getService('admin')
|
|
53
|
+
const screenshot = sdk.getService('screenshot')
|
|
54
|
+
const tracking = sdk.getService('tracking')
|
|
55
|
+
const waitlist = sdk.getService('waitlist')
|
|
56
|
+
const metrics = sdk.getService('metrics')
|
|
57
|
+
const integration = sdk.getService('integration')
|
|
58
|
+
const featureFlag = sdk.getService('featureFlag')
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
All service methods are also available directly on the SDK instance via proxy methods:
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
// These are equivalent:
|
|
65
|
+
sdk.getService('project').getProject(projectId)
|
|
66
|
+
sdk.getProject(projectId)
|
|
37
67
|
```
|
|
38
68
|
|
|
39
|
-
### Status
|
|
69
|
+
### Status & Context
|
|
70
|
+
|
|
40
71
|
```javascript
|
|
41
72
|
// Check if SDK is ready
|
|
42
|
-
|
|
73
|
+
sdk.isReady()
|
|
43
74
|
|
|
44
75
|
// Get detailed status
|
|
45
76
|
const status = sdk.getStatus()
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
{ name: 'symstory', ready: true, ... },
|
|
54
|
-
{ name: 'based', ready: true, ... },
|
|
55
|
-
{ name: 'ai', ready: true, ... }
|
|
56
|
-
],
|
|
57
|
-
context: { ... }
|
|
58
|
-
}
|
|
59
|
-
*/
|
|
77
|
+
// { ready: true, services: [...], context: {...} }
|
|
78
|
+
|
|
79
|
+
// Update context
|
|
80
|
+
sdk.updateContext({ ... })
|
|
81
|
+
|
|
82
|
+
// Cleanup
|
|
83
|
+
await sdk.destroy()
|
|
60
84
|
```
|
|
61
85
|
|
|
62
|
-
###
|
|
86
|
+
### Root Event Bus
|
|
87
|
+
|
|
88
|
+
The SDK exposes a global event bus for cross-service communication:
|
|
89
|
+
|
|
63
90
|
```javascript
|
|
64
|
-
|
|
65
|
-
sdk.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
})
|
|
91
|
+
sdk.rootBus.on('checkpoint:done', (payload) => { ... })
|
|
92
|
+
sdk.rootBus.on('clients:updated', (payload) => { ... })
|
|
93
|
+
sdk.rootBus.on('bundle:done', (payload) => { ... })
|
|
94
|
+
sdk.rootBus.on('bundle:error', (payload) => { ... })
|
|
70
95
|
```
|
|
71
96
|
|
|
72
|
-
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Services
|
|
73
100
|
|
|
74
101
|
### Auth Service
|
|
102
|
+
|
|
103
|
+
**Authentication:**
|
|
104
|
+
|
|
75
105
|
```javascript
|
|
76
106
|
const auth = sdk.getService('auth')
|
|
77
107
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
* @param {string} email - User's email
|
|
81
|
-
* @param {string} password - User's password
|
|
82
|
-
*/
|
|
83
|
-
await auth.login(email, password)
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Register a new user
|
|
87
|
-
* @param {Object} userData - User data
|
|
88
|
-
*/
|
|
89
|
-
await auth.register(userData)
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Logout the current user
|
|
93
|
-
*/
|
|
108
|
+
await auth.register(userData, options)
|
|
109
|
+
await auth.login(email, password, options)
|
|
94
110
|
await auth.logout()
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
*/
|
|
111
|
+
await auth.refreshToken(refreshToken)
|
|
112
|
+
await auth.googleAuth(idToken, inviteToken, options)
|
|
113
|
+
await auth.googleAuthCallback(code, redirectUri, inviteToken, options)
|
|
114
|
+
await auth.githubAuth(code, inviteToken, options)
|
|
100
115
|
await auth.requestPasswordReset(email)
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Confirm a password reset
|
|
104
|
-
* @param {string} token - Reset token
|
|
105
|
-
* @param {string} newPassword - New password
|
|
106
|
-
*/
|
|
107
|
-
await auth.confirmPasswordReset(token, newPassword)
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Update a user's role
|
|
111
|
-
* @param {string} userId - User ID
|
|
112
|
-
* @param {string} newRole - New role
|
|
113
|
-
*/
|
|
114
|
-
await auth.updateUserRole(userId, newRole)
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Update a member's role in a project
|
|
118
|
-
* @param {string} projectId - Project ID
|
|
119
|
-
* @param {string} userId - User ID
|
|
120
|
-
* @param {string} role - New role
|
|
121
|
-
*/
|
|
122
|
-
await auth.updateMemberRole(projectId, userId, role)
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Update a project's tier
|
|
126
|
-
* @param {string} projectId - Project ID
|
|
127
|
-
* @param {string} newTier - New tier
|
|
128
|
-
*/
|
|
129
|
-
await auth.updateProjectTier(projectId, newTier)
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Invite a member to a project
|
|
133
|
-
* @param {string} projectId - Project ID
|
|
134
|
-
* @param {string} email - Member's email
|
|
135
|
-
* @param {string} role - Member's role
|
|
136
|
-
* @param {string} name - Member's name
|
|
137
|
-
*/
|
|
138
|
-
await auth.inviteMember(projectId, email, role, name)
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Accept an invite
|
|
142
|
-
* @param {string} token - Invite token
|
|
143
|
-
*/
|
|
144
|
-
await auth.acceptInvite(token)
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Confirm a user's registration
|
|
148
|
-
* @param {string} token - Registration token
|
|
149
|
-
*/
|
|
116
|
+
await auth.confirmPasswordReset(token, password)
|
|
150
117
|
await auth.confirmRegistration(token)
|
|
118
|
+
await auth.requestPasswordChange()
|
|
119
|
+
await auth.confirmPasswordChange(currentPassword, newPassword, code)
|
|
120
|
+
```
|
|
151
121
|
|
|
152
|
-
|
|
153
|
-
* Get members of a project
|
|
154
|
-
* @param {string} projectId - Project ID
|
|
155
|
-
*/
|
|
156
|
-
await auth.getProjectMembers(projectId)
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Check if a user has a specific permission
|
|
160
|
-
* @param {string} projectId - Project ID
|
|
161
|
-
* @param {string} permission - Permission to check
|
|
162
|
-
*/
|
|
163
|
-
const hasPermission = auth.hasPermission(projectId, 'edit')
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Check if a user has a global permission
|
|
167
|
-
* @param {string} globalRole - User's global role
|
|
168
|
-
* @param {string} permission - Permission to check
|
|
169
|
-
*/
|
|
170
|
-
const hasGlobalPermission = auth.hasGlobalPermission('admin', 'manage')
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Check if a user has a project-specific permission
|
|
174
|
-
* @param {Object} projectRoles - User's project roles
|
|
175
|
-
* @param {string} projectId - Project ID
|
|
176
|
-
* @param {string} requiredPermission - Permission to check
|
|
177
|
-
*/
|
|
178
|
-
const hasProjectPermission = auth.checkProjectPermission(projectRoles, projectId, 'edit')
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Check if a project has a specific feature
|
|
182
|
-
* @param {string} projectTier - Project's tier
|
|
183
|
-
* @param {string} feature - Feature to check
|
|
184
|
-
*/
|
|
185
|
-
const hasProjectFeature = auth.checkProjectFeature('pro1', 'aiCopilot:5')
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Check if a user can perform a specific operation
|
|
189
|
-
* @param {string} projectId - Project ID
|
|
190
|
-
* @param {string} operation - Operation to check
|
|
191
|
-
* @param {Object} options - Additional options
|
|
192
|
-
*/
|
|
193
|
-
const canPerformOperation = await auth.canPerformOperation(projectId, 'edit', { checkFeatures: true })
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Execute an action with permission check
|
|
197
|
-
* @param {string} projectId - Project ID
|
|
198
|
-
* @param {string} operation - Operation to check
|
|
199
|
-
* @param {function} action - Action to execute
|
|
200
|
-
*/
|
|
201
|
-
await auth.withPermission(projectId, 'edit', () => {
|
|
202
|
-
// Action to perform
|
|
203
|
-
})
|
|
122
|
+
**User Data:**
|
|
204
123
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
124
|
+
```javascript
|
|
125
|
+
await auth.getMe(options)
|
|
126
|
+
auth.getStoredAuthState()
|
|
127
|
+
auth.getAuthToken()
|
|
128
|
+
auth.getUserProfile()
|
|
129
|
+
await auth.updateUserProfile(profileData)
|
|
130
|
+
await auth.getUserProjects()
|
|
131
|
+
await auth.getUser(userId)
|
|
132
|
+
await auth.getUserByEmail(email)
|
|
133
|
+
auth.isAuthenticated()
|
|
134
|
+
auth.hasValidTokens()
|
|
135
|
+
auth.getCurrentUser()
|
|
210
136
|
```
|
|
211
137
|
|
|
212
|
-
|
|
138
|
+
**Project Roles:**
|
|
139
|
+
|
|
213
140
|
```javascript
|
|
214
|
-
|
|
141
|
+
await auth.getMyProjectRole(projectId) // cached
|
|
142
|
+
await auth.getMyProjectRoleByKey(projectKey) // cached
|
|
143
|
+
auth.clearProjectRoleCache(projectId)
|
|
144
|
+
```
|
|
215
145
|
|
|
216
|
-
|
|
217
|
-
* Subscribe to events
|
|
218
|
-
* @param {string} event - Event name
|
|
219
|
-
* @param {function} callback - Callback function
|
|
220
|
-
* @returns {function} Unsubscribe function
|
|
221
|
-
*/
|
|
222
|
-
const unsubscribe = socket.subscribe('updates', (data) => {
|
|
223
|
-
console.log('Received:', data)
|
|
224
|
-
})
|
|
146
|
+
**Permissions:**
|
|
225
147
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
})
|
|
148
|
+
```javascript
|
|
149
|
+
auth.hasPermission(requiredPermission)
|
|
150
|
+
auth.hasGlobalPermission(globalRole, requiredPermission)
|
|
151
|
+
auth.checkProjectPermission(projectRole, requiredPermission)
|
|
152
|
+
auth.checkProjectFeature(projectTier, feature)
|
|
153
|
+
await auth.canPerformOperation(projectId, operation, options)
|
|
154
|
+
await auth.withPermission(projectId, operation, action)
|
|
155
|
+
```
|
|
235
156
|
|
|
236
|
-
|
|
237
|
-
unsubscribe()
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Symstory Service
|
|
241
|
-
```javascript
|
|
242
|
-
const symstory = sdk.getService('symstory')
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Get data
|
|
246
|
-
* @param {Object} query - Query object
|
|
247
|
-
*/
|
|
248
|
-
await symstory.getData(query)
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Update data
|
|
252
|
-
* @param {Object} changes - Changes to apply
|
|
253
|
-
*/
|
|
254
|
-
await symstory.updateData(changes)
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Delete data
|
|
258
|
-
* @param {string} path - Path to data
|
|
259
|
-
*/
|
|
260
|
-
await symstory.deleteData(path)
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Get an item
|
|
264
|
-
* @param {string} type - Item type
|
|
265
|
-
* @param {string} key - Item key
|
|
266
|
-
*/
|
|
267
|
-
await symstory.getItem(type, key)
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Add an item
|
|
271
|
-
* @param {string} type - Item type
|
|
272
|
-
* @param {Object} data - Item data
|
|
273
|
-
*/
|
|
274
|
-
await symstory.addItem(type, data)
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Update an item
|
|
278
|
-
* @param {string} type - Item type
|
|
279
|
-
* @param {Object} data - Item data
|
|
280
|
-
*/
|
|
281
|
-
await symstory.updateItem(type, data)
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Delete an item
|
|
285
|
-
* @param {string} type - Item type
|
|
286
|
-
* @param {string} key - Item key
|
|
287
|
-
*/
|
|
288
|
-
await symstory.deleteItem(type, key)
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Get branches
|
|
292
|
-
*/
|
|
293
|
-
await symstory.getBranches()
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Create a branch
|
|
297
|
-
* @param {Object} branch - Branch data
|
|
298
|
-
*/
|
|
299
|
-
await symstory.createBranch(branch)
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Merge a branch
|
|
303
|
-
* @param {Object} branch - Branch data
|
|
304
|
-
*/
|
|
305
|
-
await symstory.mergeBranch(branch)
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Restore a version
|
|
309
|
-
* @param {Object} version - Version data
|
|
310
|
-
*/
|
|
311
|
-
await symstory.restoreVersion(version)
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### Based Service
|
|
315
|
-
```javascript
|
|
316
|
-
const based = sdk.getService('based')
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Query data
|
|
320
|
-
* @param {string} collection - Collection name
|
|
321
|
-
* @param {Object} query - Query object
|
|
322
|
-
*/
|
|
323
|
-
const result = await based.query(collection, query)
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Subscribe to changes
|
|
327
|
-
* @param {string} collection - Collection name
|
|
328
|
-
* @param {Object} query - Query object
|
|
329
|
-
* @param {function} callback - Callback function
|
|
330
|
-
* @returns {function} Unsubscribe function
|
|
331
|
-
*/
|
|
332
|
-
const unsubscribe = based.subscribe(collection, query, (data) => {
|
|
333
|
-
console.log('Data updated:', data)
|
|
334
|
-
})
|
|
157
|
+
### Project Service
|
|
335
158
|
|
|
336
|
-
|
|
337
|
-
* Call a function
|
|
338
|
-
* @param {string} functionName - Function name
|
|
339
|
-
* @param {Object} params - Function parameters
|
|
340
|
-
*/
|
|
341
|
-
await based.call('functionName', params)
|
|
159
|
+
**Project Management:**
|
|
342
160
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
* @param {string} projectId - Project ID
|
|
346
|
-
*/
|
|
347
|
-
await based.getProject(projectId)
|
|
161
|
+
```javascript
|
|
162
|
+
const project = sdk.getService('project')
|
|
348
163
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
await
|
|
164
|
+
await project.createProject(projectData)
|
|
165
|
+
await project.getProjects(params)
|
|
166
|
+
await project.getProject(projectId)
|
|
167
|
+
await project.getProjectByKey(key)
|
|
168
|
+
await project.getProjectDataByKey(key, options)
|
|
169
|
+
await project.getPublicProject(projectId)
|
|
170
|
+
await project.listPublicProjects(params)
|
|
171
|
+
await project.updateProject(projectId, data)
|
|
172
|
+
await project.updateProjectComponents(projectId, components)
|
|
173
|
+
await project.updateProjectSettings(projectId, settings)
|
|
174
|
+
await project.updateProjectName(projectId, name)
|
|
175
|
+
await project.updateProjectPackage(projectId, pkg)
|
|
176
|
+
await project.duplicateProject(projectId, newName, newKey, targetUserId)
|
|
177
|
+
await project.removeProject(projectId)
|
|
178
|
+
await project.checkProjectKeyAvailability(key)
|
|
179
|
+
```
|
|
354
180
|
|
|
355
|
-
|
|
356
|
-
* Fetch a user
|
|
357
|
-
* @param {string} userId - User ID
|
|
358
|
-
*/
|
|
359
|
-
await based.fetchUser(userId)
|
|
181
|
+
**Role Permissions Config:**
|
|
360
182
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
*/
|
|
365
|
-
await based.fetchProject(projectId)
|
|
183
|
+
```javascript
|
|
184
|
+
await project.getProjectRolePermissionsConfig(projectId, options)
|
|
185
|
+
await project.updateProjectRolePermissionsConfig(projectId, rolePermissions, options)
|
|
366
186
|
```
|
|
367
187
|
|
|
368
|
-
|
|
188
|
+
**Members:**
|
|
189
|
+
|
|
369
190
|
```javascript
|
|
370
|
-
|
|
191
|
+
await project.getProjectMembers(projectId)
|
|
192
|
+
await project.inviteMember(projectId, email, role, options)
|
|
193
|
+
await project.createMagicInviteLink(projectId, options)
|
|
194
|
+
await project.acceptInvite(token)
|
|
195
|
+
await project.updateMemberRole(projectId, memberId, role)
|
|
196
|
+
await project.removeMember(projectId, memberId)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Libraries:**
|
|
371
200
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const response = await ai.prompt(query, options)
|
|
201
|
+
```javascript
|
|
202
|
+
await project.getAvailableLibraries(params)
|
|
203
|
+
await project.getProjectLibraries(projectId)
|
|
204
|
+
await project.addProjectLibraries(projectId, libraryIds)
|
|
205
|
+
await project.removeProjectLibraries(projectId, libraryIds)
|
|
378
206
|
```
|
|
379
207
|
|
|
380
|
-
|
|
208
|
+
**Project Data (Version Control):**
|
|
209
|
+
|
|
381
210
|
```javascript
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
apiUrl: 'https://api.symbols.app',
|
|
386
|
-
// Tracking configuration mirrors TrackingService options
|
|
387
|
-
tracking: {
|
|
388
|
-
url: 'https://<your-faro-receiver-url>', // FO ingest/collector URL
|
|
389
|
-
appName: 'Symbols Platform',
|
|
390
|
-
environment: 'development', // 'production' | 'staging' | 'testing' | 'development'
|
|
391
|
-
appVersion: '1.0.0',
|
|
392
|
-
sessionTracking: true,
|
|
393
|
-
enableTracing: true, // adds browser tracing when available
|
|
394
|
-
globalAttributes: { region: 'us-east-1' }
|
|
395
|
-
}
|
|
396
|
-
})
|
|
397
|
-
await sdk.initialize()
|
|
211
|
+
await project.applyProjectChanges(projectId, changes, options)
|
|
212
|
+
// changes: [['update', ['components', 'Button'], { color: 'blue' }], ['delete', ['pages', 'old']]]
|
|
213
|
+
// options: { message: 'Update button', type: 'patch' }
|
|
398
214
|
|
|
399
|
-
|
|
400
|
-
|
|
215
|
+
await project.getProjectData(projectId, options)
|
|
216
|
+
await project.getProjectVersions(projectId, options)
|
|
217
|
+
await project.restoreProjectVersion(projectId, version, options)
|
|
218
|
+
await project.updateProjectItem(projectId, path, value, options)
|
|
219
|
+
await project.deleteProjectItem(projectId, path, options)
|
|
220
|
+
await project.setProjectValue(projectId, path, value, options)
|
|
221
|
+
await project.addProjectItems(projectId, items, options)
|
|
222
|
+
await project.getProjectItemByPath(projectId, path, options)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Environments:**
|
|
401
226
|
|
|
402
|
-
// 3) Send signals
|
|
403
|
-
tracking.trackEvent('purchase', { amount: 42, currency: 'USD' })
|
|
404
|
-
tracking.trackMeasurement('cart_value', { value: 42 })
|
|
405
|
-
tracking.logError('checkout failed', { step: 'payment' })
|
|
406
|
-
tracking.trackView('Checkout', { stage: 'payment' })
|
|
407
|
-
tracking.setUser({ id: 'u_123', email: 'user@example.com' })
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
#### Configuration
|
|
411
|
-
Provide these under `tracking` when creating the `SDK` (or later via `tracking.configureTracking()`):
|
|
412
|
-
|
|
413
|
-
- `url` string: Frontend Observability/Faro ingestion URL. If omitted and no custom transports are provided, tracking is disabled.
|
|
414
|
-
- `appName` string: Logical application name used in Grafana dashboards.
|
|
415
|
-
- `appVersion` string: App version shown in Grafana.
|
|
416
|
-
- `environment` string: One of your environments; default resolves from runtime (`production`, `staging`, `testing`, `development`).
|
|
417
|
-
- `sessionTracking` boolean: Enable Faro session tracking. Default: `true`.
|
|
418
|
-
- `enableTracing` boolean: Enable web tracing and send to Tempo (if collector configured). Default: `true`.
|
|
419
|
-
- `globalAttributes` object: Key/values merged into every signal.
|
|
420
|
-
- `user` object: Initial user attributes.
|
|
421
|
-
- `maxQueueSize` number: Max queued calls before client setup. Default: `100`.
|
|
422
|
-
- `isolate` boolean: Create an isolated Faro instance.
|
|
423
|
-
- `transports` array | `transport` any: Custom transports (advanced).
|
|
424
|
-
- `instrumentations` array | `instrumentationsFactory(runtime) => Promise<array>` | `webInstrumentationOptions` object: Control Faro web instrumentations.
|
|
425
|
-
|
|
426
|
-
Note:
|
|
427
|
-
- Tracking is automatically disabled in non‑browser environments.
|
|
428
|
-
- Calls are queued until the Faro client is ready. For specific calls, pass `{ queue: false }` to skip queuing.
|
|
429
|
-
|
|
430
|
-
#### Method reference
|
|
431
|
-
The following methods are available via `sdk.getService('tracking')` and map to `utils/services.js`:
|
|
432
|
-
|
|
433
|
-
- `configureTracking(trackingOptions)` / `configure(trackingOptions)`: Merge/override runtime tracking options (supports all config keys above).
|
|
434
|
-
- `trackEvent(name, attributes?, options?)`
|
|
435
|
-
- `name` string (required)
|
|
436
|
-
- `attributes` object merged with global attributes
|
|
437
|
-
- `options` object:
|
|
438
|
-
- `domain` string | null
|
|
439
|
-
- `queue` boolean (whether to queue if client not ready)
|
|
440
|
-
- Additional transport options are forwarded to Faro
|
|
441
|
-
- Example:
|
|
442
|
-
```javascript
|
|
443
|
-
tracking.trackEvent('signup_attempt', { method: 'email' }, { domain: 'auth' })
|
|
444
|
-
```
|
|
445
|
-
- `trackError(error, options?)` / `captureException(error, options?)`
|
|
446
|
-
- `error` Error | string
|
|
447
|
-
- `options` can be:
|
|
448
|
-
- object with Faro error options (`context`, `type`, `stackFrames`, `skipDedupe`, `timestampOverwriteMs`, etc.)
|
|
449
|
-
- or a plain context object (shorthand)
|
|
450
|
-
- `queue` boolean supported
|
|
451
|
-
- Example:
|
|
452
|
-
```javascript
|
|
453
|
-
tracking.trackError(new Error('Login failed'), { context: { screen: 'Login' } })
|
|
454
|
-
```
|
|
455
|
-
- `logMessage(message, level='info', context?)`
|
|
456
|
-
- Convenience wrappers: `logDebug`, `logInfo`, `logWarning`/`logWarn`, `logErrorMessage`/`logError`
|
|
457
|
-
- `message` string | string[]
|
|
458
|
-
- `context` object merged with global attributes
|
|
459
|
-
- Example:
|
|
460
|
-
```javascript
|
|
461
|
-
tracking.logWarning('Slow response', { route: '/checkout', ttfbMs: 900 })
|
|
462
|
-
```
|
|
463
|
-
- `addBreadcrumb(message, attributes?)`
|
|
464
|
-
- Adds a low‑cost breadcrumb via `trackEvent('breadcrumb', ...)`
|
|
465
|
-
- Example:
|
|
466
|
-
```javascript
|
|
467
|
-
tracking.addBreadcrumb('Open modal', { id: 'planLimits' })
|
|
468
|
-
```
|
|
469
|
-
- `trackMeasurement(type, values, options?)`
|
|
470
|
-
- `type` string (required)
|
|
471
|
-
- `values` object | number. If number, it becomes `{ value: <number> }`.
|
|
472
|
-
- `options`:
|
|
473
|
-
- `attributes` object (merged into payload.attributes)
|
|
474
|
-
- `context` object (transport context)
|
|
475
|
-
- `queue` boolean
|
|
476
|
-
- Any additional transport options
|
|
477
|
-
- Example:
|
|
478
|
-
```javascript
|
|
479
|
-
tracking.trackMeasurement('cart_value', 42, { context: { currency: 'USD' } })
|
|
480
|
-
```
|
|
481
|
-
- `trackView(name, attributes?)`
|
|
482
|
-
- Sets the current view/page in Faro
|
|
483
|
-
- Example:
|
|
484
|
-
```javascript
|
|
485
|
-
tracking.trackView('Dashboard', { section: 'Analytics' })
|
|
486
|
-
```
|
|
487
|
-
- `setUser(user, options?)` / `clearUser()`
|
|
488
|
-
- `user` object with arbitrary attributes; supports `{ queue: boolean }`
|
|
489
|
-
- Example:
|
|
490
|
-
```javascript
|
|
491
|
-
tracking.setUser({ id: 'u_123', role: 'admin' })
|
|
492
|
-
```
|
|
493
|
-
- `setSession(session, options?)` / `clearSession()`
|
|
494
|
-
- Attach custom session data; supports `{ queue: boolean, ...sessionOptions }`
|
|
495
|
-
- `setGlobalAttributes(attributes)` / `setGlobalAttribute(key, value)` / `removeGlobalAttribute(key)`
|
|
496
|
-
- Manage the global attributes merged into every signal
|
|
497
|
-
- `flushQueue()`
|
|
498
|
-
- Immediately runs all queued calls (no‑op if client not ready)
|
|
499
|
-
- `getClient()`
|
|
500
|
-
- Returns the underlying Faro client (or `null` if not ready)
|
|
501
|
-
- `isEnabled()` / `isInitialized()`
|
|
502
|
-
- Status helpers
|
|
503
|
-
|
|
504
|
-
#### Example: auth error tracking from services
|
|
505
|
-
The SDK’s services automatically send errors to tracking:
|
|
506
227
|
```javascript
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
228
|
+
await project.listEnvironments(projectId, options)
|
|
229
|
+
await project.activateMultipleEnvironments(projectId, options)
|
|
230
|
+
await project.upsertEnvironment(projectId, envKey, config, options)
|
|
231
|
+
await project.updateEnvironment(projectId, envKey, updates, options)
|
|
232
|
+
await project.publishToEnvironment(projectId, envKey, payload, options)
|
|
233
|
+
await project.deleteEnvironment(projectId, envKey, options)
|
|
234
|
+
await project.promoteEnvironment(projectId, fromEnvKey, toEnvKey, options)
|
|
512
235
|
```
|
|
513
236
|
|
|
514
|
-
|
|
515
|
-
- Use the Frontend Observability (Faro) data source and pick:
|
|
516
|
-
- Service = your `appName`
|
|
517
|
-
- Environment = your `environment`
|
|
518
|
-
- Panels for page loads and Web Vitals require web instrumentations and real page traffic.
|
|
519
|
-
- If self‑hosting with a Faro collector → Loki/Tempo, ensure the FO app is installed and the dashboard uses the FO data source; otherwise create custom panels with LogQL over Loki.
|
|
237
|
+
**Favorites & Recent:**
|
|
520
238
|
|
|
521
|
-
## Error Handling
|
|
522
239
|
```javascript
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}
|
|
240
|
+
await project.getFavoriteProjects()
|
|
241
|
+
await project.addFavoriteProject(projectId)
|
|
242
|
+
await project.removeFavoriteProject(projectId)
|
|
243
|
+
await project.getRecentProjects(options)
|
|
528
244
|
```
|
|
529
245
|
|
|
530
|
-
|
|
246
|
+
**Access Control:**
|
|
247
|
+
|
|
531
248
|
```javascript
|
|
532
|
-
|
|
533
|
-
|
|
249
|
+
await project.setProjectAccess(projectId, access) // account/team/organization/public
|
|
250
|
+
await project.setProjectVisibility(projectId, visibility) // public/private/password-protected
|
|
534
251
|
```
|
|
535
252
|
|
|
536
|
-
|
|
253
|
+
### Branch Service
|
|
254
|
+
|
|
537
255
|
```javascript
|
|
538
|
-
const
|
|
539
|
-
useNewServices: true,
|
|
540
|
-
apiUrl: 'https://api.symbols.app',
|
|
541
|
-
socketUrl: 'https://api.symbols.app',
|
|
542
|
-
timeout: 30000,
|
|
543
|
-
retryAttempts: 3,
|
|
544
|
-
debug: false
|
|
545
|
-
}
|
|
256
|
+
const branch = sdk.getService('branch')
|
|
546
257
|
|
|
547
|
-
|
|
548
|
-
|
|
258
|
+
await branch.listBranches(projectId)
|
|
259
|
+
await branch.createBranch(projectId, branchData)
|
|
260
|
+
await branch.deleteBranch(projectId, branchName)
|
|
261
|
+
await branch.renameBranch(projectId, branchName, newName)
|
|
262
|
+
await branch.getBranchChanges(projectId, branchName, options)
|
|
263
|
+
await branch.mergeBranch(projectId, branchName, mergeData)
|
|
264
|
+
await branch.resetBranch(projectId, branchName)
|
|
265
|
+
await branch.publishVersion(projectId, publishData)
|
|
549
266
|
|
|
550
|
-
|
|
267
|
+
// Helper methods
|
|
268
|
+
await branch.createFeatureBranch(projectId, featureName) // creates 'feature/<name>'
|
|
269
|
+
await branch.createHotfixBranch(projectId, hotfixName)
|
|
270
|
+
await branch.branchExists(projectId, branchName)
|
|
271
|
+
await branch.previewMerge(projectId, sourceBranch, targetBranch)
|
|
272
|
+
await branch.commitMerge(projectId, sourceBranch, options)
|
|
273
|
+
await branch.getBranchStatus(projectId, branchName)
|
|
274
|
+
await branch.deleteBranchSafely(projectId, branchName, options)
|
|
275
|
+
await branch.getBranchesWithStatus(projectId)
|
|
276
|
+
branch.validateBranchName(branchName)
|
|
277
|
+
branch.sanitizeBranchName(branchName)
|
|
278
|
+
```
|
|
551
279
|
|
|
552
|
-
|
|
280
|
+
### Pull Request Service
|
|
553
281
|
|
|
554
282
|
```javascript
|
|
555
|
-
|
|
556
|
-
const canEdit = sdk.hasPermission(projectId, 'edit')
|
|
283
|
+
const pr = sdk.getService('pullRequest')
|
|
557
284
|
|
|
558
|
-
|
|
559
|
-
|
|
285
|
+
await pr.createPullRequest(projectId, pullRequestData)
|
|
286
|
+
await pr.listPullRequests(projectId, options)
|
|
287
|
+
await pr.getPullRequest(projectId, prId)
|
|
288
|
+
await pr.reviewPullRequest(projectId, prId, reviewData)
|
|
289
|
+
await pr.addPullRequestComment(projectId, prId, commentData)
|
|
290
|
+
await pr.mergePullRequest(projectId, prId)
|
|
291
|
+
await pr.getPullRequestDiff(projectId, prId)
|
|
292
|
+
await pr.closePullRequest(projectId, prId)
|
|
293
|
+
await pr.reopenPullRequest(projectId, prId)
|
|
560
294
|
|
|
561
|
-
//
|
|
562
|
-
|
|
295
|
+
// Helper methods
|
|
296
|
+
await pr.approvePullRequest(projectId, prId, comment)
|
|
297
|
+
await pr.requestPullRequestChanges(projectId, prId, threads)
|
|
298
|
+
await pr.getOpenPullRequests(projectId, options)
|
|
299
|
+
await pr.getClosedPullRequests(projectId, options)
|
|
300
|
+
await pr.getMergedPullRequests(projectId, options)
|
|
301
|
+
await pr.isPullRequestMergeable(projectId, prId)
|
|
302
|
+
await pr.getPullRequestStatusSummary(projectId, prId)
|
|
303
|
+
await pr.getPullRequestStats(projectId, options)
|
|
563
304
|
```
|
|
564
305
|
|
|
565
|
-
|
|
306
|
+
### Collab Service
|
|
307
|
+
|
|
308
|
+
Real-time collaboration via WebSocket and Yjs.
|
|
566
309
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|------------|----------|---------------------|-----------|
|
|
570
|
-
| edit | Edit content | editMode, showCode | editMode |
|
|
571
|
-
| view | View content | showContent | canvasPages |
|
|
572
|
-
| design | Access design tools | editMode, showCode | accessToSymbolsLibrary |
|
|
573
|
-
| manage | Project settings | projectSettings, iam | workspaceAdministration |
|
|
310
|
+
```javascript
|
|
311
|
+
const collab = sdk.getService('collab')
|
|
574
312
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
313
|
+
// Connection
|
|
314
|
+
await collab.connect({ projectId, branch, authToken })
|
|
315
|
+
collab.disconnect()
|
|
316
|
+
collab.isConnected()
|
|
317
|
+
collab.getConnectionInfo()
|
|
580
318
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
319
|
+
// Data updates
|
|
320
|
+
collab.updateData(tuples, options)
|
|
321
|
+
collab.addItem(type, data, opts)
|
|
322
|
+
collab.addMultipleItems(items, opts)
|
|
323
|
+
collab.updateItem(type, data, opts)
|
|
324
|
+
collab.deleteItem(type, key, opts)
|
|
586
325
|
|
|
587
|
-
|
|
326
|
+
// Undo/Redo
|
|
327
|
+
collab.undo()
|
|
328
|
+
collab.redo()
|
|
329
|
+
collab.canUndo()
|
|
330
|
+
collab.canRedo()
|
|
331
|
+
collab.getUndoStackSize()
|
|
332
|
+
collab.getRedoStackSize()
|
|
333
|
+
collab.clearUndoHistory()
|
|
334
|
+
collab.checkpoint()
|
|
588
335
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
336
|
+
// Presence
|
|
337
|
+
collab.sendCursor(data)
|
|
338
|
+
collab.sendPresence(data)
|
|
339
|
+
collab.toggleLive(flag)
|
|
593
340
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
} else {
|
|
598
|
-
// Show view-only mode
|
|
599
|
-
sdk.enableViewMode()
|
|
600
|
-
}
|
|
341
|
+
// Accessors
|
|
342
|
+
collab.ydoc // Yjs document
|
|
343
|
+
collab.socket // Socket instance
|
|
601
344
|
```
|
|
602
345
|
|
|
603
|
-
###
|
|
346
|
+
### File Service
|
|
347
|
+
|
|
604
348
|
```javascript
|
|
605
|
-
|
|
606
|
-
const projectTier = 'pro1'
|
|
607
|
-
const copilotTokens = sdk.checkProjectFeature(projectTier, 'aiCopilot')
|
|
349
|
+
const file = sdk.getService('file')
|
|
608
350
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
351
|
+
await file.uploadFile(file, options)
|
|
352
|
+
await file.updateProjectIcon(projectId, iconFile)
|
|
353
|
+
await file.uploadImage(imageFile, options)
|
|
354
|
+
await file.uploadDocument(documentFile, options)
|
|
355
|
+
await file.uploadMultipleFiles(files, options)
|
|
356
|
+
file.getFileUrl(fileId)
|
|
357
|
+
file.validateFile(file, options)
|
|
614
358
|
```
|
|
615
359
|
|
|
616
|
-
###
|
|
360
|
+
### Payment Service
|
|
361
|
+
|
|
617
362
|
```javascript
|
|
618
|
-
|
|
619
|
-
const isProjectAdmin = sdk.checkProjectPermission(
|
|
620
|
-
userRoles,
|
|
621
|
-
projectId,
|
|
622
|
-
'admin'
|
|
623
|
-
)
|
|
363
|
+
const payment = sdk.getService('payment')
|
|
624
364
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
365
|
+
await payment.checkout(options)
|
|
366
|
+
await payment.getSubscriptionStatus(projectId)
|
|
367
|
+
await payment.hasActiveSubscription(projectId)
|
|
368
|
+
await payment.getSubscriptionDetails(projectId)
|
|
369
|
+
await payment.checkoutForPlan(options)
|
|
370
|
+
await payment.checkoutForTeam(options)
|
|
371
|
+
await payment.getSubscriptionSummary(projectId)
|
|
630
372
|
```
|
|
631
373
|
|
|
632
|
-
###
|
|
374
|
+
### Plan Service
|
|
375
|
+
|
|
633
376
|
```javascript
|
|
634
|
-
|
|
635
|
-
const canMerge = projectId => {
|
|
636
|
-
const hasPermission = sdk.hasPermission(projectId, 'merge')
|
|
637
|
-
const isProtectedBranch = sdk.getBranchProtection(projectId)
|
|
377
|
+
const plan = sdk.getService('plan')
|
|
638
378
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
379
|
+
// Public (no auth required)
|
|
380
|
+
await plan.getPlans()
|
|
381
|
+
await plan.getPlan(planId)
|
|
382
|
+
await plan.getPlansWithPricing()
|
|
383
|
+
await plan.getPlanByKey(key)
|
|
384
|
+
await plan.getActivePlans()
|
|
385
|
+
await plan.getPlansByPriceRange(minPrice, maxPrice)
|
|
642
386
|
|
|
643
|
-
|
|
644
|
-
|
|
387
|
+
// Admin
|
|
388
|
+
await plan.getAdminPlans()
|
|
389
|
+
await plan.createPlan(planData)
|
|
390
|
+
await plan.updatePlan(planId, planData)
|
|
391
|
+
await plan.deletePlan(planId)
|
|
392
|
+
await plan.initializePlans()
|
|
645
393
|
```
|
|
646
394
|
|
|
647
|
-
|
|
395
|
+
### Subscription Service
|
|
648
396
|
|
|
649
|
-
### Global Roles
|
|
650
397
|
```javascript
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
398
|
+
const subscription = sdk.getService('subscription')
|
|
399
|
+
|
|
400
|
+
await subscription.createSubscription(subscriptionData)
|
|
401
|
+
await subscription.getProjectStatus(projectId)
|
|
402
|
+
await subscription.getUsage(subscriptionId)
|
|
403
|
+
await subscription.cancelSubscription(subscriptionId)
|
|
404
|
+
await subscription.listInvoices(subscriptionId, options)
|
|
405
|
+
await subscription.getPortalUrl(projectId)
|
|
406
|
+
await subscription.getProjectSubscription(projectId)
|
|
407
|
+
await subscription.getProjectUsage(projectId)
|
|
408
|
+
await subscription.hasActiveSubscription(projectId)
|
|
409
|
+
await subscription.changeSubscription(projectId, planId)
|
|
410
|
+
await subscription.downgrade(projectId)
|
|
657
411
|
```
|
|
658
412
|
|
|
659
|
-
###
|
|
413
|
+
### DNS Service
|
|
414
|
+
|
|
660
415
|
```javascript
|
|
661
|
-
const
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
416
|
+
const dns = sdk.getService('dns')
|
|
417
|
+
|
|
418
|
+
await dns.createDnsRecord(domain, options)
|
|
419
|
+
await dns.getDnsRecord(domain)
|
|
420
|
+
await dns.removeDnsRecord(domain)
|
|
421
|
+
await dns.getCustomHost(hostname)
|
|
422
|
+
await dns.addProjectCustomDomains(projectId, customDomains, options)
|
|
423
|
+
await dns.isDomainAvailable(domain)
|
|
424
|
+
await dns.getDomainStatus(domain)
|
|
425
|
+
await dns.verifyDomainOwnership(domain)
|
|
426
|
+
await dns.getProjectDomains(projectId)
|
|
427
|
+
await dns.removeProjectCustomDomain(projectId, domain)
|
|
428
|
+
dns.validateDomain(domain)
|
|
429
|
+
dns.formatDomain(domain)
|
|
430
|
+
dns.extractDomainFromUrl(url)
|
|
676
431
|
```
|
|
677
432
|
|
|
678
|
-
|
|
433
|
+
### Admin Service
|
|
679
434
|
|
|
680
|
-
1. **Creating New Project**
|
|
681
435
|
```javascript
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
436
|
+
const admin = sdk.getService('admin')
|
|
437
|
+
|
|
438
|
+
await admin.getAdminUsers(params)
|
|
439
|
+
await admin.updateUser(userId, userData)
|
|
440
|
+
await admin.searchAdminUsers(searchQuery, options)
|
|
441
|
+
await admin.getAdminUsersByEmails(emails)
|
|
442
|
+
await admin.getAdminUsersByIds(ids)
|
|
443
|
+
await admin.assignProjectsToUser(userId, options)
|
|
444
|
+
await admin.assignSpecificProjectsToUser(userId, projectIds, role)
|
|
445
|
+
await admin.assignAllProjectsToUser(userId, role)
|
|
446
|
+
await admin.getUserStats(userId)
|
|
447
|
+
await admin.bulkUpdateUsers(updates)
|
|
448
|
+
await admin.getUsersByRole(role)
|
|
449
|
+
await admin.getUsersByStatus(status)
|
|
450
|
+
await admin.activateUser(userId)
|
|
451
|
+
await admin.deactivateUser(userId)
|
|
452
|
+
await admin.suspendUser(userId)
|
|
453
|
+
await admin.promoteToAdmin(userId)
|
|
454
|
+
await admin.demoteFromAdmin(userId)
|
|
686
455
|
```
|
|
687
456
|
|
|
688
|
-
|
|
457
|
+
### Screenshot Service
|
|
458
|
+
|
|
689
459
|
```javascript
|
|
690
|
-
const
|
|
691
|
-
if (canInvite) {
|
|
692
|
-
const tier = sdk.getProjectTier(projectId)
|
|
693
|
-
const maxMembers = TIER_LIMITS[tier].teamMembers
|
|
694
|
-
const currentSize = await sdk.getCurrentTeamSize()
|
|
460
|
+
const screenshot = sdk.getService('screenshot')
|
|
695
461
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
462
|
+
await screenshot.createScreenshotProject(payload)
|
|
463
|
+
await screenshot.getProjectScreenshots(projectKey, params)
|
|
464
|
+
await screenshot.reprocessProjectScreenshots(projectKey, body)
|
|
465
|
+
await screenshot.recreateProjectScreenshots(projectKey, body)
|
|
466
|
+
await screenshot.deleteProjectScreenshots(projectKey)
|
|
467
|
+
await screenshot.getThumbnailCandidate(projectKey, options)
|
|
468
|
+
await screenshot.updateProjectThumbnail(projectKey, body)
|
|
469
|
+
await screenshot.refreshThumbnail(projectKey)
|
|
470
|
+
await screenshot.getPageScreenshot(screenshotId, format)
|
|
471
|
+
await screenshot.getComponentScreenshot(screenshotId, format)
|
|
472
|
+
await screenshot.getScreenshotByKey(key)
|
|
473
|
+
await screenshot.getQueueStatistics()
|
|
700
474
|
```
|
|
701
475
|
|
|
702
|
-
|
|
476
|
+
### Tracking Service (Grafana Faro)
|
|
477
|
+
|
|
703
478
|
```javascript
|
|
704
|
-
const
|
|
705
|
-
const tier = await sdk.getProjectTier(projectId)
|
|
706
|
-
const copilotAccess = sdk.checkProjectFeature(tier, 'aiCopilot')
|
|
479
|
+
const tracking = sdk.getService('tracking')
|
|
707
480
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
}
|
|
715
|
-
}
|
|
481
|
+
// Events
|
|
482
|
+
tracking.trackEvent('purchase', { amount: 42, currency: 'USD' })
|
|
483
|
+
tracking.trackError(new Error('Login failed'), { context: { screen: 'Login' } })
|
|
484
|
+
tracking.captureException(error, context)
|
|
485
|
+
tracking.trackMeasurement('cart_value', 42, { context: { currency: 'USD' } })
|
|
486
|
+
tracking.trackView('Dashboard', { section: 'Analytics' })
|
|
716
487
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
488
|
+
// Logging
|
|
489
|
+
tracking.logMessage(message)
|
|
490
|
+
tracking.logDebug(message)
|
|
491
|
+
tracking.logInfo(message)
|
|
492
|
+
tracking.logWarning(message)
|
|
493
|
+
tracking.logError(message)
|
|
494
|
+
tracking.addBreadcrumb('Open modal', { id: 'planLimits' })
|
|
720
495
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
496
|
+
// User & Session
|
|
497
|
+
tracking.setUser({ id: 'u_123', role: 'admin' })
|
|
498
|
+
tracking.clearUser()
|
|
499
|
+
tracking.setSession(session)
|
|
500
|
+
tracking.clearSession()
|
|
726
501
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
502
|
+
// Global Attributes
|
|
503
|
+
tracking.setGlobalAttributes(attributes)
|
|
504
|
+
tracking.setGlobalAttribute(key, value)
|
|
505
|
+
tracking.removeGlobalAttribute(key)
|
|
506
|
+
|
|
507
|
+
// Queue & Status
|
|
508
|
+
tracking.flushQueue()
|
|
509
|
+
tracking.getClient()
|
|
510
|
+
tracking.isEnabled()
|
|
511
|
+
tracking.isInitialized()
|
|
733
512
|
```
|
|
734
513
|
|
|
735
|
-
|
|
514
|
+
#### Tracking Configuration
|
|
736
515
|
|
|
737
516
|
```javascript
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
console.error('User lacks required permissions')
|
|
748
|
-
break
|
|
749
|
-
case 'TIER_LIMIT_EXCEEDED':
|
|
750
|
-
console.error('Upgrade required for this feature')
|
|
751
|
-
break
|
|
752
|
-
default:
|
|
753
|
-
console.error('Unexpected error:', error)
|
|
517
|
+
const sdk = new SDK({
|
|
518
|
+
tracking: {
|
|
519
|
+
url: 'https://<your-faro-receiver-url>',
|
|
520
|
+
appName: 'Symbols Platform',
|
|
521
|
+
environment: 'production',
|
|
522
|
+
appVersion: '1.0.0',
|
|
523
|
+
sessionTracking: true,
|
|
524
|
+
enableTracing: true,
|
|
525
|
+
globalAttributes: { region: 'us-east-1' }
|
|
754
526
|
}
|
|
755
|
-
}
|
|
527
|
+
})
|
|
756
528
|
```
|
|
757
529
|
|
|
758
|
-
|
|
530
|
+
Tracking is automatically disabled on localhost and in non-browser environments.
|
|
531
|
+
|
|
532
|
+
### Waitlist Service
|
|
533
|
+
|
|
534
|
+
```javascript
|
|
535
|
+
const waitlist = sdk.getService('waitlist')
|
|
759
536
|
|
|
760
|
-
|
|
537
|
+
await waitlist.joinWaitlist(data) // public
|
|
538
|
+
await waitlist.listWaitlistEntries(options) // admin
|
|
539
|
+
await waitlist.updateWaitlistEntry(id, update) // admin
|
|
540
|
+
await waitlist.inviteWaitlistEntry(id) // admin
|
|
541
|
+
```
|
|
761
542
|
|
|
762
|
-
###
|
|
763
|
-
- **Automatic Token Refresh**: Tokens are refreshed automatically before expiration
|
|
764
|
-
- **Persistent Storage**: Tokens persist across page refreshes using localStorage
|
|
765
|
-
- **Secure Handling**: Automatic cleanup on logout and error handling
|
|
766
|
-
- **Flexible Storage**: Supports localStorage, sessionStorage, or memory storage
|
|
543
|
+
### Metrics Service
|
|
767
544
|
|
|
768
|
-
### Configuration
|
|
769
545
|
```javascript
|
|
770
|
-
|
|
546
|
+
const metrics = sdk.getService('metrics')
|
|
771
547
|
|
|
772
|
-
//
|
|
773
|
-
const tokenManager = getTokenManager({
|
|
774
|
-
storageType: 'localStorage', // 'localStorage' | 'sessionStorage' | 'memory'
|
|
775
|
-
refreshBuffer: 60 * 1000, // Refresh 1 minute before expiry
|
|
776
|
-
apiUrl: '/api',
|
|
777
|
-
onTokenRefresh: (tokens) => console.log('Token refreshed'),
|
|
778
|
-
onTokenExpired: () => console.log('Session expired'),
|
|
779
|
-
onTokenError: (error) => console.error('Token error:', error)
|
|
780
|
-
})
|
|
548
|
+
await metrics.getContributions(options) // contribution heat-map stats
|
|
781
549
|
```
|
|
782
550
|
|
|
783
|
-
###
|
|
551
|
+
### Integration Service
|
|
552
|
+
|
|
784
553
|
```javascript
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
554
|
+
const integration = sdk.getService('integration')
|
|
555
|
+
|
|
556
|
+
// Integration management
|
|
557
|
+
await integration.integrationWhoami(apiKey, options)
|
|
558
|
+
await integration.listIntegrations(options)
|
|
559
|
+
await integration.createIntegration(data)
|
|
560
|
+
await integration.updateIntegration(integrationId, update)
|
|
790
561
|
|
|
791
|
-
//
|
|
792
|
-
|
|
562
|
+
// API Keys
|
|
563
|
+
await integration.createIntegrationApiKey(integrationId, data)
|
|
564
|
+
await integration.listIntegrationApiKeys(integrationId)
|
|
565
|
+
await integration.revokeIntegrationApiKey(integrationId, keyId)
|
|
793
566
|
|
|
794
|
-
//
|
|
795
|
-
|
|
796
|
-
|
|
567
|
+
// Webhooks
|
|
568
|
+
await integration.createIntegrationWebhook(integrationId, data)
|
|
569
|
+
await integration.listIntegrationWebhooks(integrationId)
|
|
570
|
+
await integration.updateIntegrationWebhook(integrationId, webhookId, update)
|
|
571
|
+
await integration.deleteIntegrationWebhook(integrationId, webhookId)
|
|
572
|
+
await integration.listIntegrationWebhookDeliveries(integrationId, webhookId, options)
|
|
573
|
+
await integration.replayIntegrationWebhookDelivery(integrationId, webhookId, deliveryId)
|
|
797
574
|
|
|
798
|
-
//
|
|
799
|
-
await
|
|
575
|
+
// GitHub Connectors
|
|
576
|
+
await integration.listGitHubConnectors()
|
|
577
|
+
await integration.createGitHubConnector(data)
|
|
578
|
+
await integration.updateGitHubConnector(connectorId, update)
|
|
579
|
+
await integration.deleteGitHubConnector(connectorId)
|
|
800
580
|
```
|
|
801
581
|
|
|
802
|
-
|
|
582
|
+
### Feature Flag Service
|
|
803
583
|
|
|
804
|
-
### Project Data Management (Symstory Replacement)
|
|
805
584
|
```javascript
|
|
806
|
-
|
|
807
|
-
await symbols.applyProjectChanges('projectId', [
|
|
808
|
-
['update', ['components', 'Button'], { color: 'blue' }],
|
|
809
|
-
['delete', ['pages', 'oldPage']]
|
|
810
|
-
], { message: 'Update button color', type: 'patch' })
|
|
585
|
+
const featureFlag = sdk.getService('featureFlag')
|
|
811
586
|
|
|
812
|
-
//
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
includeHistory: true
|
|
816
|
-
})
|
|
817
|
-
|
|
818
|
-
// Restore to previous version
|
|
819
|
-
await symbols.restoreProjectVersion('projectId', '1.2.0', {
|
|
820
|
-
message: 'Rollback to stable version'
|
|
821
|
-
})
|
|
587
|
+
// User-facing
|
|
588
|
+
await featureFlag.getFeatureFlags(params)
|
|
589
|
+
await featureFlag.getFeatureFlag(key)
|
|
822
590
|
|
|
823
|
-
//
|
|
824
|
-
await
|
|
825
|
-
await
|
|
826
|
-
await
|
|
591
|
+
// Admin
|
|
592
|
+
await featureFlag.getAdminFeatureFlags(params)
|
|
593
|
+
await featureFlag.createFeatureFlag(flagData)
|
|
594
|
+
await featureFlag.updateFeatureFlag(id, patch)
|
|
595
|
+
await featureFlag.archiveFeatureFlag(id)
|
|
827
596
|
```
|
|
828
597
|
|
|
829
|
-
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
## Token Management
|
|
601
|
+
|
|
602
|
+
The SDK includes automatic token management with persistence and refresh:
|
|
603
|
+
|
|
604
|
+
- **Automatic Token Refresh** - tokens are refreshed before expiration
|
|
605
|
+
- **Persistent Storage** - tokens persist across page refreshes via localStorage
|
|
606
|
+
- **Secure Handling** - automatic cleanup on logout
|
|
607
|
+
- **Flexible Storage** - supports localStorage, sessionStorage, or memory
|
|
608
|
+
|
|
830
609
|
```javascript
|
|
831
|
-
|
|
832
|
-
const pr = await symbols.createPullRequest('projectId', {
|
|
833
|
-
source: 'feature/new-ui',
|
|
834
|
-
target: 'main',
|
|
835
|
-
title: 'Add new UI components',
|
|
836
|
-
description: 'Modern UI overhaul'
|
|
837
|
-
})
|
|
610
|
+
import { getTokenManager } from '@symbo.ls/sdk'
|
|
838
611
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
612
|
+
const tokenManager = getTokenManager({
|
|
613
|
+
storageType: 'localStorage', // 'localStorage' | 'sessionStorage' | 'memory'
|
|
614
|
+
refreshBuffer: 60 * 1000, // refresh 1 minute before expiry
|
|
615
|
+
apiUrl: '/api',
|
|
616
|
+
onTokenRefresh: (tokens) => { ... },
|
|
617
|
+
onTokenExpired: () => { ... },
|
|
618
|
+
onTokenError: (error) => { ... }
|
|
844
619
|
})
|
|
620
|
+
```
|
|
845
621
|
|
|
846
|
-
|
|
847
|
-
await symbols.approvePullRequest('projectId', 'pr_123', 'Great work!')
|
|
622
|
+
All authenticated API calls automatically use fresh tokens via the BaseService `_request()` method.
|
|
848
623
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
comment: 'Add error handling',
|
|
855
|
-
type: 'issue'
|
|
856
|
-
}
|
|
857
|
-
])
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
## Permissions
|
|
627
|
+
|
|
628
|
+
### Role Permissions
|
|
858
629
|
|
|
859
|
-
|
|
860
|
-
|
|
630
|
+
```javascript
|
|
631
|
+
// Global roles
|
|
632
|
+
const ROLE_PERMISSIONS = {
|
|
633
|
+
guest: ['viewPublicProjects'],
|
|
634
|
+
user: ['viewPublicProjects', 'createProject'],
|
|
635
|
+
admin: ['viewPublicProjects', 'createProject', 'governance'],
|
|
636
|
+
superAdmin: ['viewPublicProjects', 'createProject', 'governance', 'managePlatform']
|
|
637
|
+
}
|
|
861
638
|
|
|
862
|
-
//
|
|
863
|
-
const
|
|
639
|
+
// Project roles
|
|
640
|
+
const PROJECT_ROLE_PERMISSIONS = {
|
|
641
|
+
guest: ['platformSettings', 'showContent'],
|
|
642
|
+
editor: ['platformSettings', 'showContent', 'showCode', 'editMode', 'versions'],
|
|
643
|
+
admin: [/* editor + */ 'inviteMembers', 'branchProtection', 'projectSettings'],
|
|
644
|
+
owner: [/* admin + */ 'copyPasteAllowanceSetting', 'iam']
|
|
645
|
+
}
|
|
864
646
|
```
|
|
865
647
|
|
|
866
|
-
###
|
|
648
|
+
### Permission Checks
|
|
649
|
+
|
|
867
650
|
```javascript
|
|
868
|
-
|
|
869
|
-
|
|
651
|
+
auth.hasPermission('edit')
|
|
652
|
+
auth.hasGlobalPermission('admin', 'governance')
|
|
653
|
+
auth.checkProjectPermission('editor', 'editMode')
|
|
654
|
+
auth.checkProjectFeature('pro1', 'aiCopilot') // returns tier limit (e.g. 5)
|
|
655
|
+
await auth.canPerformOperation(projectId, 'edit', { checkFeatures: true })
|
|
656
|
+
await auth.withPermission(projectId, 'edit', () => { /* action */ })
|
|
657
|
+
```
|
|
870
658
|
|
|
871
|
-
|
|
872
|
-
await symbols.createFeatureBranch('projectId', 'user authentication')
|
|
873
|
-
// Creates: 'feature/user-authentication'
|
|
659
|
+
### Tier Features
|
|
874
660
|
|
|
875
|
-
|
|
876
|
-
|
|
661
|
+
| Feature | Free | Pro1 | Pro2 |
|
|
662
|
+
|---------|------|------|------|
|
|
663
|
+
| aiCopilot | 3 | 5 | 15 |
|
|
664
|
+
| aiChatbot | 3 | 5 | 15 |
|
|
877
665
|
|
|
878
|
-
|
|
879
|
-
const preview = await symbols.previewMerge('projectId', 'feature/new-ui', 'main')
|
|
880
|
-
if (preview.data.conflicts.length === 0) {
|
|
881
|
-
// Commit merge if no conflicts
|
|
882
|
-
await symbols.commitMerge('projectId', 'feature/new-ui', {
|
|
883
|
-
message: 'Add new UI features',
|
|
884
|
-
type: 'minor'
|
|
885
|
-
})
|
|
886
|
-
}
|
|
666
|
+
---
|
|
887
667
|
|
|
888
|
-
|
|
889
|
-
await symbols.deleteBranchSafely('projectId', 'feature/old-feature')
|
|
668
|
+
## Environment Configuration
|
|
890
669
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
670
|
+
The SDK auto-detects environment from hostname and provides:
|
|
671
|
+
|
|
672
|
+
```javascript
|
|
673
|
+
import { environment } from '@symbo.ls/sdk'
|
|
674
|
+
|
|
675
|
+
environment.apiUrl // HTTP API URL
|
|
676
|
+
environment.socketUrl // WebSocket URL
|
|
677
|
+
environment.features // { trackingEnabled, betaFeatures, newUserOnboarding }
|
|
896
678
|
```
|
|
897
679
|
|
|
898
|
-
|
|
680
|
+
Supported environments: local, development, testing, upcoming, staging, preview, production.
|
|
681
|
+
|
|
682
|
+
---
|
|
899
683
|
|
|
900
|
-
|
|
684
|
+
## Error Handling
|
|
901
685
|
|
|
902
686
|
```javascript
|
|
903
687
|
try {
|
|
904
|
-
await
|
|
688
|
+
await sdk.initialize()
|
|
689
|
+
} catch (error) {
|
|
690
|
+
console.error('SDK initialization failed:', error.message)
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
try {
|
|
694
|
+
await project.mergePullRequest(projectId, prId)
|
|
905
695
|
} catch (error) {
|
|
906
696
|
if (error.message.includes('conflicts')) {
|
|
907
697
|
// Handle merge conflicts
|
|
908
|
-
console.log('Manual conflict resolution required')
|
|
909
698
|
} else if (error.message.includes('403')) {
|
|
910
699
|
// Handle permission errors
|
|
911
|
-
console.log('Insufficient permissions')
|
|
912
|
-
} else {
|
|
913
|
-
// Handle other errors
|
|
914
|
-
console.error('Operation failed:', error.message)
|
|
915
700
|
}
|
|
916
701
|
}
|
|
917
702
|
```
|
|
918
703
|
|
|
704
|
+
---
|
|
919
705
|
|
|
706
|
+
## Direct Service Creation
|
|
707
|
+
|
|
708
|
+
Services can be created independently without the SDK class:
|
|
709
|
+
|
|
710
|
+
```javascript
|
|
711
|
+
import { createAuthService, createProjectService } from '@symbo.ls/sdk'
|
|
712
|
+
|
|
713
|
+
const auth = createAuthService({ context, options })
|
|
714
|
+
await auth.init({ context, options })
|
|
715
|
+
```
|
|
920
716
|
|
|
717
|
+
Available factory functions: `createAuthService`, `createCollabService`, `createProjectService`, `createPlanService`, `createFileService`, `createPaymentService`, `createDnsService`, `createBranchService`, `createPullRequestService`, `createAdminService`, `createSubscriptionService`, `createScreenshotService`, `createTrackingService`, `createWaitlistService`, `createMetricsService`, `createIntegrationService`, `createFeatureFlagService`.
|