@symbo.ls/sdk 3.2.3 → 3.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -0
- package/dist/cjs/config/environment.js +94 -10
- package/dist/cjs/index.js +152 -12
- package/dist/cjs/services/AdminService.js +351 -0
- package/dist/cjs/services/AuthService.js +738 -305
- package/dist/cjs/services/BaseService.js +158 -6
- package/dist/cjs/services/BranchService.js +484 -0
- package/dist/cjs/services/CollabService.js +439 -116
- package/dist/cjs/services/DnsService.js +340 -0
- package/dist/cjs/services/FeatureFlagService.js +175 -0
- package/dist/cjs/services/FileService.js +201 -0
- package/dist/cjs/services/IntegrationService.js +538 -0
- package/dist/cjs/services/MetricsService.js +62 -0
- package/dist/cjs/services/PaymentService.js +271 -0
- package/dist/cjs/services/PlanService.js +426 -0
- package/dist/cjs/services/ProjectService.js +1207 -0
- package/dist/cjs/services/PullRequestService.js +503 -0
- package/dist/cjs/services/ScreenshotService.js +304 -0
- package/dist/cjs/services/SubscriptionService.js +396 -0
- package/dist/cjs/services/TrackingService.js +661 -0
- package/dist/cjs/services/WaitlistService.js +148 -0
- package/dist/cjs/services/index.js +60 -4
- package/dist/cjs/state/RootStateManager.js +2 -23
- package/dist/cjs/state/rootEventBus.js +9 -0
- package/dist/cjs/utils/CollabClient.js +78 -12
- package/dist/cjs/utils/TokenManager.js +16 -3
- package/dist/cjs/utils/changePreprocessor.js +199 -0
- package/dist/cjs/utils/jsonDiff.js +46 -4
- package/dist/cjs/utils/ordering.js +309 -0
- package/dist/cjs/utils/services.js +285 -128
- package/dist/cjs/utils/validation.js +0 -3
- package/dist/esm/config/environment.js +94 -10
- package/dist/esm/index.js +47862 -18248
- package/dist/esm/services/AdminService.js +1132 -0
- package/dist/esm/services/AuthService.js +1493 -386
- package/dist/esm/services/BaseService.js +757 -6
- package/dist/esm/services/BranchService.js +1265 -0
- package/dist/esm/services/CollabService.js +24956 -16089
- package/dist/esm/services/DnsService.js +1121 -0
- package/dist/esm/services/FeatureFlagService.js +956 -0
- package/dist/esm/services/FileService.js +982 -0
- package/dist/esm/services/IntegrationService.js +1319 -0
- package/dist/esm/services/MetricsService.js +843 -0
- package/dist/esm/services/PaymentService.js +1052 -0
- package/dist/esm/services/PlanService.js +1207 -0
- package/dist/esm/services/ProjectService.js +2526 -0
- package/dist/esm/services/PullRequestService.js +1284 -0
- package/dist/esm/services/ScreenshotService.js +1085 -0
- package/dist/esm/services/SubscriptionService.js +1177 -0
- package/dist/esm/services/TrackingService.js +18454 -0
- package/dist/esm/services/WaitlistService.js +929 -0
- package/dist/esm/services/index.js +47373 -18027
- package/dist/esm/state/RootStateManager.js +11 -23
- package/dist/esm/state/rootEventBus.js +9 -0
- package/dist/esm/utils/CollabClient.js +17526 -16120
- package/dist/esm/utils/TokenManager.js +16 -3
- package/dist/esm/utils/changePreprocessor.js +542 -0
- package/dist/esm/utils/jsonDiff.js +958 -43
- package/dist/esm/utils/ordering.js +291 -0
- package/dist/esm/utils/services.js +285 -128
- package/dist/esm/utils/validation.js +116 -50
- package/dist/node/config/environment.js +94 -10
- package/dist/node/index.js +183 -16
- package/dist/node/services/AdminService.js +332 -0
- package/dist/node/services/AuthService.js +742 -310
- package/dist/node/services/BaseService.js +148 -6
- package/dist/node/services/BranchService.js +465 -0
- package/dist/node/services/CollabService.js +439 -116
- package/dist/node/services/DnsService.js +321 -0
- package/dist/node/services/FeatureFlagService.js +156 -0
- package/dist/node/services/FileService.js +182 -0
- package/dist/node/services/IntegrationService.js +519 -0
- package/dist/node/services/MetricsService.js +43 -0
- package/dist/node/services/PaymentService.js +252 -0
- package/dist/node/services/PlanService.js +407 -0
- package/dist/node/services/ProjectService.js +1188 -0
- package/dist/node/services/PullRequestService.js +484 -0
- package/dist/node/services/ScreenshotService.js +285 -0
- package/dist/node/services/SubscriptionService.js +377 -0
- package/dist/node/services/TrackingService.js +632 -0
- package/dist/node/services/WaitlistService.js +129 -0
- package/dist/node/services/index.js +60 -4
- package/dist/node/state/RootStateManager.js +2 -23
- package/dist/node/state/rootEventBus.js +9 -0
- package/dist/node/utils/CollabClient.js +77 -11
- package/dist/node/utils/TokenManager.js +16 -3
- package/dist/node/utils/changePreprocessor.js +180 -0
- package/dist/node/utils/jsonDiff.js +46 -4
- package/dist/node/utils/ordering.js +290 -0
- package/dist/node/utils/services.js +285 -128
- package/dist/node/utils/validation.js +0 -3
- package/package.json +30 -18
- package/src/config/environment.js +95 -10
- package/src/index.js +190 -23
- package/src/services/AdminService.js +374 -0
- package/src/services/AuthService.js +874 -328
- package/src/services/BaseService.js +166 -6
- package/src/services/BranchService.js +536 -0
- package/src/services/CollabService.js +557 -148
- package/src/services/DnsService.js +366 -0
- package/src/services/FeatureFlagService.js +174 -0
- package/src/services/FileService.js +213 -0
- package/src/services/IntegrationService.js +548 -0
- package/src/services/MetricsService.js +40 -0
- package/src/services/PaymentService.js +287 -0
- package/src/services/PlanService.js +468 -0
- package/src/services/ProjectService.js +1366 -0
- package/src/services/PullRequestService.js +537 -0
- package/src/services/ScreenshotService.js +258 -0
- package/src/services/SubscriptionService.js +425 -0
- package/src/services/TrackingService.js +853 -0
- package/src/services/WaitlistService.js +130 -0
- package/src/services/index.js +79 -5
- package/src/services/tests/BranchService/createBranch.test.js +153 -0
- package/src/services/tests/BranchService/deleteBranch.test.js +173 -0
- package/src/services/tests/BranchService/getBranchChanges.test.js +146 -0
- package/src/services/tests/BranchService/listBranches.test.js +87 -0
- package/src/services/tests/BranchService/mergeBranch.test.js +210 -0
- package/src/services/tests/BranchService/publishVersion.test.js +183 -0
- package/src/services/tests/BranchService/renameBranch.test.js +240 -0
- package/src/services/tests/BranchService/resetBranch.test.js +152 -0
- package/src/services/tests/FeatureFlagService/adminFeatureFlags.test.js +67 -0
- package/src/services/tests/FeatureFlagService/getFeatureFlags.test.js +75 -0
- package/src/services/tests/FileService/createFileFormData.test.js +74 -0
- package/src/services/tests/FileService/getFileUrl.test.js +69 -0
- package/src/services/tests/FileService/updateProjectIcon.test.js +109 -0
- package/src/services/tests/FileService/uploadDocument.test.js +36 -0
- package/src/services/tests/FileService/uploadFile.test.js +78 -0
- package/src/services/tests/FileService/uploadFileWithValidation.test.js +114 -0
- package/src/services/tests/FileService/uploadImage.test.js +36 -0
- package/src/services/tests/FileService/uploadMultipleFiles.test.js +111 -0
- package/src/services/tests/FileService/validateFile.test.js +63 -0
- package/src/services/tests/PlanService/createPlan.test.js +104 -0
- package/src/services/tests/PlanService/createPlanWithValidation.test.js +523 -0
- package/src/services/tests/PlanService/deletePlan.test.js +92 -0
- package/src/services/tests/PlanService/getActivePlans.test.js +123 -0
- package/src/services/tests/PlanService/getAdminPlans.test.js +84 -0
- package/src/services/tests/PlanService/getPlan.test.js +50 -0
- package/src/services/tests/PlanService/getPlanByKey.test.js +109 -0
- package/src/services/tests/PlanService/getPlanWithValidation.test.js +85 -0
- package/src/services/tests/PlanService/getPlans.test.js +53 -0
- package/src/services/tests/PlanService/getPlansByPriceRange.test.js +109 -0
- package/src/services/tests/PlanService/getPlansWithValidation.test.js +48 -0
- package/src/services/tests/PlanService/initializePlans.test.js +75 -0
- package/src/services/tests/PlanService/updatePlan.test.js +111 -0
- package/src/services/tests/PlanService/updatePlanWithValidation.test.js +556 -0
- package/src/state/RootStateManager.js +37 -32
- package/src/state/rootEventBus.js +19 -0
- package/src/utils/CollabClient.js +99 -12
- package/src/utils/TokenManager.js +20 -3
- package/src/utils/changePreprocessor.js +239 -0
- package/src/utils/jsonDiff.js +40 -5
- package/src/utils/ordering.js +271 -0
- package/src/utils/services.js +306 -139
- package/src/utils/validation.js +0 -3
- package/dist/cjs/services/AIService.js +0 -155
- package/dist/cjs/services/BasedService.js +0 -1185
- package/dist/cjs/services/CoreService.js +0 -2295
- package/dist/cjs/services/SocketService.js +0 -309
- package/dist/cjs/services/SymstoryService.js +0 -571
- package/dist/cjs/utils/basedQuerys.js +0 -181
- package/dist/cjs/utils/symstoryClient.js +0 -259
- package/dist/esm/services/AIService.js +0 -185
- package/dist/esm/services/BasedService.js +0 -5262
- package/dist/esm/services/CoreService.js +0 -2827
- package/dist/esm/services/SocketService.js +0 -456
- package/dist/esm/services/SymstoryService.js +0 -7025
- package/dist/esm/utils/basedQuerys.js +0 -163
- package/dist/esm/utils/symstoryClient.js +0 -354
- package/dist/node/services/AIService.js +0 -136
- package/dist/node/services/BasedService.js +0 -1156
- package/dist/node/services/CoreService.js +0 -2266
- package/dist/node/services/SocketService.js +0 -280
- package/dist/node/services/SymstoryService.js +0 -542
- package/dist/node/utils/basedQuerys.js +0 -162
- package/dist/node/utils/symstoryClient.js +0 -230
- package/src/services/AIService.js +0 -150
- package/src/services/BasedService.js +0 -1302
- package/src/services/CoreService.js +0 -2548
- package/src/services/SocketService.js +0 -336
- package/src/services/SymstoryService.js +0 -649
- package/src/utils/basedQuerys.js +0 -164
- package/src/utils/symstoryClient.js +0 -252
|
@@ -2,18 +2,54 @@ import { BaseService } from "./BaseService.js";
|
|
|
2
2
|
import { CollabClient } from "../utils/CollabClient.js";
|
|
3
3
|
import { RootStateManager } from "../state/RootStateManager.js";
|
|
4
4
|
import { rootBus } from "../state/rootEventBus.js";
|
|
5
|
+
import { validateParams } from "../utils/validation.js";
|
|
6
|
+
import { deepStringifyFunctions } from "@domql/utils";
|
|
7
|
+
import { preprocessChanges } from "../utils/changePreprocessor.js";
|
|
8
|
+
const FUNCTION_META_KEYS = ["node", "__ref", "__element", "parent", "parse"];
|
|
9
|
+
function stringifyFunctionsForTransport(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
10
|
+
if (value === null || typeof value !== "object") {
|
|
11
|
+
return typeof value === "function" ? value.toString() : value;
|
|
12
|
+
}
|
|
13
|
+
if (seen.has(value)) {
|
|
14
|
+
return seen.get(value);
|
|
15
|
+
}
|
|
16
|
+
const clone = Array.isArray(value) ? [] : {};
|
|
17
|
+
seen.set(value, clone);
|
|
18
|
+
if (Array.isArray(value)) {
|
|
19
|
+
for (let i = 0; i < value.length; i++) {
|
|
20
|
+
clone[i] = stringifyFunctionsForTransport(value[i], seen);
|
|
21
|
+
}
|
|
22
|
+
return clone;
|
|
23
|
+
}
|
|
24
|
+
const keys = Object.keys(value);
|
|
25
|
+
for (let i = 0; i < keys.length; i++) {
|
|
26
|
+
const key = keys[i];
|
|
27
|
+
if (!FUNCTION_META_KEYS.includes(key)) {
|
|
28
|
+
clone[key] = stringifyFunctionsForTransport(value[key], seen);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return clone;
|
|
32
|
+
}
|
|
5
33
|
class CollabService extends BaseService {
|
|
6
34
|
constructor(config) {
|
|
7
35
|
super(config);
|
|
8
36
|
this._client = null;
|
|
9
37
|
this._stateManager = null;
|
|
10
38
|
this._connected = false;
|
|
39
|
+
this._connecting = false;
|
|
40
|
+
this._connectPromise = null;
|
|
41
|
+
this._connectionMeta = null;
|
|
42
|
+
this._pendingConnectReject = null;
|
|
11
43
|
this._undoStack = [];
|
|
12
44
|
this._redoStack = [];
|
|
13
45
|
this._isUndoRedo = false;
|
|
14
46
|
this._pendingOps = [];
|
|
47
|
+
this._onSocketConnect = this._onSocketConnect.bind(this);
|
|
48
|
+
this._onSocketDisconnect = this._onSocketDisconnect.bind(this);
|
|
49
|
+
this._onSocketError = this._onSocketError.bind(this);
|
|
15
50
|
}
|
|
16
51
|
init({ context }) {
|
|
52
|
+
super.init({ context });
|
|
17
53
|
if (context == null ? void 0 : context.state) {
|
|
18
54
|
try {
|
|
19
55
|
this._stateManager = new RootStateManager(context.state);
|
|
@@ -41,90 +77,240 @@ class CollabService extends BaseService {
|
|
|
41
77
|
* caller can react accordingly.
|
|
42
78
|
*/
|
|
43
79
|
_ensureStateManager() {
|
|
44
|
-
var _a;
|
|
80
|
+
var _a, _b;
|
|
45
81
|
if (!this._stateManager) {
|
|
46
82
|
if (!((_a = this._context) == null ? void 0 : _a.state)) {
|
|
47
83
|
throw new Error("[CollabService] Cannot operate without root state");
|
|
48
84
|
}
|
|
49
85
|
this._stateManager = new RootStateManager(this._context.state);
|
|
50
86
|
}
|
|
87
|
+
const root = (_b = this._stateManager) == null ? void 0 : _b.root;
|
|
88
|
+
if (root && !root.__element) {
|
|
89
|
+
root.__element = {
|
|
90
|
+
/**
|
|
91
|
+
* Very small subset of the DOMQL `call` API that we rely on inside the
|
|
92
|
+
* CollabService for browser notifications and data helpers.
|
|
93
|
+
* In a Node.js test context we simply log or return fallbacks.
|
|
94
|
+
*/
|
|
95
|
+
call: (method, ...args) => {
|
|
96
|
+
switch (method) {
|
|
97
|
+
case "openNotification": {
|
|
98
|
+
const [payload = {}] = args;
|
|
99
|
+
const { type = "info", title = "", message = "" } = payload;
|
|
100
|
+
const logger = type === "error" ? console.error : console.log;
|
|
101
|
+
logger(`[Notification] ${title}${message ? ` \u2013 ${message}` : ""}`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
case "deepStringifyFunctions": {
|
|
105
|
+
return deepStringifyFunctions(...args);
|
|
106
|
+
}
|
|
107
|
+
default:
|
|
108
|
+
return {};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
51
113
|
}
|
|
52
114
|
/* ---------- Connection Management ---------- */
|
|
53
115
|
async connect(options = {}) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const {
|
|
57
|
-
authToken: jwt,
|
|
58
|
-
projectId,
|
|
59
|
-
branch = "main",
|
|
60
|
-
pro
|
|
61
|
-
} = {
|
|
62
|
-
...this._context,
|
|
63
|
-
...options
|
|
64
|
-
};
|
|
65
|
-
console.log(jwt, projectId, branch, pro);
|
|
66
|
-
if (!projectId) {
|
|
67
|
-
throw new Error("projectId is required for CollabService connection");
|
|
68
|
-
}
|
|
69
|
-
if (this._client) {
|
|
70
|
-
await this.disconnect();
|
|
116
|
+
if (this._connectPromise) {
|
|
117
|
+
return this._connectPromise;
|
|
71
118
|
}
|
|
72
|
-
|
|
119
|
+
this._connectPromise = (async () => {
|
|
120
|
+
var _a;
|
|
121
|
+
this._connecting = true;
|
|
122
|
+
this._connected = false;
|
|
123
|
+
this._ensureStateManager();
|
|
124
|
+
const mergedOptions = {
|
|
125
|
+
...this._context,
|
|
126
|
+
...options
|
|
127
|
+
};
|
|
128
|
+
let { authToken: jwt } = mergedOptions;
|
|
129
|
+
const { projectId, branch = "main", pro } = mergedOptions;
|
|
130
|
+
if (!jwt && this._tokenManager) {
|
|
131
|
+
try {
|
|
132
|
+
jwt = await this._tokenManager.ensureValidToken();
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.warn(
|
|
135
|
+
"[CollabService] Failed to obtain auth token from token manager",
|
|
136
|
+
error
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
if (!jwt && typeof this._tokenManager.getAccessToken === "function") {
|
|
140
|
+
jwt = this._tokenManager.getAccessToken();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (!jwt) {
|
|
144
|
+
throw new Error("[CollabService] Cannot connect without auth token");
|
|
145
|
+
}
|
|
146
|
+
this._context = {
|
|
147
|
+
...this._context,
|
|
148
|
+
authToken: jwt,
|
|
149
|
+
projectId,
|
|
150
|
+
branch,
|
|
151
|
+
pro
|
|
152
|
+
};
|
|
153
|
+
if (!projectId) {
|
|
154
|
+
const state = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
155
|
+
const el = state.__element;
|
|
156
|
+
el.call("openNotification", {
|
|
157
|
+
type: "error",
|
|
158
|
+
title: "projectId is required",
|
|
159
|
+
message: "projectId is required for CollabService connection"
|
|
160
|
+
});
|
|
161
|
+
throw new Error("projectId is required for CollabService connection");
|
|
162
|
+
}
|
|
163
|
+
if (this._client) {
|
|
164
|
+
await this.disconnect();
|
|
165
|
+
}
|
|
73
166
|
this._client = new CollabClient({
|
|
74
167
|
jwt,
|
|
75
168
|
projectId,
|
|
76
169
|
branch,
|
|
77
170
|
live: Boolean(pro)
|
|
78
171
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
172
|
+
const { socket } = this._client;
|
|
173
|
+
try {
|
|
174
|
+
await new Promise((resolve, reject) => {
|
|
175
|
+
if (!socket) {
|
|
176
|
+
reject(new Error("[CollabService] Socket instance missing"));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (socket.connected) {
|
|
180
|
+
resolve();
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const cleanup = () => {
|
|
184
|
+
socket.off("connect", handleConnect);
|
|
185
|
+
socket.off("connect_error", handleError);
|
|
186
|
+
socket.off("error", handleError);
|
|
187
|
+
socket.off("disconnect", handleDisconnect);
|
|
188
|
+
if (this._pendingConnectReject === handleError) {
|
|
189
|
+
this._pendingConnectReject = null;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
const handleConnect = () => {
|
|
193
|
+
cleanup();
|
|
194
|
+
resolve();
|
|
195
|
+
};
|
|
196
|
+
const handleError = (error) => {
|
|
197
|
+
cleanup();
|
|
198
|
+
reject(
|
|
199
|
+
error instanceof Error ? error : new Error(String(error || "Unknown connection error"))
|
|
200
|
+
);
|
|
201
|
+
};
|
|
202
|
+
const handleDisconnect = (reason) => {
|
|
203
|
+
handleError(
|
|
204
|
+
reason instanceof Error ? reason : new Error(
|
|
205
|
+
`[CollabService] Socket disconnected before connect: ${reason || "unknown"}`
|
|
206
|
+
)
|
|
207
|
+
);
|
|
208
|
+
};
|
|
209
|
+
this._pendingConnectReject = handleError;
|
|
210
|
+
socket.once("connect", handleConnect);
|
|
211
|
+
socket.once("connect_error", handleError);
|
|
212
|
+
socket.once("error", handleError);
|
|
213
|
+
socket.once("disconnect", handleDisconnect);
|
|
214
|
+
});
|
|
215
|
+
} catch (error) {
|
|
216
|
+
socket == null ? void 0 : socket.disconnect();
|
|
217
|
+
this._client = null;
|
|
218
|
+
this._connectionMeta = null;
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
this._attachSocketLifecycleListeners();
|
|
222
|
+
if (socket == null ? void 0 : socket.connected) {
|
|
223
|
+
this._onSocketConnect();
|
|
224
|
+
}
|
|
225
|
+
socket == null ? void 0 : socket.on("ops", ({ changes }) => {
|
|
89
226
|
console.log(`ops event`);
|
|
90
|
-
console.log(changes);
|
|
91
227
|
this._stateManager.applyChanges(changes, { fromSocket: true });
|
|
92
228
|
});
|
|
93
|
-
|
|
94
|
-
|
|
229
|
+
socket == null ? void 0 : socket.on("commit", ({ version }) => {
|
|
230
|
+
if (version) {
|
|
231
|
+
this._stateManager.setVersion(version);
|
|
232
|
+
}
|
|
95
233
|
rootBus.emit("checkpoint:done", { version, origin: "auto" });
|
|
96
234
|
});
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
235
|
+
socket == null ? void 0 : socket.on("clients", this._handleClientsEvent.bind(this));
|
|
236
|
+
socket == null ? void 0 : socket.on("bundle:done", this._handleBundleDoneEvent.bind(this));
|
|
237
|
+
socket == null ? void 0 : socket.on("bundle:error", this._handleBundleErrorEvent.bind(this));
|
|
100
238
|
if (this._pendingOps.length) {
|
|
101
239
|
console.log(
|
|
102
240
|
`[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
|
|
103
241
|
);
|
|
104
|
-
this._pendingOps.forEach(
|
|
105
|
-
|
|
106
|
-
|
|
242
|
+
this._pendingOps.forEach(
|
|
243
|
+
({ changes, granularChanges, orders, options: opOptions }) => {
|
|
244
|
+
const { message } = opOptions || {};
|
|
245
|
+
const ts = Date.now();
|
|
246
|
+
const payload = {
|
|
247
|
+
changes,
|
|
248
|
+
granularChanges,
|
|
249
|
+
orders,
|
|
250
|
+
ts
|
|
251
|
+
};
|
|
252
|
+
if (message) {
|
|
253
|
+
payload.message = message;
|
|
254
|
+
}
|
|
255
|
+
this.socket.emit("ops", payload);
|
|
256
|
+
}
|
|
257
|
+
);
|
|
107
258
|
this._pendingOps.length = 0;
|
|
108
259
|
}
|
|
109
|
-
this.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
260
|
+
await this._client.ready;
|
|
261
|
+
this._connectionMeta = {
|
|
262
|
+
projectId,
|
|
263
|
+
branch,
|
|
264
|
+
live: Boolean(pro)
|
|
265
|
+
};
|
|
266
|
+
return this.getConnectionInfo();
|
|
267
|
+
})();
|
|
268
|
+
try {
|
|
269
|
+
return await this._connectPromise;
|
|
270
|
+
} finally {
|
|
271
|
+
this._connecting = false;
|
|
272
|
+
this._connectPromise = null;
|
|
114
273
|
}
|
|
115
274
|
}
|
|
116
275
|
disconnect() {
|
|
117
276
|
var _a;
|
|
118
277
|
if ((_a = this._client) == null ? void 0 : _a.socket) {
|
|
119
|
-
this.
|
|
278
|
+
if (this._pendingConnectReject) {
|
|
279
|
+
this._pendingConnectReject(
|
|
280
|
+
new Error("[CollabService] Connection attempt aborted")
|
|
281
|
+
);
|
|
282
|
+
this._pendingConnectReject = null;
|
|
283
|
+
}
|
|
284
|
+
this._detachSocketLifecycleListeners();
|
|
285
|
+
if (typeof this._client.dispose === "function") {
|
|
286
|
+
this._client.dispose();
|
|
287
|
+
} else {
|
|
288
|
+
this._client.socket.disconnect();
|
|
289
|
+
}
|
|
120
290
|
}
|
|
121
291
|
this._client = null;
|
|
122
292
|
this._connected = false;
|
|
293
|
+
this._connecting = false;
|
|
294
|
+
this._connectionMeta = null;
|
|
295
|
+
this._pendingConnectReject = null;
|
|
123
296
|
console.log("[CollabService] Disconnected");
|
|
124
297
|
}
|
|
125
298
|
isConnected() {
|
|
126
299
|
var _a, _b;
|
|
127
|
-
return this._connected && ((_b = (_a = this._client) == null ? void 0 : _a.socket) == null ? void 0 : _b.connected);
|
|
300
|
+
return Boolean(this._connected && ((_b = (_a = this._client) == null ? void 0 : _a.socket) == null ? void 0 : _b.connected));
|
|
301
|
+
}
|
|
302
|
+
getConnectionInfo() {
|
|
303
|
+
var _a, _b, _c;
|
|
304
|
+
return {
|
|
305
|
+
connected: this.isConnected(),
|
|
306
|
+
connecting: this._connecting,
|
|
307
|
+
projectId: ((_a = this._connectionMeta) == null ? void 0 : _a.projectId) ?? null,
|
|
308
|
+
branch: ((_b = this._connectionMeta) == null ? void 0 : _b.branch) ?? null,
|
|
309
|
+
live: ((_c = this._connectionMeta) == null ? void 0 : _c.live) ?? null,
|
|
310
|
+
pendingOps: this._pendingOps.length,
|
|
311
|
+
undoStackSize: this.getUndoStackSize(),
|
|
312
|
+
redoStackSize: this.getRedoStackSize()
|
|
313
|
+
};
|
|
128
314
|
}
|
|
129
315
|
/* convenient shortcuts */
|
|
130
316
|
get ydoc() {
|
|
@@ -149,20 +335,47 @@ class CollabService extends BaseService {
|
|
|
149
335
|
}
|
|
150
336
|
/* ---------- data helpers ---------- */
|
|
151
337
|
updateData(tuples, options = {}) {
|
|
152
|
-
var _a;
|
|
338
|
+
var _a, _b;
|
|
153
339
|
this._ensureStateManager();
|
|
154
340
|
const { isUndo = false, isRedo = false } = options;
|
|
155
341
|
if (!isUndo && !isRedo && !this._isUndoRedo) {
|
|
156
342
|
this._trackForUndo(tuples, options);
|
|
157
343
|
}
|
|
344
|
+
const root = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
345
|
+
const { granularChanges: processedTuples, orders } = preprocessChanges(
|
|
346
|
+
root,
|
|
347
|
+
tuples,
|
|
348
|
+
options
|
|
349
|
+
);
|
|
350
|
+
if (options.append && options.append.length) {
|
|
351
|
+
processedTuples.push(...options.append);
|
|
352
|
+
}
|
|
158
353
|
this._stateManager.applyChanges(tuples, { ...options });
|
|
354
|
+
const stringifiedGranularTuples = stringifyFunctionsForTransport(processedTuples);
|
|
355
|
+
const stringifiedTuples = stringifyFunctionsForTransport(tuples);
|
|
356
|
+
const { message } = options;
|
|
159
357
|
if (!this.isConnected()) {
|
|
160
358
|
console.warn("[CollabService] Not connected, queuing real-time update");
|
|
161
|
-
this._pendingOps.push({
|
|
359
|
+
this._pendingOps.push({
|
|
360
|
+
changes: stringifiedTuples,
|
|
361
|
+
granularChanges: stringifiedGranularTuples,
|
|
362
|
+
orders,
|
|
363
|
+
options
|
|
364
|
+
});
|
|
162
365
|
return;
|
|
163
366
|
}
|
|
164
|
-
if ((
|
|
165
|
-
|
|
367
|
+
if ((_b = this.socket) == null ? void 0 : _b.connected) {
|
|
368
|
+
const ts = Date.now();
|
|
369
|
+
const payload = {
|
|
370
|
+
changes: stringifiedTuples,
|
|
371
|
+
granularChanges: stringifiedGranularTuples,
|
|
372
|
+
orders,
|
|
373
|
+
ts
|
|
374
|
+
};
|
|
375
|
+
if (message) {
|
|
376
|
+
payload.message = message;
|
|
377
|
+
}
|
|
378
|
+
this.socket.emit("ops", payload);
|
|
166
379
|
}
|
|
167
380
|
return { success: true };
|
|
168
381
|
}
|
|
@@ -205,7 +418,14 @@ class CollabService extends BaseService {
|
|
|
205
418
|
}
|
|
206
419
|
}
|
|
207
420
|
undo() {
|
|
421
|
+
var _a;
|
|
208
422
|
if (!this._undoStack.length) {
|
|
423
|
+
const state = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
424
|
+
const el = state.__element;
|
|
425
|
+
el.call("openNotification", {
|
|
426
|
+
type: "error",
|
|
427
|
+
title: "Nothing to undo"
|
|
428
|
+
});
|
|
209
429
|
throw new Error("Nothing to undo");
|
|
210
430
|
}
|
|
211
431
|
if (!this.isConnected()) {
|
|
@@ -233,7 +453,14 @@ class CollabService extends BaseService {
|
|
|
233
453
|
return operations;
|
|
234
454
|
}
|
|
235
455
|
redo() {
|
|
456
|
+
var _a;
|
|
236
457
|
if (!this._redoStack.length) {
|
|
458
|
+
const state = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
459
|
+
const el = state.__element;
|
|
460
|
+
el.call("openNotification", {
|
|
461
|
+
type: "error",
|
|
462
|
+
title: "Nothing to redo"
|
|
463
|
+
});
|
|
237
464
|
throw new Error("Nothing to redo");
|
|
238
465
|
}
|
|
239
466
|
if (!this.isConnected()) {
|
|
@@ -278,47 +505,99 @@ class CollabService extends BaseService {
|
|
|
278
505
|
this._redoStack.length = 0;
|
|
279
506
|
}
|
|
280
507
|
addItem(type, data, opts = {}) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
508
|
+
try {
|
|
509
|
+
validateParams.type(type);
|
|
510
|
+
validateParams.data(data, type);
|
|
511
|
+
const { value, ...schema } = data;
|
|
512
|
+
const tuples = [
|
|
513
|
+
["update", [type, data.key], value],
|
|
514
|
+
["update", ["schema", type, data.key], schema || {}]
|
|
515
|
+
];
|
|
516
|
+
const updatedOpts = { ...opts, skipComponentsChangedEvent: true };
|
|
517
|
+
return this.updateData(tuples, updatedOpts);
|
|
518
|
+
} catch (error) {
|
|
519
|
+
throw new Error(`Failed to add item: ${error.message}`, { cause: error });
|
|
520
|
+
}
|
|
288
521
|
}
|
|
289
522
|
addMultipleItems(items, opts = {}) {
|
|
523
|
+
var _a;
|
|
290
524
|
const tuples = [];
|
|
291
|
-
|
|
525
|
+
try {
|
|
526
|
+
items.forEach(([type, data]) => {
|
|
527
|
+
validateParams.type(type);
|
|
528
|
+
validateParams.data(data, type);
|
|
529
|
+
const { value, ...schema } = data;
|
|
530
|
+
tuples.push(
|
|
531
|
+
["update", [type, data.key], value],
|
|
532
|
+
["update", ["schema", type, data.key], schema]
|
|
533
|
+
);
|
|
534
|
+
});
|
|
535
|
+
this.updateData([...tuples, ...opts.append || []], {
|
|
536
|
+
message: `Created ${tuples.length} items`,
|
|
537
|
+
...opts
|
|
538
|
+
});
|
|
539
|
+
return tuples;
|
|
540
|
+
} catch (error) {
|
|
541
|
+
const state = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
542
|
+
const el = state.__element;
|
|
543
|
+
el.call("openNotification", {
|
|
544
|
+
type: "error",
|
|
545
|
+
title: "Failed to add item",
|
|
546
|
+
message: error.message
|
|
547
|
+
});
|
|
548
|
+
throw new Error(`Failed to add item: ${error.message}`, { cause: error });
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
updateItem(type, data, opts = {}) {
|
|
552
|
+
var _a;
|
|
553
|
+
try {
|
|
554
|
+
validateParams.type(type);
|
|
555
|
+
validateParams.data(data, type);
|
|
292
556
|
const { value, ...schema } = data;
|
|
293
|
-
tuples
|
|
557
|
+
const tuples = [
|
|
294
558
|
["update", [type, data.key], value],
|
|
295
559
|
["update", ["schema", type, data.key], schema]
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
return this.updateData(tuples, opts);
|
|
560
|
+
];
|
|
561
|
+
return this.updateData(tuples, opts);
|
|
562
|
+
} catch (error) {
|
|
563
|
+
const state = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
564
|
+
const el = state.__element;
|
|
565
|
+
el.call("openNotification", {
|
|
566
|
+
type: "error",
|
|
567
|
+
title: "Failed to update item",
|
|
568
|
+
message: error.message
|
|
569
|
+
});
|
|
570
|
+
throw new Error(`Failed to update item: ${error.message}`, {
|
|
571
|
+
cause: error
|
|
572
|
+
});
|
|
573
|
+
}
|
|
311
574
|
}
|
|
312
575
|
deleteItem(type, key, opts = {}) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
576
|
+
var _a;
|
|
577
|
+
try {
|
|
578
|
+
validateParams.type(type);
|
|
579
|
+
validateParams.key(key, type);
|
|
580
|
+
const tuples = [
|
|
581
|
+
["delete", [type, key]],
|
|
582
|
+
["delete", ["schema", type, key]],
|
|
583
|
+
...opts.append || []
|
|
584
|
+
];
|
|
585
|
+
return this.updateData(tuples, {
|
|
586
|
+
message: `Deleted ${key} from ${type}`,
|
|
587
|
+
...opts
|
|
588
|
+
});
|
|
589
|
+
} catch (error) {
|
|
590
|
+
const state = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
591
|
+
const el = state.__element;
|
|
592
|
+
el.call("openNotification", {
|
|
593
|
+
type: "error",
|
|
594
|
+
title: "Failed to delete item",
|
|
595
|
+
message: error.message
|
|
596
|
+
});
|
|
597
|
+
throw new Error(`Failed to delete item: ${error.message}`, {
|
|
598
|
+
cause: error
|
|
599
|
+
});
|
|
600
|
+
}
|
|
322
601
|
}
|
|
323
602
|
/* ---------- socket event helpers ---------- */
|
|
324
603
|
/**
|
|
@@ -331,48 +610,92 @@ class CollabService extends BaseService {
|
|
|
331
610
|
var _a;
|
|
332
611
|
const root = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
333
612
|
if (root && typeof root.replace === "function") {
|
|
334
|
-
root.
|
|
335
|
-
{ clients: data },
|
|
336
|
-
{
|
|
337
|
-
fromSocket: true,
|
|
338
|
-
preventUpdate: true
|
|
339
|
-
}
|
|
340
|
-
);
|
|
613
|
+
root.clients = data;
|
|
341
614
|
}
|
|
615
|
+
rootBus.emit("clients:updated", data);
|
|
342
616
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
617
|
+
/* ---------- Dependency bundling events ---------- */
|
|
618
|
+
_handleBundleDoneEvent({
|
|
619
|
+
project,
|
|
620
|
+
ticket,
|
|
621
|
+
dependencies = {},
|
|
622
|
+
schema = {}
|
|
623
|
+
} = {}) {
|
|
624
|
+
var _a;
|
|
625
|
+
console.info("[CollabService] Bundle done", { project, ticket });
|
|
626
|
+
try {
|
|
627
|
+
this._ensureStateManager();
|
|
628
|
+
const { dependencies: schemaDependencies = {} } = schema || {};
|
|
629
|
+
const tuples = [
|
|
630
|
+
["update", ["dependencies"], dependencies],
|
|
631
|
+
["update", ["schema", "dependencies"], schemaDependencies]
|
|
632
|
+
];
|
|
633
|
+
this._stateManager.applyChanges(tuples, {
|
|
634
|
+
fromSocket: true,
|
|
635
|
+
preventFetchDeps: true,
|
|
636
|
+
preventUpdate: ["Iframe"]
|
|
637
|
+
});
|
|
638
|
+
} catch (err) {
|
|
639
|
+
console.error("[CollabService] Failed to update deps after bundle", err);
|
|
352
640
|
}
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
641
|
+
const root = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
642
|
+
const el = root == null ? void 0 : root.__element;
|
|
643
|
+
if (el == null ? void 0 : el.call) {
|
|
644
|
+
el.call("openNotification", {
|
|
645
|
+
type: "success",
|
|
646
|
+
title: "Dependencies ready",
|
|
647
|
+
message: `Project ${project} dependencies have been bundled successfully.`
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
rootBus.emit("bundle:done", { project, ticket });
|
|
651
|
+
}
|
|
652
|
+
_handleBundleErrorEvent({ project, ticket, error } = {}) {
|
|
653
|
+
var _a;
|
|
654
|
+
console.error("[CollabService] Bundle error", { project, ticket, error });
|
|
655
|
+
const root = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
656
|
+
const el = root == null ? void 0 : root.__element;
|
|
657
|
+
if (el == null ? void 0 : el.call) {
|
|
658
|
+
el.call("openNotification", {
|
|
659
|
+
type: "error",
|
|
660
|
+
title: "Dependency bundle failed",
|
|
661
|
+
message: error || `An error occurred while bundling dependencies for project ${project}.`
|
|
662
|
+
});
|
|
360
663
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
664
|
+
rootBus.emit("bundle:error", { project, ticket, error });
|
|
665
|
+
}
|
|
666
|
+
/* ---------- Manual checkpoint ---------- */
|
|
667
|
+
_attachSocketLifecycleListeners() {
|
|
668
|
+
var _a;
|
|
669
|
+
const socket = (_a = this._client) == null ? void 0 : _a.socket;
|
|
670
|
+
if (!socket) {
|
|
671
|
+
return;
|
|
367
672
|
}
|
|
368
|
-
|
|
369
|
-
|
|
673
|
+
socket.on("connect", this._onSocketConnect);
|
|
674
|
+
socket.on("disconnect", this._onSocketDisconnect);
|
|
675
|
+
socket.on("connect_error", this._onSocketError);
|
|
676
|
+
}
|
|
677
|
+
_detachSocketLifecycleListeners() {
|
|
678
|
+
var _a;
|
|
679
|
+
const socket = (_a = this._client) == null ? void 0 : _a.socket;
|
|
680
|
+
if (!socket) {
|
|
681
|
+
return;
|
|
370
682
|
}
|
|
371
|
-
|
|
372
|
-
|
|
683
|
+
socket.off("connect", this._onSocketConnect);
|
|
684
|
+
socket.off("disconnect", this._onSocketDisconnect);
|
|
685
|
+
socket.off("connect_error", this._onSocketError);
|
|
686
|
+
}
|
|
687
|
+
_onSocketConnect() {
|
|
688
|
+
this._connected = true;
|
|
689
|
+
}
|
|
690
|
+
_onSocketDisconnect(reason) {
|
|
691
|
+
this._connected = false;
|
|
692
|
+
if (reason && reason !== "io client disconnect") {
|
|
693
|
+
console.warn("[CollabService] Socket disconnected", reason);
|
|
373
694
|
}
|
|
374
695
|
}
|
|
375
|
-
|
|
696
|
+
_onSocketError(error) {
|
|
697
|
+
console.warn("[CollabService] Socket connection error", error);
|
|
698
|
+
}
|
|
376
699
|
/**
|
|
377
700
|
* Manually request a checkpoint / commit of buffered operations on the server.
|
|
378
701
|
* Resolves with the new version number once the backend confirms via the
|