mindcache 2.2.0 → 2.3.0
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/dist/cloud/index.d.mts +2 -2
- package/dist/cloud/index.d.ts +2 -2
- package/dist/cloud/index.js +93 -27
- package/dist/cloud/index.js.map +1 -1
- package/dist/cloud/index.mjs +93 -27
- package/dist/cloud/index.mjs.map +1 -1
- package/dist/{index-XM7bmK7C.d.mts → index-DXb0fL3e.d.mts} +30 -3
- package/dist/{index-XM7bmK7C.d.ts → index-DXb0fL3e.d.ts} +30 -3
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +93 -27
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +93 -27
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cloud/index.mjs
CHANGED
|
@@ -15,16 +15,17 @@ var CloudAdapter_exports = {};
|
|
|
15
15
|
__export(CloudAdapter_exports, {
|
|
16
16
|
CloudAdapter: () => CloudAdapter
|
|
17
17
|
});
|
|
18
|
-
var
|
|
18
|
+
var RECONNECT_DELAY, MAX_RECONNECT_DELAY, CloudAdapter;
|
|
19
19
|
var init_CloudAdapter = __esm({
|
|
20
20
|
"src/cloud/CloudAdapter.ts"() {
|
|
21
|
-
DEFAULT_BASE_URL = "wss://api.mindcache.io";
|
|
22
21
|
RECONNECT_DELAY = 1e3;
|
|
23
22
|
MAX_RECONNECT_DELAY = 3e4;
|
|
24
23
|
CloudAdapter = class {
|
|
25
24
|
constructor(config) {
|
|
26
25
|
this.config = config;
|
|
27
|
-
|
|
26
|
+
if (!config.baseUrl) {
|
|
27
|
+
throw new Error("MindCache Cloud: baseUrl is required. Please provide the cloud API URL in your configuration.");
|
|
28
|
+
}
|
|
28
29
|
}
|
|
29
30
|
ws = null;
|
|
30
31
|
queue = [];
|
|
@@ -85,6 +86,40 @@ var init_CloudAdapter = __esm({
|
|
|
85
86
|
}
|
|
86
87
|
this.mindcache = null;
|
|
87
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Fetch a short-lived WebSocket token from the API using the API key.
|
|
91
|
+
* This keeps the API key secure by only using it for a single HTTPS request,
|
|
92
|
+
* then using the short-lived token for the WebSocket connection.
|
|
93
|
+
*
|
|
94
|
+
* Supports two key formats:
|
|
95
|
+
* - API keys: mc_live_xxx or mc_test_xxx → Bearer token
|
|
96
|
+
* - Delegate keys: del_xxx:sec_xxx → ApiKey format
|
|
97
|
+
*/
|
|
98
|
+
async fetchTokenWithApiKey() {
|
|
99
|
+
if (!this.config.apiKey) {
|
|
100
|
+
throw new Error("API key is required to fetch token");
|
|
101
|
+
}
|
|
102
|
+
const httpBaseUrl = this.config.baseUrl.replace("wss://", "https://").replace("ws://", "http://");
|
|
103
|
+
const isDelegate = this.config.apiKey.startsWith("del_") && this.config.apiKey.includes(":");
|
|
104
|
+
const authHeader = isDelegate ? `ApiKey ${this.config.apiKey}` : `Bearer ${this.config.apiKey}`;
|
|
105
|
+
const response = await fetch(`${httpBaseUrl}/api/ws-token`, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: {
|
|
108
|
+
"Content-Type": "application/json",
|
|
109
|
+
"Authorization": authHeader
|
|
110
|
+
},
|
|
111
|
+
body: JSON.stringify({
|
|
112
|
+
instanceId: this.config.instanceId,
|
|
113
|
+
permission: "write"
|
|
114
|
+
})
|
|
115
|
+
});
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const error = await response.json().catch(() => ({ error: "Failed to get token" }));
|
|
118
|
+
throw new Error(error.error || `Failed to get WebSocket token: ${response.status}`);
|
|
119
|
+
}
|
|
120
|
+
const data = await response.json();
|
|
121
|
+
return data.token;
|
|
122
|
+
}
|
|
88
123
|
/**
|
|
89
124
|
* Connect to the cloud service
|
|
90
125
|
*/
|
|
@@ -94,13 +129,19 @@ var init_CloudAdapter = __esm({
|
|
|
94
129
|
}
|
|
95
130
|
this._state = "connecting";
|
|
96
131
|
try {
|
|
97
|
-
if (
|
|
98
|
-
|
|
132
|
+
if (!this.token) {
|
|
133
|
+
if (this.config.tokenProvider) {
|
|
134
|
+
this.token = await this.config.tokenProvider();
|
|
135
|
+
} else if (this.config.apiKey) {
|
|
136
|
+
this.token = await this.fetchTokenWithApiKey();
|
|
137
|
+
}
|
|
99
138
|
}
|
|
100
139
|
let url = `${this.config.baseUrl}/sync/${this.config.instanceId}`;
|
|
101
140
|
if (this.token) {
|
|
102
141
|
url += `?token=${encodeURIComponent(this.token)}`;
|
|
103
142
|
this.token = null;
|
|
143
|
+
} else {
|
|
144
|
+
throw new Error("MindCache Cloud: No authentication method available. Provide apiKey or tokenProvider.");
|
|
104
145
|
}
|
|
105
146
|
this.ws = new WebSocket(url);
|
|
106
147
|
this.setupWebSocket();
|
|
@@ -162,12 +203,6 @@ var init_CloudAdapter = __esm({
|
|
|
162
203
|
return;
|
|
163
204
|
}
|
|
164
205
|
this.ws.onopen = () => {
|
|
165
|
-
if (this.config.apiKey) {
|
|
166
|
-
this.ws.send(JSON.stringify({
|
|
167
|
-
type: "auth",
|
|
168
|
-
apiKey: this.config.apiKey
|
|
169
|
-
}));
|
|
170
|
-
}
|
|
171
206
|
};
|
|
172
207
|
this.ws.onmessage = (event) => {
|
|
173
208
|
try {
|
|
@@ -175,6 +210,7 @@ var init_CloudAdapter = __esm({
|
|
|
175
210
|
this.handleMessage(msg);
|
|
176
211
|
} catch (error) {
|
|
177
212
|
console.error("MindCache Cloud: Failed to parse message:", error);
|
|
213
|
+
console.error("Raw message:", typeof event.data === "string" ? event.data.slice(0, 200) : event.data);
|
|
178
214
|
}
|
|
179
215
|
};
|
|
180
216
|
this.ws.onclose = () => {
|
|
@@ -182,10 +218,12 @@ var init_CloudAdapter = __esm({
|
|
|
182
218
|
this.emit("disconnected");
|
|
183
219
|
this.scheduleReconnect();
|
|
184
220
|
};
|
|
185
|
-
this.ws.onerror = (
|
|
221
|
+
this.ws.onerror = () => {
|
|
186
222
|
this._state = "error";
|
|
187
|
-
|
|
188
|
-
console.error(
|
|
223
|
+
const url = `${this.config.baseUrl}/sync/${this.config.instanceId}`;
|
|
224
|
+
console.error(`MindCache Cloud: WebSocket error connecting to ${url}`);
|
|
225
|
+
console.error("Check that the instance ID and API key are correct, and that the server is reachable.");
|
|
226
|
+
this.emit("error", new Error(`WebSocket connection failed to ${url}`));
|
|
189
227
|
};
|
|
190
228
|
}
|
|
191
229
|
handleMessage(msg) {
|
|
@@ -262,15 +300,6 @@ var init_CloudAdapter = __esm({
|
|
|
262
300
|
this.reconnectTimeout = setTimeout(async () => {
|
|
263
301
|
this.reconnectTimeout = null;
|
|
264
302
|
this.reconnectAttempts++;
|
|
265
|
-
if (this.config.tokenProvider) {
|
|
266
|
-
try {
|
|
267
|
-
this.token = await this.config.tokenProvider();
|
|
268
|
-
} catch (error) {
|
|
269
|
-
console.error("MindCache Cloud: Failed to get token for reconnect:", error);
|
|
270
|
-
this.emit("error", error);
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
303
|
this.connect();
|
|
275
304
|
}, delay);
|
|
276
305
|
}
|
|
@@ -325,6 +354,7 @@ var MindCache = class {
|
|
|
325
354
|
_cloudConfig = null;
|
|
326
355
|
// Access level for system operations
|
|
327
356
|
_accessLevel = "user";
|
|
357
|
+
_initPromise = null;
|
|
328
358
|
constructor(options) {
|
|
329
359
|
if (options?.accessLevel) {
|
|
330
360
|
this._accessLevel = options.accessLevel;
|
|
@@ -333,7 +363,7 @@ var MindCache = class {
|
|
|
333
363
|
this._cloudConfig = options.cloud;
|
|
334
364
|
this._isLoaded = false;
|
|
335
365
|
this._connectionState = "disconnected";
|
|
336
|
-
this._initCloud();
|
|
366
|
+
this._initPromise = this._initCloud();
|
|
337
367
|
}
|
|
338
368
|
}
|
|
339
369
|
/**
|
|
@@ -353,9 +383,11 @@ var MindCache = class {
|
|
|
353
383
|
return;
|
|
354
384
|
}
|
|
355
385
|
try {
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
386
|
+
const CloudAdapter2 = await this._getCloudAdapterClass();
|
|
387
|
+
if (!this._cloudConfig.baseUrl) {
|
|
388
|
+
throw new Error("MindCache Cloud: baseUrl is required. Please provide the cloud API URL in your configuration.");
|
|
389
|
+
}
|
|
390
|
+
const baseUrl = this._cloudConfig.baseUrl.replace("https://", "wss://").replace("http://", "ws://");
|
|
359
391
|
const adapter = new CloudAdapter2({
|
|
360
392
|
instanceId: this._cloudConfig.instanceId,
|
|
361
393
|
projectId: this._cloudConfig.projectId || "default",
|
|
@@ -423,12 +455,46 @@ var MindCache = class {
|
|
|
423
455
|
get isLoaded() {
|
|
424
456
|
return this._isLoaded;
|
|
425
457
|
}
|
|
458
|
+
/**
|
|
459
|
+
* Protected method to load CloudAdapter class.
|
|
460
|
+
* Can be overridden/mocked for testing.
|
|
461
|
+
*/
|
|
462
|
+
async _getCloudAdapterClass() {
|
|
463
|
+
const { CloudAdapter: CloudAdapter2 } = await Promise.resolve().then(() => (init_CloudAdapter(), CloudAdapter_exports));
|
|
464
|
+
return CloudAdapter2;
|
|
465
|
+
}
|
|
426
466
|
/**
|
|
427
467
|
* Check if this instance is connected to cloud
|
|
428
468
|
*/
|
|
429
469
|
get isCloud() {
|
|
430
470
|
return this._cloudConfig !== null;
|
|
431
471
|
}
|
|
472
|
+
/**
|
|
473
|
+
* Wait for initial sync to complete (or resolve immediately if already synced/local).
|
|
474
|
+
* Useful for scripts or linear execution flows.
|
|
475
|
+
*/
|
|
476
|
+
async waitForSync() {
|
|
477
|
+
if (this._isLoaded) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (this._initPromise) {
|
|
481
|
+
await this._initPromise;
|
|
482
|
+
}
|
|
483
|
+
if (this._isLoaded) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
return new Promise((resolve) => {
|
|
487
|
+
if (!this._cloudAdapter) {
|
|
488
|
+
resolve();
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
const handler = () => {
|
|
492
|
+
this._cloudAdapter?.off("synced", handler);
|
|
493
|
+
resolve();
|
|
494
|
+
};
|
|
495
|
+
this._cloudAdapter.on("synced", handler);
|
|
496
|
+
});
|
|
497
|
+
}
|
|
432
498
|
/**
|
|
433
499
|
* Disconnect from cloud (if connected)
|
|
434
500
|
*/
|