@symbo.ls/sdk 2.32.6 → 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
@@ -17490,6 +17490,9 @@ var CONFIG = {
17490
17490
  // For based api
17491
17491
  githubClientId: "Ov23liAFrsR0StbAO6PO",
17492
17492
  // For github api
17493
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/aef64330db80bdfeaac084317bf72f99",
17494
+ // For grafana tracing
17495
+ grafanaAppName: "Localhost Symbols",
17493
17496
  // Environment-specific feature toggles (override common)
17494
17497
  features: {
17495
17498
  betaFeatures: true
@@ -17505,6 +17508,9 @@ var CONFIG = {
17505
17508
  socketUrl: "https://dev.api.symbols.app",
17506
17509
  apiUrl: "https://dev.api.symbols.app",
17507
17510
  githubClientId: "Ov23liHxyWFBxS8f1gnF",
17511
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
17512
+ // For grafana tracing
17513
+ grafanaAppName: "Symbols Dev",
17508
17514
  typesenseCollectionName: "docs",
17509
17515
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
17510
17516
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -17518,6 +17524,9 @@ var CONFIG = {
17518
17524
  basedProject: "platform-v2-sm",
17519
17525
  basedOrg: "symbols",
17520
17526
  githubClientId: "Ov23liHxyWFBxS8f1gnF",
17527
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
17528
+ // For grafana tracing
17529
+ grafanaAppName: "Symbols Test",
17521
17530
  typesenseCollectionName: "docs",
17522
17531
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
17523
17532
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -17528,6 +17537,9 @@ var CONFIG = {
17528
17537
  socketUrl: "https://upcoming.api.symbols.app",
17529
17538
  apiUrl: "https://upcoming.api.symbols.app",
17530
17539
  githubClientId: "Ov23liWF7NvdZ056RV5J",
17540
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
17541
+ // For grafana tracing
17542
+ grafanaAppName: "Symbols Upcoming",
17531
17543
  typesenseCollectionName: "docs",
17532
17544
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
17533
17545
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -17541,6 +17553,9 @@ var CONFIG = {
17541
17553
  basedProject: "platform-v2-sm",
17542
17554
  basedOrg: "symbols",
17543
17555
  githubClientId: "Ov23ligwZDQVD0VfuWNa",
17556
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
17557
+ // For grafana tracing
17558
+ grafanaAppName: "Symbols Staging",
17544
17559
  typesenseCollectionName: "docs",
17545
17560
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
17546
17561
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -17554,6 +17569,9 @@ var CONFIG = {
17554
17569
  basedProject: "platform-v2-sm",
17555
17570
  basedOrg: "symbols",
17556
17571
  githubClientId: "Ov23liFAlOEIXtX3dBtR",
17572
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/5c1089f3c3eea4ec5658e05c3f53baae",
17573
+ // For grafana tracing
17574
+ grafanaAppName: "Symbols",
17557
17575
  typesenseCollectionName: "docs",
17558
17576
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
17559
17577
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -17580,6 +17598,7 @@ var getConfig = () => {
17580
17598
  basedProject: process.env.SYMBOLS_APP_BASED_PROJECT || envConfig.basedProject,
17581
17599
  basedOrg: process.env.SYMBOLS_APP_BASED_ORG || envConfig.basedOrg,
17582
17600
  githubClientId: process.env.SYMBOLS_APP_GITHUB_CLIENT_ID || envConfig.githubClientId,
17601
+ grafanaUrl: process.env.SYMBOLS_APP_GRAFANA_URL || envConfig.grafanaUrl,
17583
17602
  typesenseCollectionName: process.env.TYPESENSE_COLLECTION_NAME || envConfig.typesenseCollectionName,
17584
17603
  typesenseApiKey: process.env.TYPESENSE_API_KEY || envConfig.typesenseApiKey,
17585
17604
  typesenseHost: process.env.TYPESENSE_HOST || envConfig.typesenseHost,
@@ -17750,8 +17769,8 @@ var CollabClient = class {
17750
17769
  __publicField(this, "_buffer", []);
17751
17770
  __publicField(this, "_flushTimer", null);
17752
17771
  __publicField(this, "_clientId", nanoid());
17753
- __publicField(this, "_outboxStore", null);
17754
- // Dexie table
17772
+ __publicField(this, "_outboxStore", createMemoryOutbox());
17773
+ // Dexie table fallback
17755
17774
  __publicField(this, "_readyResolve");
17756
17775
  __publicField(this, "ready", new Promise((res) => this._readyResolve = res));
17757
17776
  /* ---------- private handlers ---------- */
@@ -17793,6 +17812,12 @@ var CollabClient = class {
17793
17812
  await this._outboxStore.clear();
17794
17813
  }
17795
17814
  });
17815
+ __publicField(this, "_onLiveMode", (flag) => {
17816
+ this.live = flag;
17817
+ });
17818
+ __publicField(this, "_onError", (e) => {
17819
+ console.warn("[collab] socket error", e);
17820
+ });
17796
17821
  Object.assign(this, { jwt, projectId, branch, live });
17797
17822
  this.ydoc = new Doc();
17798
17823
  const hasIndexedDB = typeof globalThis.indexedDB !== "undefined";
@@ -17805,14 +17830,11 @@ var CollabClient = class {
17805
17830
  console.warn("[CollabClient] Failed to load IndexeddbPersistence:", err);
17806
17831
  });
17807
17832
  }
17808
- if (typeof window === "undefined" || !hasIndexedDB) {
17809
- this._outboxStore = createMemoryOutbox();
17810
- } else {
17833
+ if (typeof window !== "undefined" && hasIndexedDB) {
17811
17834
  createDexieOutbox(`${projectId}:${branch}`).then((outboxStore) => {
17812
17835
  this._outboxStore = outboxStore;
17813
17836
  }).catch((err) => {
17814
17837
  console.warn("[CollabClient] Failed to load Dexie:", err);
17815
- this._outboxStore = createMemoryOutbox();
17816
17838
  });
17817
17839
  }
17818
17840
  this.socket = lookup2(environment_default.socketUrl, {
@@ -17822,9 +17844,7 @@ var CollabClient = class {
17822
17844
  reconnectionAttempts: Infinity,
17823
17845
  reconnectionDelayMax: 4e3
17824
17846
  });
17825
- this.socket.on("snapshot", this._onSnapshot).on("ops", this._onOps).on("commit", this._onCommit).on("liveMode", (flag) => {
17826
- this.live = flag;
17827
- }).on("connect", this._onConnect).on("error", (e) => console.warn("[collab] socket error", e));
17847
+ 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);
17828
17848
  this._prevJson = this.ydoc.getMap("root").toJSON();
17829
17849
  this.ydoc.on("afterTransaction", (tr) => {
17830
17850
  if (tr.origin === "remote") {
@@ -17871,6 +17891,42 @@ var CollabClient = class {
17871
17891
  });
17872
17892
  this._buffer.length = 0;
17873
17893
  }
17894
+ dispose() {
17895
+ var _a;
17896
+ clearTimeout(this._flushTimer);
17897
+ this._flushTimer = null;
17898
+ this._buffer.length = 0;
17899
+ if ((_a = this._outboxStore) == null ? void 0 : _a.clear) {
17900
+ try {
17901
+ const result = this._outboxStore.clear();
17902
+ if (result && typeof result.catch === "function") {
17903
+ result.catch(() => {
17904
+ });
17905
+ }
17906
+ } catch (error) {
17907
+ console.warn("[CollabClient] Failed to clear outbox store during dispose:", error);
17908
+ }
17909
+ }
17910
+ if (this.socket) {
17911
+ this.socket.off("snapshot", this._onSnapshot);
17912
+ this.socket.off("ops", this._onOps);
17913
+ this.socket.off("commit", this._onCommit);
17914
+ this.socket.off("liveMode", this._onLiveMode);
17915
+ this.socket.off("connect", this._onConnect);
17916
+ this.socket.off("error", this._onError);
17917
+ this.socket.removeAllListeners();
17918
+ this.socket.disconnect();
17919
+ this.socket = null;
17920
+ }
17921
+ if (this.ydoc) {
17922
+ this.ydoc.destroy();
17923
+ this.ydoc = null;
17924
+ }
17925
+ if (typeof this._readyResolve === "function") {
17926
+ this._readyResolve();
17927
+ this._readyResolve = null;
17928
+ }
17929
+ }
17874
17930
  };
17875
17931
  function createMemoryOutbox() {
17876
17932
  const store = /* @__PURE__ */ new Map();
@@ -25,6 +25,9 @@ const CONFIG = {
25
25
  // For based api
26
26
  githubClientId: "Ov23liAFrsR0StbAO6PO",
27
27
  // For github api
28
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/aef64330db80bdfeaac084317bf72f99",
29
+ // For grafana tracing
30
+ grafanaAppName: "Localhost Symbols",
28
31
  // Environment-specific feature toggles (override common)
29
32
  features: {
30
33
  betaFeatures: true
@@ -40,6 +43,9 @@ const CONFIG = {
40
43
  socketUrl: "https://dev.api.symbols.app",
41
44
  apiUrl: "https://dev.api.symbols.app",
42
45
  githubClientId: "Ov23liHxyWFBxS8f1gnF",
46
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
47
+ // For grafana tracing
48
+ grafanaAppName: "Symbols Dev",
43
49
  typesenseCollectionName: "docs",
44
50
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
45
51
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -53,6 +59,9 @@ const CONFIG = {
53
59
  basedProject: "platform-v2-sm",
54
60
  basedOrg: "symbols",
55
61
  githubClientId: "Ov23liHxyWFBxS8f1gnF",
62
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
63
+ // For grafana tracing
64
+ grafanaAppName: "Symbols Test",
56
65
  typesenseCollectionName: "docs",
57
66
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
58
67
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -63,6 +72,9 @@ const CONFIG = {
63
72
  socketUrl: "https://upcoming.api.symbols.app",
64
73
  apiUrl: "https://upcoming.api.symbols.app",
65
74
  githubClientId: "Ov23liWF7NvdZ056RV5J",
75
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
76
+ // For grafana tracing
77
+ grafanaAppName: "Symbols Upcoming",
66
78
  typesenseCollectionName: "docs",
67
79
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
68
80
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -76,6 +88,9 @@ const CONFIG = {
76
88
  basedProject: "platform-v2-sm",
77
89
  basedOrg: "symbols",
78
90
  githubClientId: "Ov23ligwZDQVD0VfuWNa",
91
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/7a3ba473cee2025c68513667024316b8",
92
+ // For grafana tracing
93
+ grafanaAppName: "Symbols Staging",
79
94
  typesenseCollectionName: "docs",
80
95
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
81
96
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -89,6 +104,9 @@ const CONFIG = {
89
104
  basedProject: "platform-v2-sm",
90
105
  basedOrg: "symbols",
91
106
  githubClientId: "Ov23liFAlOEIXtX3dBtR",
107
+ grafanaUrl: "https://faro-collector-prod-us-east-0.grafana.net/collect/5c1089f3c3eea4ec5658e05c3f53baae",
108
+ // For grafana tracing
109
+ grafanaAppName: "Symbols",
92
110
  typesenseCollectionName: "docs",
93
111
  typesenseApiKey: "awmcVpbWqZi9IUgmvslp1C5LKDU8tMjA",
94
112
  typesenseHost: "tl2qpnwxev4cjm36p-1.a1.typesense.net",
@@ -116,6 +134,7 @@ const 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,
@@ -302,10 +302,12 @@ class AuthService extends BaseService {
302
302
  throw new Error(`Password change confirmation failed: ${error.message}`, { cause: error });
303
303
  }
304
304
  }
305
- async getMe() {
305
+ async getMe(options = {}) {
306
306
  this._requireReady("getMe");
307
307
  try {
308
- const response = await this._request("/auth/me", {
308
+ const session = this._resolvePluginSession(options.session);
309
+ const endpoint = session ? `/auth/me?session=${encodeURIComponent(session)}` : "/auth/me";
310
+ const response = await this._request(endpoint, {
309
311
  method: "GET",
310
312
  methodName: "getMe"
311
313
  });
@@ -11,12 +11,20 @@ class CollabService extends BaseService {
11
11
  this._client = null;
12
12
  this._stateManager = null;
13
13
  this._connected = false;
14
+ this._connecting = false;
15
+ this._connectPromise = null;
16
+ this._connectionMeta = null;
17
+ this._pendingConnectReject = null;
14
18
  this._undoStack = [];
15
19
  this._redoStack = [];
16
20
  this._isUndoRedo = false;
17
21
  this._pendingOps = [];
22
+ this._onSocketConnect = this._onSocketConnect.bind(this);
23
+ this._onSocketDisconnect = this._onSocketDisconnect.bind(this);
24
+ this._onSocketError = this._onSocketError.bind(this);
18
25
  }
19
26
  init({ context }) {
27
+ super.init({ context });
20
28
  if (context == null ? void 0 : context.state) {
21
29
  try {
22
30
  this._stateManager = new RootStateManager(context.state);
@@ -80,86 +88,196 @@ class CollabService extends BaseService {
80
88
  }
81
89
  /* ---------- Connection Management ---------- */
82
90
  async connect(options = {}) {
83
- var _a, _b, _c, _d, _e, _f;
84
- this._ensureStateManager();
85
- const {
86
- authToken: jwt,
87
- projectId,
88
- branch = "main",
89
- pro
90
- } = {
91
- ...this._context,
92
- ...options
93
- };
94
- if (!projectId) {
95
- const state = (_a = this._stateManager) == null ? void 0 : _a.root;
96
- const el = state.__element;
97
- el.call("openNotification", {
98
- type: "error",
99
- title: "projectId is required",
100
- message: "projectId is required for CollabService connection"
101
- });
102
- throw new Error("projectId is required for CollabService connection");
103
- }
104
- if (this._client) {
105
- await this.disconnect();
91
+ if (this._connectPromise) {
92
+ return this._connectPromise;
106
93
  }
107
- this._client = new CollabClient({
108
- jwt,
109
- projectId,
110
- branch,
111
- live: Boolean(pro)
112
- });
113
- await new Promise((resolve) => {
114
- var _a2, _b2;
115
- if ((_a2 = this._client.socket) == null ? void 0 : _a2.connected) {
116
- resolve();
117
- } else {
118
- (_b2 = this._client.socket) == null ? void 0 : _b2.once("connect", resolve);
94
+ this._connectPromise = (async () => {
95
+ var _a;
96
+ this._connecting = true;
97
+ this._connected = false;
98
+ this._ensureStateManager();
99
+ const mergedOptions = {
100
+ ...this._context,
101
+ ...options
102
+ };
103
+ let { authToken: jwt } = mergedOptions;
104
+ const {
105
+ projectId,
106
+ branch = "main",
107
+ pro
108
+ } = mergedOptions;
109
+ if (!jwt && this._tokenManager) {
110
+ try {
111
+ jwt = await this._tokenManager.ensureValidToken();
112
+ } catch (error) {
113
+ console.warn("[CollabService] Failed to obtain auth token from token manager", error);
114
+ }
115
+ if (!jwt && typeof this._tokenManager.getAccessToken === "function") {
116
+ jwt = this._tokenManager.getAccessToken();
117
+ }
119
118
  }
120
- });
121
- (_b = this._client.socket) == null ? void 0 : _b.on("ops", ({ changes }) => {
122
- console.log(`ops event`);
123
- this._stateManager.applyChanges(changes, { fromSocket: true });
124
- });
125
- (_c = this._client.socket) == null ? void 0 : _c.on("commit", ({ version }) => {
126
- if (version) {
127
- this._stateManager.setVersion(version);
119
+ if (!jwt) {
120
+ throw new Error("[CollabService] Cannot connect without auth token");
128
121
  }
129
- rootBus.emit("checkpoint:done", { version, origin: "auto" });
130
- });
131
- (_d = this._client.socket) == null ? void 0 : _d.on("clients", this._handleClientsEvent.bind(this));
132
- (_e = this._client.socket) == null ? void 0 : _e.on(
133
- "bundle:done",
134
- this._handleBundleDoneEvent.bind(this)
135
- );
136
- (_f = this._client.socket) == null ? void 0 : _f.on(
137
- "bundle:error",
138
- this._handleBundleErrorEvent.bind(this)
139
- );
140
- if (this._pendingOps.length) {
141
- console.log(
142
- `[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
143
- );
144
- this._pendingOps.forEach(({ changes, granularChanges, orders }) => {
145
- this.socket.emit("ops", { changes, granularChanges, orders, ts: Date.now() });
122
+ this._context = {
123
+ ...this._context,
124
+ authToken: jwt,
125
+ projectId,
126
+ branch,
127
+ pro
128
+ };
129
+ if (!projectId) {
130
+ const state = (_a = this._stateManager) == null ? void 0 : _a.root;
131
+ const el = state.__element;
132
+ el.call("openNotification", {
133
+ type: "error",
134
+ title: "projectId is required",
135
+ message: "projectId is required for CollabService connection"
136
+ });
137
+ throw new Error("projectId is required for CollabService connection");
138
+ }
139
+ if (this._client) {
140
+ await this.disconnect();
141
+ }
142
+ this._client = new CollabClient({
143
+ jwt,
144
+ projectId,
145
+ branch,
146
+ live: Boolean(pro)
147
+ });
148
+ const { socket } = this._client;
149
+ try {
150
+ await new Promise((resolve, reject) => {
151
+ if (!socket) {
152
+ reject(new Error("[CollabService] Socket instance missing"));
153
+ return;
154
+ }
155
+ if (socket.connected) {
156
+ resolve();
157
+ return;
158
+ }
159
+ const cleanup = () => {
160
+ socket.off("connect", handleConnect);
161
+ socket.off("connect_error", handleError);
162
+ socket.off("error", handleError);
163
+ socket.off("disconnect", handleDisconnect);
164
+ if (this._pendingConnectReject === handleError) {
165
+ this._pendingConnectReject = null;
166
+ }
167
+ };
168
+ const handleConnect = () => {
169
+ cleanup();
170
+ resolve();
171
+ };
172
+ const handleError = (error) => {
173
+ cleanup();
174
+ reject(
175
+ error instanceof Error ? error : new Error(String(error || "Unknown connection error"))
176
+ );
177
+ };
178
+ const handleDisconnect = (reason) => {
179
+ handleError(
180
+ reason instanceof Error ? reason : new Error(
181
+ `[CollabService] Socket disconnected before connect: ${reason || "unknown"}`
182
+ )
183
+ );
184
+ };
185
+ this._pendingConnectReject = handleError;
186
+ socket.once("connect", handleConnect);
187
+ socket.once("connect_error", handleError);
188
+ socket.once("error", handleError);
189
+ socket.once("disconnect", handleDisconnect);
190
+ });
191
+ } catch (error) {
192
+ socket == null ? void 0 : socket.disconnect();
193
+ this._client = null;
194
+ this._connectionMeta = null;
195
+ throw error;
196
+ }
197
+ this._attachSocketLifecycleListeners();
198
+ if (socket == null ? void 0 : socket.connected) {
199
+ this._onSocketConnect();
200
+ }
201
+ socket == null ? void 0 : socket.on("ops", ({ changes }) => {
202
+ console.log(`ops event`);
203
+ this._stateManager.applyChanges(changes, { fromSocket: true });
146
204
  });
147
- this._pendingOps.length = 0;
205
+ socket == null ? void 0 : socket.on("commit", ({ version }) => {
206
+ if (version) {
207
+ this._stateManager.setVersion(version);
208
+ }
209
+ rootBus.emit("checkpoint:done", { version, origin: "auto" });
210
+ });
211
+ socket == null ? void 0 : socket.on("clients", this._handleClientsEvent.bind(this));
212
+ socket == null ? void 0 : socket.on(
213
+ "bundle:done",
214
+ this._handleBundleDoneEvent.bind(this)
215
+ );
216
+ socket == null ? void 0 : socket.on(
217
+ "bundle:error",
218
+ this._handleBundleErrorEvent.bind(this)
219
+ );
220
+ if (this._pendingOps.length) {
221
+ console.log(
222
+ `[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
223
+ );
224
+ this._pendingOps.forEach(({ changes, granularChanges, orders }) => {
225
+ this.socket.emit("ops", { changes, granularChanges, orders, ts: Date.now() });
226
+ });
227
+ this._pendingOps.length = 0;
228
+ }
229
+ await this._client.ready;
230
+ this._connectionMeta = {
231
+ projectId,
232
+ branch,
233
+ live: Boolean(pro)
234
+ };
235
+ return this.getConnectionInfo();
236
+ })();
237
+ try {
238
+ return await this._connectPromise;
239
+ } finally {
240
+ this._connecting = false;
241
+ this._connectPromise = null;
148
242
  }
149
- this._connected = true;
150
243
  }
151
244
  disconnect() {
152
245
  var _a;
153
246
  if ((_a = this._client) == null ? void 0 : _a.socket) {
154
- this._client.socket.disconnect();
247
+ if (this._pendingConnectReject) {
248
+ this._pendingConnectReject(new Error("[CollabService] Connection attempt aborted"));
249
+ this._pendingConnectReject = null;
250
+ }
251
+ this._detachSocketLifecycleListeners();
252
+ if (typeof this._client.dispose === "function") {
253
+ this._client.dispose();
254
+ } else {
255
+ this._client.socket.disconnect();
256
+ }
155
257
  }
156
258
  this._client = null;
157
259
  this._connected = false;
260
+ this._connecting = false;
261
+ this._connectionMeta = null;
262
+ this._pendingConnectReject = null;
158
263
  console.log("[CollabService] Disconnected");
159
264
  }
160
265
  isConnected() {
161
266
  var _a, _b;
162
- return this._connected && ((_b = (_a = this._client) == null ? void 0 : _a.socket) == null ? void 0 : _b.connected);
267
+ return Boolean(this._connected && ((_b = (_a = this._client) == null ? void 0 : _a.socket) == null ? void 0 : _b.connected));
268
+ }
269
+ getConnectionInfo() {
270
+ var _a, _b, _c;
271
+ return {
272
+ connected: this.isConnected(),
273
+ connecting: this._connecting,
274
+ projectId: ((_a = this._connectionMeta) == null ? void 0 : _a.projectId) ?? null,
275
+ branch: ((_b = this._connectionMeta) == null ? void 0 : _b.branch) ?? null,
276
+ live: ((_c = this._connectionMeta) == null ? void 0 : _c.live) ?? null,
277
+ pendingOps: this._pendingOps.length,
278
+ undoStackSize: this.getUndoStackSize(),
279
+ redoStackSize: this.getRedoStackSize()
280
+ };
163
281
  }
164
282
  /* convenient shortcuts */
165
283
  get ydoc() {
@@ -526,6 +644,38 @@ class CollabService extends BaseService {
526
644
  rootBus.emit("bundle:error", { project, ticket, error });
527
645
  }
528
646
  /* ---------- Manual checkpoint ---------- */
647
+ _attachSocketLifecycleListeners() {
648
+ var _a;
649
+ const socket = (_a = this._client) == null ? void 0 : _a.socket;
650
+ if (!socket) {
651
+ return;
652
+ }
653
+ socket.on("connect", this._onSocketConnect);
654
+ socket.on("disconnect", this._onSocketDisconnect);
655
+ socket.on("connect_error", this._onSocketError);
656
+ }
657
+ _detachSocketLifecycleListeners() {
658
+ var _a;
659
+ const socket = (_a = this._client) == null ? void 0 : _a.socket;
660
+ if (!socket) {
661
+ return;
662
+ }
663
+ socket.off("connect", this._onSocketConnect);
664
+ socket.off("disconnect", this._onSocketDisconnect);
665
+ socket.off("connect_error", this._onSocketError);
666
+ }
667
+ _onSocketConnect() {
668
+ this._connected = true;
669
+ }
670
+ _onSocketDisconnect(reason) {
671
+ this._connected = false;
672
+ if (reason && reason !== "io client disconnect") {
673
+ console.warn("[CollabService] Socket disconnected", reason);
674
+ }
675
+ }
676
+ _onSocketError(error) {
677
+ console.warn("[CollabService] Socket connection error", error);
678
+ }
529
679
  /**
530
680
  * Manually request a checkpoint / commit of buffered operations on the server.
531
681
  * Resolves with the new version number once the backend confirms via the
@@ -154,7 +154,8 @@ class ProjectService extends BaseService {
154
154
  const {
155
155
  branch = "main",
156
156
  version = "latest",
157
- includeHistory = false
157
+ includeHistory = false,
158
+ headers
158
159
  } = options;
159
160
  const queryParams = new URLSearchParams({
160
161
  branch,
@@ -166,7 +167,8 @@ class ProjectService extends BaseService {
166
167
  `/projects/key/${key}/data?${queryParams}`,
167
168
  {
168
169
  method: "GET",
169
- methodName: "getProjectDataByKey"
170
+ methodName: "getProjectDataByKey",
171
+ ...headers ? { headers } : {}
170
172
  }
171
173
  );
172
174
  if (response.success) {
@@ -357,7 +359,7 @@ class ProjectService extends BaseService {
357
359
  if (!projectId || !email || !role) {
358
360
  throw new Error("Project ID, email, and role are required");
359
361
  }
360
- const { name, callbackUrl } = options;
362
+ const { name, callbackUrl, headers } = options;
361
363
  const defaultCallbackUrl = typeof window === "undefined" ? "https://app.symbols.com/accept-invite" : `${window.location.origin}/accept-invite`;
362
364
  try {
363
365
  const requestBody = {
@@ -371,6 +373,7 @@ class ProjectService extends BaseService {
371
373
  const response = await this._request(`/projects/${projectId}/invite`, {
372
374
  method: "POST",
373
375
  body: JSON.stringify(requestBody),
376
+ ...headers ? { headers } : {},
374
377
  methodName: "inviteMember"
375
378
  });
376
379
  if (response.success) {
@@ -532,7 +535,7 @@ class ProjectService extends BaseService {
532
535
  if (!Array.isArray(changes)) {
533
536
  throw new Error("Changes must be an array");
534
537
  }
535
- const { message, branch = "main", type = "patch" } = options;
538
+ const { message, branch = "main", type = "patch", headers } = options;
536
539
  const state = this._context && this._context.state;
537
540
  const { granularChanges, orders: preprocessorOrders } = preprocessChanges(state, changes, options);
538
541
  const derivedOrders = options.orders || (preprocessorOrders && preprocessorOrders.length ? preprocessorOrders : state ? computeOrdersForTuples(state, granularChanges) : []);
@@ -548,6 +551,7 @@ class ProjectService extends BaseService {
548
551
  type,
549
552
  ...derivedOrders && derivedOrders.length ? { orders: derivedOrders } : {}
550
553
  }),
554
+ ...headers ? { headers } : {},
551
555
  methodName: "applyProjectChanges"
552
556
  });
553
557
  if (response.success) {
@@ -570,7 +574,8 @@ class ProjectService extends BaseService {
570
574
  const {
571
575
  branch = "main",
572
576
  version = "latest",
573
- includeHistory = false
577
+ includeHistory = false,
578
+ headers
574
579
  } = options;
575
580
  const queryParams = new URLSearchParams({
576
581
  branch,
@@ -582,7 +587,8 @@ class ProjectService extends BaseService {
582
587
  `/projects/${projectId}/data?${queryParams}`,
583
588
  {
584
589
  method: "GET",
585
- methodName: "getProjectData"
590
+ methodName: "getProjectData",
591
+ ...headers ? { headers } : {}
586
592
  }
587
593
  );
588
594
  if (response.success) {
@@ -601,7 +607,7 @@ class ProjectService extends BaseService {
601
607
  if (!projectId) {
602
608
  throw new Error("Project ID is required");
603
609
  }
604
- const { branch = "main", page = 1, limit = 50 } = options;
610
+ const { branch = "main", page = 1, limit = 50, headers } = options;
605
611
  const queryParams = new URLSearchParams({
606
612
  branch,
607
613
  page: page.toString(),
@@ -612,7 +618,8 @@ class ProjectService extends BaseService {
612
618
  `/projects/${projectId}/versions?${queryParams}`,
613
619
  {
614
620
  method: "GET",
615
- methodName: "getProjectVersions"
621
+ methodName: "getProjectVersions",
622
+ ...headers ? { headers } : {}
616
623
  }
617
624
  );
618
625
  if (response.success) {
@@ -635,7 +642,7 @@ class ProjectService extends BaseService {
635
642
  if (!version) {
636
643
  throw new Error("Version is required");
637
644
  }
638
- const { message, branch = "main", type = "patch" } = options;
645
+ const { message, branch = "main", type = "patch", headers } = options;
639
646
  try {
640
647
  const response = await this._request(`/projects/${projectId}/restore`, {
641
648
  method: "POST",
@@ -645,6 +652,7 @@ class ProjectService extends BaseService {
645
652
  branch,
646
653
  type
647
654
  }),
655
+ ...headers ? { headers } : {},
648
656
  methodName: "restoreProjectVersion"
649
657
  });
650
658
  if (response.success) {
@@ -794,7 +802,7 @@ class ProjectService extends BaseService {
794
802
  // ==================== RECENT PROJECT METHODS ====================
795
803
  async getRecentProjects(options = {}) {
796
804
  this._requireReady("getRecentProjects");
797
- const { limit = 20 } = options;
805
+ const { limit = 20, headers } = options;
798
806
  const queryString = new URLSearchParams({
799
807
  limit: limit.toString()
800
808
  }).toString();
@@ -802,6 +810,7 @@ class ProjectService extends BaseService {
802
810
  try {
803
811
  const response = await this._request(url, {
804
812
  method: "GET",
813
+ ...headers ? { headers } : {},
805
814
  methodName: "getRecentProjects"
806
815
  });
807
816
  if (response.success) {