@symbo.ls/sdk 2.32.7 → 2.32.8

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 (34) hide show
  1. package/dist/cjs/config/environment.js +19 -0
  2. package/dist/cjs/services/AuthService.js +4 -2
  3. package/dist/cjs/services/CollabService.js +214 -64
  4. package/dist/cjs/services/ProjectService.js +19 -10
  5. package/dist/cjs/utils/CollabClient.js +46 -9
  6. package/dist/esm/config/environment.js +19 -0
  7. package/dist/esm/index.js +302 -85
  8. package/dist/esm/services/AdminService.js +19 -0
  9. package/dist/esm/services/AuthService.js +23 -2
  10. package/dist/esm/services/BaseService.js +19 -0
  11. package/dist/esm/services/BranchService.js +19 -0
  12. package/dist/esm/services/CollabService.js +279 -73
  13. package/dist/esm/services/CoreService.js +19 -0
  14. package/dist/esm/services/DnsService.js +19 -0
  15. package/dist/esm/services/FileService.js +19 -0
  16. package/dist/esm/services/PaymentService.js +19 -0
  17. package/dist/esm/services/PlanService.js +19 -0
  18. package/dist/esm/services/ProjectService.js +38 -10
  19. package/dist/esm/services/PullRequestService.js +19 -0
  20. package/dist/esm/services/ScreenshotService.js +19 -0
  21. package/dist/esm/services/SubscriptionService.js +19 -0
  22. package/dist/esm/services/index.js +302 -85
  23. package/dist/esm/utils/CollabClient.js +65 -9
  24. package/dist/node/config/environment.js +19 -0
  25. package/dist/node/services/AuthService.js +4 -2
  26. package/dist/node/services/CollabService.js +214 -64
  27. package/dist/node/services/ProjectService.js +19 -10
  28. package/dist/node/utils/CollabClient.js +46 -9
  29. package/package.json +6 -6
  30. package/src/config/environment.js +20 -1
  31. package/src/services/AuthService.js +7 -2
  32. package/src/services/CollabService.js +258 -77
  33. package/src/services/ProjectService.js +19 -10
  34. package/src/utils/CollabClient.js +51 -8
@@ -48,6 +48,9 @@ const CONFIG = {
48
48
  // For based api
49
49
  githubClientId: "Ov23liAFrsR0StbAO6PO",
50
50
  // For github api
51
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/aef64330db80bdfeaac084317bf72f99",
52
+ // For grafana tracing
53
+ grafanaAppName: "Localhost Symbols",
51
54
  // Environment-specific feature toggles (override common)
52
55
  features: {
53
56
  betaFeatures: true
@@ -63,6 +66,9 @@ const CONFIG = {
63
66
  socketUrl: "https://dev.api.symbols.app",
64
67
  apiUrl: "https://dev.api.symbols.app",
65
68
  githubClientId: "Ov23liHxyWFBxS8f1gnF",
69
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
70
+ // For grafana tracing
71
+ grafanaAppName: "Symbols Dev",
66
72
  typesenseCollectionName: "docs",
67
73
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
68
74
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -76,6 +82,9 @@ const CONFIG = {
76
82
  basedProject: "platform-v2-sm",
77
83
  basedOrg: "symbols",
78
84
  githubClientId: "Ov23liHxyWFBxS8f1gnF",
85
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
86
+ // For grafana tracing
87
+ grafanaAppName: "Symbols Test",
79
88
  typesenseCollectionName: "docs",
80
89
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
81
90
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -86,6 +95,9 @@ const CONFIG = {
86
95
  socketUrl: "https://upcoming.api.symbols.app",
87
96
  apiUrl: "https://upcoming.api.symbols.app",
88
97
  githubClientId: "Ov23liWF7NvdZ056RV5J",
98
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
99
+ // For grafana tracing
100
+ grafanaAppName: "Symbols Upcoming",
89
101
  typesenseCollectionName: "docs",
90
102
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
91
103
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -99,6 +111,9 @@ const CONFIG = {
99
111
  basedProject: "platform-v2-sm",
100
112
  basedOrg: "symbols",
101
113
  githubClientId: "Ov23ligwZDQVD0VfuWNa",
114
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
115
+ // For grafana tracing
116
+ grafanaAppName: "Symbols Staging",
102
117
  typesenseCollectionName: "docs",
103
118
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
104
119
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -112,6 +127,9 @@ const CONFIG = {
112
127
  basedProject: "platform-v2-sm",
113
128
  basedOrg: "symbols",
114
129
  githubClientId: "Ov23liFAlOEIXtX3dBtR",
130
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/5c1089f3c3eea4ec5658e05c3f53baae",
131
+ // For grafana tracing
132
+ grafanaAppName: "Symbols",
115
133
  typesenseCollectionName: "docs",
116
134
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
117
135
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -139,6 +157,7 @@ const getConfig = () => {
139
157
  basedProject: process.env.SYMBOLS_APP_BASED_PROJECT || envConfig.basedProject,
140
158
  basedOrg: process.env.SYMBOLS_APP_BASED_ORG || envConfig.basedOrg,
141
159
  githubClientId: process.env.SYMBOLS_APP_GITHUB_CLIENT_ID || envConfig.githubClientId,
160
+ grafanaUrl: process.env.SYMBOLS_APP_GRAFANA_URL || envConfig.grafanaUrl,
142
161
  typesenseCollectionName: process.env.TYPESENSE_COLLECTION_NAME || envConfig.typesenseCollectionName,
143
162
  typesenseApiKey: process.env.TYPESENSE_API_KEY || envConfig.typesenseApiKey,
144
163
  typesenseHost: process.env.TYPESENSE_HOST || envConfig.typesenseHost,
@@ -320,10 +320,12 @@ class AuthService extends import_BaseService.BaseService {
320
320
  throw new Error(`Password change confirmation failed: ${error.message}`, { cause: error });
321
321
  }
322
322
  }
323
- async getMe() {
323
+ async getMe(options = {}) {
324
324
  this._requireReady("getMe");
325
325
  try {
326
- const response = await this._request("/auth/me", {
326
+ const session = this._resolvePluginSession(options.session);
327
+ const endpoint = session ? `/auth/me?session=${encodeURIComponent(session)}` : "/auth/me";
328
+ const response = await this._request(endpoint, {
327
329
  method: "GET",
328
330
  methodName: "getMe"
329
331
  });
@@ -33,12 +33,20 @@ class CollabService extends import_BaseService.BaseService {
33
33
  this._client = null;
34
34
  this._stateManager = null;
35
35
  this._connected = false;
36
+ this._connecting = false;
37
+ this._connectPromise = null;
38
+ this._connectionMeta = null;
39
+ this._pendingConnectReject = null;
36
40
  this._undoStack = [];
37
41
  this._redoStack = [];
38
42
  this._isUndoRedo = false;
39
43
  this._pendingOps = [];
44
+ this._onSocketConnect = this._onSocketConnect.bind(this);
45
+ this._onSocketDisconnect = this._onSocketDisconnect.bind(this);
46
+ this._onSocketError = this._onSocketError.bind(this);
40
47
  }
41
48
  init({ context }) {
49
+ super.init({ context });
42
50
  if (context == null ? void 0 : context.state) {
43
51
  try {
44
52
  this._stateManager = new import_RootStateManager.RootStateManager(context.state);
@@ -102,86 +110,196 @@ class CollabService extends import_BaseService.BaseService {
102
110
  }
103
111
  /* ---------- Connection Management ---------- */
104
112
  async connect(options = {}) {
105
- var _a, _b, _c, _d, _e, _f;
106
- this._ensureStateManager();
107
- const {
108
- authToken: jwt,
109
- projectId,
110
- branch = "main",
111
- pro
112
- } = {
113
- ...this._context,
114
- ...options
115
- };
116
- if (!projectId) {
117
- const state = (_a = this._stateManager) == null ? void 0 : _a.root;
118
- const el = state.__element;
119
- el.call("openNotification", {
120
- type: "error",
121
- title: "projectId is required",
122
- message: "projectId is required for CollabService connection"
123
- });
124
- throw new Error("projectId is required for CollabService connection");
125
- }
126
- if (this._client) {
127
- await this.disconnect();
113
+ if (this._connectPromise) {
114
+ return this._connectPromise;
128
115
  }
129
- this._client = new import_CollabClient.CollabClient({
130
- jwt,
131
- projectId,
132
- branch,
133
- live: Boolean(pro)
134
- });
135
- await new Promise((resolve) => {
136
- var _a2, _b2;
137
- if ((_a2 = this._client.socket) == null ? void 0 : _a2.connected) {
138
- resolve();
139
- } else {
140
- (_b2 = this._client.socket) == null ? void 0 : _b2.once("connect", resolve);
116
+ this._connectPromise = (async () => {
117
+ var _a;
118
+ this._connecting = true;
119
+ this._connected = false;
120
+ this._ensureStateManager();
121
+ const mergedOptions = {
122
+ ...this._context,
123
+ ...options
124
+ };
125
+ let { authToken: jwt } = mergedOptions;
126
+ const {
127
+ projectId,
128
+ branch = "main",
129
+ pro
130
+ } = mergedOptions;
131
+ if (!jwt && this._tokenManager) {
132
+ try {
133
+ jwt = await this._tokenManager.ensureValidToken();
134
+ } catch (error) {
135
+ console.warn("[CollabService] Failed to obtain auth token from token manager", error);
136
+ }
137
+ if (!jwt && typeof this._tokenManager.getAccessToken === "function") {
138
+ jwt = this._tokenManager.getAccessToken();
139
+ }
141
140
  }
142
- });
143
- (_b = this._client.socket) == null ? void 0 : _b.on("ops", ({ changes }) => {
144
- console.log(`ops event`);
145
- this._stateManager.applyChanges(changes, { fromSocket: true });
146
- });
147
- (_c = this._client.socket) == null ? void 0 : _c.on("commit", ({ version }) => {
148
- if (version) {
149
- this._stateManager.setVersion(version);
141
+ if (!jwt) {
142
+ throw new Error("[CollabService] Cannot connect without auth token");
150
143
  }
151
- import_rootEventBus.rootBus.emit("checkpoint:done", { version, origin: "auto" });
152
- });
153
- (_d = this._client.socket) == null ? void 0 : _d.on("clients", this._handleClientsEvent.bind(this));
154
- (_e = this._client.socket) == null ? void 0 : _e.on(
155
- "bundle:done",
156
- this._handleBundleDoneEvent.bind(this)
157
- );
158
- (_f = this._client.socket) == null ? void 0 : _f.on(
159
- "bundle:error",
160
- this._handleBundleErrorEvent.bind(this)
161
- );
162
- if (this._pendingOps.length) {
163
- console.log(
164
- `[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
165
- );
166
- this._pendingOps.forEach(({ changes, granularChanges, orders }) => {
167
- this.socket.emit("ops", { changes, granularChanges, orders, ts: Date.now() });
144
+ this._context = {
145
+ ...this._context,
146
+ authToken: jwt,
147
+ projectId,
148
+ branch,
149
+ pro
150
+ };
151
+ if (!projectId) {
152
+ const state = (_a = this._stateManager) == null ? void 0 : _a.root;
153
+ const el = state.__element;
154
+ el.call("openNotification", {
155
+ type: "error",
156
+ title: "projectId is required",
157
+ message: "projectId is required for CollabService connection"
158
+ });
159
+ throw new Error("projectId is required for CollabService connection");
160
+ }
161
+ if (this._client) {
162
+ await this.disconnect();
163
+ }
164
+ this._client = new import_CollabClient.CollabClient({
165
+ jwt,
166
+ projectId,
167
+ branch,
168
+ live: Boolean(pro)
169
+ });
170
+ const { socket } = this._client;
171
+ try {
172
+ await new Promise((resolve, reject) => {
173
+ if (!socket) {
174
+ reject(new Error("[CollabService] Socket instance missing"));
175
+ return;
176
+ }
177
+ if (socket.connected) {
178
+ resolve();
179
+ return;
180
+ }
181
+ const cleanup = () => {
182
+ socket.off("connect", handleConnect);
183
+ socket.off("connect_error", handleError);
184
+ socket.off("error", handleError);
185
+ socket.off("disconnect", handleDisconnect);
186
+ if (this._pendingConnectReject === handleError) {
187
+ this._pendingConnectReject = null;
188
+ }
189
+ };
190
+ const handleConnect = () => {
191
+ cleanup();
192
+ resolve();
193
+ };
194
+ const handleError = (error) => {
195
+ cleanup();
196
+ reject(
197
+ error instanceof Error ? error : new Error(String(error || "Unknown connection error"))
198
+ );
199
+ };
200
+ const handleDisconnect = (reason) => {
201
+ handleError(
202
+ reason instanceof Error ? reason : new Error(
203
+ `[CollabService] Socket disconnected before connect: ${reason || "unknown"}`
204
+ )
205
+ );
206
+ };
207
+ this._pendingConnectReject = handleError;
208
+ socket.once("connect", handleConnect);
209
+ socket.once("connect_error", handleError);
210
+ socket.once("error", handleError);
211
+ socket.once("disconnect", handleDisconnect);
212
+ });
213
+ } catch (error) {
214
+ socket == null ? void 0 : socket.disconnect();
215
+ this._client = null;
216
+ this._connectionMeta = null;
217
+ throw error;
218
+ }
219
+ this._attachSocketLifecycleListeners();
220
+ if (socket == null ? void 0 : socket.connected) {
221
+ this._onSocketConnect();
222
+ }
223
+ socket == null ? void 0 : socket.on("ops", ({ changes }) => {
224
+ console.log(`ops event`);
225
+ this._stateManager.applyChanges(changes, { fromSocket: true });
168
226
  });
169
- this._pendingOps.length = 0;
227
+ socket == null ? void 0 : socket.on("commit", ({ version }) => {
228
+ if (version) {
229
+ this._stateManager.setVersion(version);
230
+ }
231
+ import_rootEventBus.rootBus.emit("checkpoint:done", { version, origin: "auto" });
232
+ });
233
+ socket == null ? void 0 : socket.on("clients", this._handleClientsEvent.bind(this));
234
+ socket == null ? void 0 : socket.on(
235
+ "bundle:done",
236
+ this._handleBundleDoneEvent.bind(this)
237
+ );
238
+ socket == null ? void 0 : socket.on(
239
+ "bundle:error",
240
+ this._handleBundleErrorEvent.bind(this)
241
+ );
242
+ if (this._pendingOps.length) {
243
+ console.log(
244
+ `[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
245
+ );
246
+ this._pendingOps.forEach(({ changes, granularChanges, orders }) => {
247
+ this.socket.emit("ops", { changes, granularChanges, orders, ts: Date.now() });
248
+ });
249
+ this._pendingOps.length = 0;
250
+ }
251
+ await this._client.ready;
252
+ this._connectionMeta = {
253
+ projectId,
254
+ branch,
255
+ live: Boolean(pro)
256
+ };
257
+ return this.getConnectionInfo();
258
+ })();
259
+ try {
260
+ return await this._connectPromise;
261
+ } finally {
262
+ this._connecting = false;
263
+ this._connectPromise = null;
170
264
  }
171
- this._connected = true;
172
265
  }
173
266
  disconnect() {
174
267
  var _a;
175
268
  if ((_a = this._client) == null ? void 0 : _a.socket) {
176
- this._client.socket.disconnect();
269
+ if (this._pendingConnectReject) {
270
+ this._pendingConnectReject(new Error("[CollabService] Connection attempt aborted"));
271
+ this._pendingConnectReject = null;
272
+ }
273
+ this._detachSocketLifecycleListeners();
274
+ if (typeof this._client.dispose === "function") {
275
+ this._client.dispose();
276
+ } else {
277
+ this._client.socket.disconnect();
278
+ }
177
279
  }
178
280
  this._client = null;
179
281
  this._connected = false;
282
+ this._connecting = false;
283
+ this._connectionMeta = null;
284
+ this._pendingConnectReject = null;
180
285
  console.log("[CollabService] Disconnected");
181
286
  }
182
287
  isConnected() {
183
288
  var _a, _b;
184
- return this._connected && ((_b = (_a = this._client) == null ? void 0 : _a.socket) == null ? void 0 : _b.connected);
289
+ return Boolean(this._connected && ((_b = (_a = this._client) == null ? void 0 : _a.socket) == null ? void 0 : _b.connected));
290
+ }
291
+ getConnectionInfo() {
292
+ var _a, _b, _c;
293
+ return {
294
+ connected: this.isConnected(),
295
+ connecting: this._connecting,
296
+ projectId: ((_a = this._connectionMeta) == null ? void 0 : _a.projectId) ?? null,
297
+ branch: ((_b = this._connectionMeta) == null ? void 0 : _b.branch) ?? null,
298
+ live: ((_c = this._connectionMeta) == null ? void 0 : _c.live) ?? null,
299
+ pendingOps: this._pendingOps.length,
300
+ undoStackSize: this.getUndoStackSize(),
301
+ redoStackSize: this.getRedoStackSize()
302
+ };
185
303
  }
186
304
  /* convenient shortcuts */
187
305
  get ydoc() {
@@ -548,6 +666,38 @@ class CollabService extends import_BaseService.BaseService {
548
666
  import_rootEventBus.rootBus.emit("bundle:error", { project, ticket, error });
549
667
  }
550
668
  /* ---------- Manual checkpoint ---------- */
669
+ _attachSocketLifecycleListeners() {
670
+ var _a;
671
+ const socket = (_a = this._client) == null ? void 0 : _a.socket;
672
+ if (!socket) {
673
+ return;
674
+ }
675
+ socket.on("connect", this._onSocketConnect);
676
+ socket.on("disconnect", this._onSocketDisconnect);
677
+ socket.on("connect_error", this._onSocketError);
678
+ }
679
+ _detachSocketLifecycleListeners() {
680
+ var _a;
681
+ const socket = (_a = this._client) == null ? void 0 : _a.socket;
682
+ if (!socket) {
683
+ return;
684
+ }
685
+ socket.off("connect", this._onSocketConnect);
686
+ socket.off("disconnect", this._onSocketDisconnect);
687
+ socket.off("connect_error", this._onSocketError);
688
+ }
689
+ _onSocketConnect() {
690
+ this._connected = true;
691
+ }
692
+ _onSocketDisconnect(reason) {
693
+ this._connected = false;
694
+ if (reason && reason !== "io client disconnect") {
695
+ console.warn("[CollabService] Socket disconnected", reason);
696
+ }
697
+ }
698
+ _onSocketError(error) {
699
+ console.warn("[CollabService] Socket connection error", error);
700
+ }
551
701
  /**
552
702
  * Manually request a checkpoint / commit of buffered operations on the server.
553
703
  * Resolves with the new version number once the backend confirms via the
@@ -176,7 +176,8 @@ class ProjectService extends import_BaseService.BaseService {
176
176
  const {
177
177
  branch = "main",
178
178
  version = "latest",
179
- includeHistory = false
179
+ includeHistory = false,
180
+ headers
180
181
  } = options;
181
182
  const queryParams = new URLSearchParams({
182
183
  branch,
@@ -188,7 +189,8 @@ class ProjectService extends import_BaseService.BaseService {
188
189
  `/projects/key/${key}/data?${queryParams}`,
189
190
  {
190
191
  method: "GET",
191
- methodName: "getProjectDataByKey"
192
+ methodName: "getProjectDataByKey",
193
+ ...headers ? { headers } : {}
192
194
  }
193
195
  );
194
196
  if (response.success) {
@@ -379,7 +381,7 @@ class ProjectService extends import_BaseService.BaseService {
379
381
  if (!projectId || !email || !role) {
380
382
  throw new Error("Project ID, email, and role are required");
381
383
  }
382
- const { name, callbackUrl } = options;
384
+ const { name, callbackUrl, headers } = options;
383
385
  const defaultCallbackUrl = typeof window === "undefined" ? "https://app.symbols.com/accept-invite" : `${window.location.origin}/accept-invite`;
384
386
  try {
385
387
  const requestBody = {
@@ -393,6 +395,7 @@ class ProjectService extends import_BaseService.BaseService {
393
395
  const response = await this._request(`/projects/${projectId}/invite`, {
394
396
  method: "POST",
395
397
  body: JSON.stringify(requestBody),
398
+ ...headers ? { headers } : {},
396
399
  methodName: "inviteMember"
397
400
  });
398
401
  if (response.success) {
@@ -554,7 +557,7 @@ class ProjectService extends import_BaseService.BaseService {
554
557
  if (!Array.isArray(changes)) {
555
558
  throw new Error("Changes must be an array");
556
559
  }
557
- const { message, branch = "main", type = "patch" } = options;
560
+ const { message, branch = "main", type = "patch", headers } = options;
558
561
  const state = this._context && this._context.state;
559
562
  const { granularChanges, orders: preprocessorOrders } = (0, import_changePreprocessor.preprocessChanges)(state, changes, options);
560
563
  const derivedOrders = options.orders || (preprocessorOrders && preprocessorOrders.length ? preprocessorOrders : state ? (0, import_ordering.computeOrdersForTuples)(state, granularChanges) : []);
@@ -570,6 +573,7 @@ class ProjectService extends import_BaseService.BaseService {
570
573
  type,
571
574
  ...derivedOrders && derivedOrders.length ? { orders: derivedOrders } : {}
572
575
  }),
576
+ ...headers ? { headers } : {},
573
577
  methodName: "applyProjectChanges"
574
578
  });
575
579
  if (response.success) {
@@ -592,7 +596,8 @@ class ProjectService extends import_BaseService.BaseService {
592
596
  const {
593
597
  branch = "main",
594
598
  version = "latest",
595
- includeHistory = false
599
+ includeHistory = false,
600
+ headers
596
601
  } = options;
597
602
  const queryParams = new URLSearchParams({
598
603
  branch,
@@ -604,7 +609,8 @@ class ProjectService extends import_BaseService.BaseService {
604
609
  `/projects/${projectId}/data?${queryParams}`,
605
610
  {
606
611
  method: "GET",
607
- methodName: "getProjectData"
612
+ methodName: "getProjectData",
613
+ ...headers ? { headers } : {}
608
614
  }
609
615
  );
610
616
  if (response.success) {
@@ -623,7 +629,7 @@ class ProjectService extends import_BaseService.BaseService {
623
629
  if (!projectId) {
624
630
  throw new Error("Project ID is required");
625
631
  }
626
- const { branch = "main", page = 1, limit = 50 } = options;
632
+ const { branch = "main", page = 1, limit = 50, headers } = options;
627
633
  const queryParams = new URLSearchParams({
628
634
  branch,
629
635
  page: page.toString(),
@@ -634,7 +640,8 @@ class ProjectService extends import_BaseService.BaseService {
634
640
  `/projects/${projectId}/versions?${queryParams}`,
635
641
  {
636
642
  method: "GET",
637
- methodName: "getProjectVersions"
643
+ methodName: "getProjectVersions",
644
+ ...headers ? { headers } : {}
638
645
  }
639
646
  );
640
647
  if (response.success) {
@@ -657,7 +664,7 @@ class ProjectService extends import_BaseService.BaseService {
657
664
  if (!version) {
658
665
  throw new Error("Version is required");
659
666
  }
660
- const { message, branch = "main", type = "patch" } = options;
667
+ const { message, branch = "main", type = "patch", headers } = options;
661
668
  try {
662
669
  const response = await this._request(`/projects/${projectId}/restore`, {
663
670
  method: "POST",
@@ -667,6 +674,7 @@ class ProjectService extends import_BaseService.BaseService {
667
674
  branch,
668
675
  type
669
676
  }),
677
+ ...headers ? { headers } : {},
670
678
  methodName: "restoreProjectVersion"
671
679
  });
672
680
  if (response.success) {
@@ -816,7 +824,7 @@ class ProjectService extends import_BaseService.BaseService {
816
824
  // ==================== RECENT PROJECT METHODS ====================
817
825
  async getRecentProjects(options = {}) {
818
826
  this._requireReady("getRecentProjects");
819
- const { limit = 20 } = options;
827
+ const { limit = 20, headers } = options;
820
828
  const queryString = new URLSearchParams({
821
829
  limit: limit.toString()
822
830
  }).toString();
@@ -824,6 +832,7 @@ class ProjectService extends import_BaseService.BaseService {
824
832
  try {
825
833
  const response = await this._request(url, {
826
834
  method: "GET",
835
+ ...headers ? { headers } : {},
827
836
  methodName: "getRecentProjects"
828
837
  });
829
838
  if (response.success) {
@@ -47,8 +47,8 @@ class CollabClient {
47
47
  _buffer = [];
48
48
  _flushTimer = null;
49
49
  _clientId = (0, import_nanoid.nanoid)();
50
- _outboxStore = null;
51
- // Dexie table
50
+ _outboxStore = createMemoryOutbox();
51
+ // Dexie table fallback
52
52
  _readyResolve;
53
53
  ready = new Promise((res) => this._readyResolve = res);
54
54
  constructor({ jwt, projectId, branch = "main", live = false }) {
@@ -64,14 +64,11 @@ class CollabClient {
64
64
  console.warn("[CollabClient] Failed to load IndexeddbPersistence:", err);
65
65
  });
66
66
  }
67
- if (typeof window === "undefined" || !hasIndexedDB) {
68
- this._outboxStore = createMemoryOutbox();
69
- } else {
67
+ if (typeof window !== "undefined" && hasIndexedDB) {
70
68
  createDexieOutbox(`${projectId}:${branch}`).then((outboxStore) => {
71
69
  this._outboxStore = outboxStore;
72
70
  }).catch((err) => {
73
71
  console.warn("[CollabClient] Failed to load Dexie:", err);
74
- this._outboxStore = createMemoryOutbox();
75
72
  });
76
73
  }
77
74
  this.socket = (0, import_socket.io)(import_environment.default.socketUrl, {
@@ -81,9 +78,7 @@ class CollabClient {
81
78
  reconnectionAttempts: Infinity,
82
79
  reconnectionDelayMax: 4e3
83
80
  });
84
- this.socket.on("snapshot", this._onSnapshot).on("ops", this._onOps).on("commit", this._onCommit).on("liveMode", (flag) => {
85
- this.live = flag;
86
- }).on("connect", this._onConnect).on("error", (e) => console.warn("[collab] socket error", e));
81
+ this.socket.on("snapshot", this._onSnapshot).on("ops", this._onOps).on("commit", this._onCommit).on("liveMode", this._onLiveMode).on("connect", this._onConnect).on("error", this._onError);
87
82
  this._prevJson = this.ydoc.getMap("root").toJSON();
88
83
  this.ydoc.on("afterTransaction", (tr) => {
89
84
  if (tr.origin === "remote") {
@@ -169,6 +164,48 @@ class CollabClient {
169
164
  });
170
165
  this._buffer.length = 0;
171
166
  }
167
+ dispose() {
168
+ var _a;
169
+ clearTimeout(this._flushTimer);
170
+ this._flushTimer = null;
171
+ this._buffer.length = 0;
172
+ if ((_a = this._outboxStore) == null ? void 0 : _a.clear) {
173
+ try {
174
+ const result = this._outboxStore.clear();
175
+ if (result && typeof result.catch === "function") {
176
+ result.catch(() => {
177
+ });
178
+ }
179
+ } catch (error) {
180
+ console.warn("[CollabClient] Failed to clear outbox store during dispose:", error);
181
+ }
182
+ }
183
+ if (this.socket) {
184
+ this.socket.off("snapshot", this._onSnapshot);
185
+ this.socket.off("ops", this._onOps);
186
+ this.socket.off("commit", this._onCommit);
187
+ this.socket.off("liveMode", this._onLiveMode);
188
+ this.socket.off("connect", this._onConnect);
189
+ this.socket.off("error", this._onError);
190
+ this.socket.removeAllListeners();
191
+ this.socket.disconnect();
192
+ this.socket = null;
193
+ }
194
+ if (this.ydoc) {
195
+ this.ydoc.destroy();
196
+ this.ydoc = null;
197
+ }
198
+ if (typeof this._readyResolve === "function") {
199
+ this._readyResolve();
200
+ this._readyResolve = null;
201
+ }
202
+ }
203
+ _onLiveMode = (flag) => {
204
+ this.live = flag;
205
+ };
206
+ _onError = (e) => {
207
+ console.warn("[collab] socket error", e);
208
+ };
172
209
  }
173
210
  function createMemoryOutbox() {
174
211
  const store = /* @__PURE__ */ new Map();
@@ -26,6 +26,9 @@ var CONFIG = {
26
26
  // For based api
27
27
  githubClientId: "Ov23liAFrsR0StbAO6PO",
28
28
  // For github api
29
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/aef64330db80bdfeaac084317bf72f99",
30
+ // For grafana tracing
31
+ grafanaAppName: "Localhost Symbols",
29
32
  // Environment-specific feature toggles (override common)
30
33
  features: {
31
34
  betaFeatures: true
@@ -41,6 +44,9 @@ var CONFIG = {
41
44
  socketUrl: "https://dev.api.symbols.app",
42
45
  apiUrl: "https://dev.api.symbols.app",
43
46
  githubClientId: "Ov23liHxyWFBxS8f1gnF",
47
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
48
+ // For grafana tracing
49
+ grafanaAppName: "Symbols Dev",
44
50
  typesenseCollectionName: "docs",
45
51
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
46
52
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -54,6 +60,9 @@ var CONFIG = {
54
60
  basedProject: "platform-v2-sm",
55
61
  basedOrg: "symbols",
56
62
  githubClientId: "Ov23liHxyWFBxS8f1gnF",
63
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
64
+ // For grafana tracing
65
+ grafanaAppName: "Symbols Test",
57
66
  typesenseCollectionName: "docs",
58
67
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
59
68
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -64,6 +73,9 @@ var CONFIG = {
64
73
  socketUrl: "https://upcoming.api.symbols.app",
65
74
  apiUrl: "https://upcoming.api.symbols.app",
66
75
  githubClientId: "Ov23liWF7NvdZ056RV5J",
76
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
77
+ // For grafana tracing
78
+ grafanaAppName: "Symbols Upcoming",
67
79
  typesenseCollectionName: "docs",
68
80
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
69
81
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -77,6 +89,9 @@ var CONFIG = {
77
89
  basedProject: "platform-v2-sm",
78
90
  basedOrg: "symbols",
79
91
  githubClientId: "Ov23ligwZDQVD0VfuWNa",
92
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
93
+ // For grafana tracing
94
+ grafanaAppName: "Symbols Staging",
80
95
  typesenseCollectionName: "docs",
81
96
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
82
97
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -90,6 +105,9 @@ var CONFIG = {
90
105
  basedProject: "platform-v2-sm",
91
106
  basedOrg: "symbols",
92
107
  githubClientId: "Ov23liFAlOEIXtX3dBtR",
108
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/5c1089f3c3eea4ec5658e05c3f53baae",
109
+ // For grafana tracing
110
+ grafanaAppName: "Symbols",
93
111
  typesenseCollectionName: "docs",
94
112
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
95
113
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -116,6 +134,7 @@ var getConfig = () => {
116
134
  basedProject: process.env.SYMBOLS_APP_BASED_PROJECT || envConfig.basedProject,
117
135
  basedOrg: process.env.SYMBOLS_APP_BASED_ORG || envConfig.basedOrg,
118
136
  githubClientId: process.env.SYMBOLS_APP_GITHUB_CLIENT_ID || envConfig.githubClientId,
137
+ grafanaUrl: process.env.SYMBOLS_APP_GRAFANA_URL || envConfig.grafanaUrl,
119
138
  typesenseCollectionName: process.env.TYPESENSE_COLLECTION_NAME || envConfig.typesenseCollectionName,
120
139
  typesenseApiKey: process.env.TYPESENSE_API_KEY || envConfig.typesenseApiKey,
121
140
  typesenseHost: process.env.TYPESENSE_HOST || envConfig.typesenseHost,