@scriptdb/browser-client 1.1.0 → 1.1.2

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 CHANGED
@@ -228,7 +228,7 @@ scriptdb shell
228
228
 
229
229
  ## Changelog
230
230
 
231
- ### 1.1.0 (2025-01-16)
231
+ ### 1.1.2 (2025-01-16)
232
232
 
233
233
  **Added**
234
234
  - Native `scriptdb logs` command to view real-time logs
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Browser-compatible ScriptDB Client
3
+ *
4
+ * This is a lightweight WebSocket client that connects to the ScriptDB WebSocket proxy.
5
+ * The proxy handles all communication with the ScriptDB server using @scriptdb/client.
6
+ */
7
+ type Action = 'script-code' | 'save-db' | 'remove-db' | 'rename-db' | 'login' | 'logout' | 'get-info' | 'list-dbs' | 'create-db' | 'update-db' | 'get-db' | 'shell-command';
8
+ interface Logger {
9
+ debug?: (...args: any[]) => void;
10
+ info?: (...args: any[]) => void;
11
+ warn?: (...args: any[]) => void;
12
+ error?: (...args: any[]) => void;
13
+ }
14
+ interface ClientOptions {
15
+ host?: string;
16
+ port?: number;
17
+ username?: string;
18
+ password?: string;
19
+ logger?: Logger;
20
+ requestTimeout?: number;
21
+ secure?: boolean;
22
+ }
23
+ interface Message {
24
+ id?: number;
25
+ action?: Action;
26
+ message?: string;
27
+ data?: any;
28
+ }
29
+ declare class BrowserClient {
30
+ private logger;
31
+ private host;
32
+ private port;
33
+ private username;
34
+ private password;
35
+ private requestTimeout;
36
+ private secure;
37
+ private ws;
38
+ private _connected;
39
+ private _nextId;
40
+ private _pending;
41
+ constructor(options: ClientOptions);
42
+ /**
43
+ * Check if connected
44
+ */
45
+ get connected(): boolean;
46
+ /**
47
+ * Connect to WebSocket proxy and authenticate
48
+ */
49
+ connect(): Promise<BrowserClient>;
50
+ /**
51
+ * Setup message listeners
52
+ */
53
+ private _setupListeners;
54
+ /**
55
+ * Handle incoming message
56
+ */
57
+ private _handleMessage;
58
+ /**
59
+ * Send request to proxy (internal helper)
60
+ */
61
+ private _sendRequest;
62
+ /**
63
+ * Cleanup on disconnect
64
+ */
65
+ private _cleanup;
66
+ /**
67
+ * Close connection
68
+ */
69
+ close(): void;
70
+ /**
71
+ * Disconnect (alias for close)
72
+ */
73
+ disconnect(): Promise<void>;
74
+ /**
75
+ * Send request helper (for public API methods)
76
+ */
77
+ sendRequest(action: Action, data?: any): Promise<any>;
78
+ /**
79
+ * Execute a command. Supports concurrent requests via request id mapping.
80
+ * Returns a Promise resolved with response.data or rejected on ERROR/timeout.
81
+ */
82
+ execute(message: Message): Promise<any>;
83
+ /**
84
+ * Login with username and password
85
+ */
86
+ login(username: string, password: string): Promise<any>;
87
+ /**
88
+ * Logout from server
89
+ */
90
+ logout(): Promise<any>;
91
+ /**
92
+ * List all databases
93
+ */
94
+ listDatabases(): Promise<any>;
95
+ /**
96
+ * Create a new database
97
+ */
98
+ createDatabase(name: string): Promise<any>;
99
+ /**
100
+ * Remove a database
101
+ */
102
+ removeDatabase(name: string): Promise<any>;
103
+ /**
104
+ * Rename a database
105
+ */
106
+ renameDatabase(oldName: string, newName: string): Promise<any>;
107
+ /**
108
+ * Execute code in a database
109
+ */
110
+ run(code: string | Function, databaseName: string): Promise<any>;
111
+ /**
112
+ * Save a database to disk
113
+ */
114
+ saveDatabase(databaseName: string): Promise<any>;
115
+ /**
116
+ * Update database metadata
117
+ */
118
+ updateDatabase(databaseName: string, data: any): Promise<any>;
119
+ /**
120
+ * Get database content
121
+ */
122
+ getDatabase(name: string): Promise<{
123
+ success: boolean;
124
+ databaseName: string;
125
+ content: string;
126
+ path?: string;
127
+ }>;
128
+ /**
129
+ * Get server information
130
+ */
131
+ getInfo(): Promise<any>;
132
+ /**
133
+ * Execute shell command on server
134
+ */
135
+ executeShell(command: string): Promise<{
136
+ stdout: string;
137
+ stderr: string;
138
+ }>;
139
+ }
140
+
141
+ export { BrowserClient, BrowserClient as default };
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Browser-compatible ScriptDB Client
3
+ *
4
+ * This is a lightweight WebSocket client that connects to the ScriptDB WebSocket proxy.
5
+ * The proxy handles all communication with the ScriptDB server using @scriptdb/client.
6
+ */
7
+ type Action = 'script-code' | 'save-db' | 'remove-db' | 'rename-db' | 'login' | 'logout' | 'get-info' | 'list-dbs' | 'create-db' | 'update-db' | 'get-db' | 'shell-command';
8
+ interface Logger {
9
+ debug?: (...args: any[]) => void;
10
+ info?: (...args: any[]) => void;
11
+ warn?: (...args: any[]) => void;
12
+ error?: (...args: any[]) => void;
13
+ }
14
+ interface ClientOptions {
15
+ host?: string;
16
+ port?: number;
17
+ username?: string;
18
+ password?: string;
19
+ logger?: Logger;
20
+ requestTimeout?: number;
21
+ secure?: boolean;
22
+ }
23
+ interface Message {
24
+ id?: number;
25
+ action?: Action;
26
+ message?: string;
27
+ data?: any;
28
+ }
29
+ declare class BrowserClient {
30
+ private logger;
31
+ private host;
32
+ private port;
33
+ private username;
34
+ private password;
35
+ private requestTimeout;
36
+ private secure;
37
+ private ws;
38
+ private _connected;
39
+ private _nextId;
40
+ private _pending;
41
+ constructor(options: ClientOptions);
42
+ /**
43
+ * Check if connected
44
+ */
45
+ get connected(): boolean;
46
+ /**
47
+ * Connect to WebSocket proxy and authenticate
48
+ */
49
+ connect(): Promise<BrowserClient>;
50
+ /**
51
+ * Setup message listeners
52
+ */
53
+ private _setupListeners;
54
+ /**
55
+ * Handle incoming message
56
+ */
57
+ private _handleMessage;
58
+ /**
59
+ * Send request to proxy (internal helper)
60
+ */
61
+ private _sendRequest;
62
+ /**
63
+ * Cleanup on disconnect
64
+ */
65
+ private _cleanup;
66
+ /**
67
+ * Close connection
68
+ */
69
+ close(): void;
70
+ /**
71
+ * Disconnect (alias for close)
72
+ */
73
+ disconnect(): Promise<void>;
74
+ /**
75
+ * Send request helper (for public API methods)
76
+ */
77
+ sendRequest(action: Action, data?: any): Promise<any>;
78
+ /**
79
+ * Execute a command. Supports concurrent requests via request id mapping.
80
+ * Returns a Promise resolved with response.data or rejected on ERROR/timeout.
81
+ */
82
+ execute(message: Message): Promise<any>;
83
+ /**
84
+ * Login with username and password
85
+ */
86
+ login(username: string, password: string): Promise<any>;
87
+ /**
88
+ * Logout from server
89
+ */
90
+ logout(): Promise<any>;
91
+ /**
92
+ * List all databases
93
+ */
94
+ listDatabases(): Promise<any>;
95
+ /**
96
+ * Create a new database
97
+ */
98
+ createDatabase(name: string): Promise<any>;
99
+ /**
100
+ * Remove a database
101
+ */
102
+ removeDatabase(name: string): Promise<any>;
103
+ /**
104
+ * Rename a database
105
+ */
106
+ renameDatabase(oldName: string, newName: string): Promise<any>;
107
+ /**
108
+ * Execute code in a database
109
+ */
110
+ run(code: string | Function, databaseName: string): Promise<any>;
111
+ /**
112
+ * Save a database to disk
113
+ */
114
+ saveDatabase(databaseName: string): Promise<any>;
115
+ /**
116
+ * Update database metadata
117
+ */
118
+ updateDatabase(databaseName: string, data: any): Promise<any>;
119
+ /**
120
+ * Get database content
121
+ */
122
+ getDatabase(name: string): Promise<{
123
+ success: boolean;
124
+ databaseName: string;
125
+ content: string;
126
+ path?: string;
127
+ }>;
128
+ /**
129
+ * Get server information
130
+ */
131
+ getInfo(): Promise<any>;
132
+ /**
133
+ * Execute shell command on server
134
+ */
135
+ executeShell(command: string): Promise<{
136
+ stdout: string;
137
+ stderr: string;
138
+ }>;
139
+ }
140
+
141
+ export { BrowserClient, BrowserClient as default };
package/dist/index.js CHANGED
@@ -1,35 +1,62 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
1
20
  // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ BrowserClient: () => BrowserClient,
24
+ default: () => index_default
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
2
27
  var noopLogger = {
3
- debug: () => {},
4
- info: () => {},
5
- warn: () => {},
6
- error: () => {}
28
+ debug: () => {
29
+ },
30
+ info: () => {
31
+ },
32
+ warn: () => {
33
+ },
34
+ error: () => {
35
+ }
7
36
  };
8
-
9
- class BrowserClient {
10
- logger;
11
- host;
12
- port;
13
- username;
14
- password;
15
- requestTimeout;
16
- secure;
17
- ws = null;
18
- _connected = false;
19
- _nextId = 1;
20
- _pending = new Map;
37
+ var BrowserClient = class {
21
38
  constructor(options) {
39
+ this.ws = null;
40
+ this._connected = false;
41
+ this._nextId = 1;
42
+ this._pending = /* @__PURE__ */ new Map();
22
43
  this.logger = options.logger || noopLogger;
23
44
  this.host = options.host || "localhost";
24
45
  this.port = options.port || 1234;
25
46
  this.username = options.username || null;
26
47
  this.password = options.password || null;
27
- this.requestTimeout = Number.isFinite(options.requestTimeout) ? options.requestTimeout : 120000;
28
- this.secure = options.secure !== undefined ? options.secure : false;
48
+ this.requestTimeout = Number.isFinite(options.requestTimeout) ? options.requestTimeout : 12e4;
49
+ this.secure = options.secure !== void 0 ? options.secure : false;
29
50
  }
51
+ /**
52
+ * Check if connected
53
+ */
30
54
  get connected() {
31
55
  return this._connected;
32
56
  }
57
+ /**
58
+ * Connect to WebSocket proxy and authenticate
59
+ */
33
60
  async connect() {
34
61
  return new Promise((resolve, reject) => {
35
62
  const wsPort = this.port + 1;
@@ -75,9 +102,11 @@ class BrowserClient {
75
102
  };
76
103
  });
77
104
  }
105
+ /**
106
+ * Setup message listeners
107
+ */
78
108
  _setupListeners() {
79
- if (!this.ws)
80
- return;
109
+ if (!this.ws) return;
81
110
  this.ws.onmessage = (event) => {
82
111
  console.log("WebSocket onmessage fired - browserClient.ts", event.data);
83
112
  try {
@@ -90,6 +119,9 @@ class BrowserClient {
90
119
  }
91
120
  };
92
121
  }
122
+ /**
123
+ * Handle incoming message
124
+ */
93
125
  _handleMessage(msg) {
94
126
  console.log("_handleMessage called with:", msg);
95
127
  if (!msg || typeof msg !== "object") {
@@ -107,8 +139,7 @@ class BrowserClient {
107
139
  return;
108
140
  }
109
141
  const { resolve, reject, timer } = pending;
110
- if (timer)
111
- clearTimeout(timer);
142
+ if (timer) clearTimeout(timer);
112
143
  this._pending.delete(msg.id);
113
144
  console.log("Resolving request with message:", msg.message, "data:", msg.data);
114
145
  if (msg.message === "ERROR" || msg.message === "AUTH FAILED" || msg.message === "AUTH FAIL") {
@@ -123,7 +154,10 @@ class BrowserClient {
123
154
  }
124
155
  console.log("Message has no id, ignoring");
125
156
  }
126
- async sendRequest(action, data = {}) {
157
+ /**
158
+ * Send request to proxy (internal helper)
159
+ */
160
+ async _sendRequest(action, data = {}) {
127
161
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
128
162
  throw new Error("Not connected");
129
163
  }
@@ -143,71 +177,163 @@ class BrowserClient {
143
177
  try {
144
178
  this.ws?.send(JSON.stringify(request));
145
179
  } catch (e) {
146
- if (timer)
147
- clearTimeout(timer);
180
+ if (timer) clearTimeout(timer);
148
181
  this._pending.delete(id);
149
182
  reject(e);
150
183
  }
151
184
  });
152
185
  }
186
+ /**
187
+ * Cleanup on disconnect
188
+ */
153
189
  _cleanup() {
154
190
  this._pending.forEach((pending) => {
155
- if (pending.timer)
156
- clearTimeout(pending.timer);
191
+ if (pending.timer) clearTimeout(pending.timer);
157
192
  try {
158
193
  pending.reject(new Error("Disconnected"));
159
- } catch (e) {}
194
+ } catch (e) {
195
+ }
160
196
  });
161
197
  this._pending.clear();
162
198
  }
199
+ /**
200
+ * Close connection
201
+ */
163
202
  close() {
164
203
  if (this.ws) {
165
204
  try {
166
205
  this.ws.close();
167
- } catch (e) {}
206
+ } catch (e) {
207
+ }
168
208
  this.ws = null;
169
209
  }
170
210
  this._cleanup();
171
211
  }
212
+ /**
213
+ * Disconnect (alias for close)
214
+ */
172
215
  async disconnect() {
173
216
  this.close();
174
217
  }
218
+ /**
219
+ * Send request helper (for public API methods)
220
+ */
221
+ async sendRequest(action, data = {}) {
222
+ return this.execute({ action, data });
223
+ }
224
+ /**
225
+ * Execute a command. Supports concurrent requests via request id mapping.
226
+ * Returns a Promise resolved with response.data or rejected on ERROR/timeout.
227
+ */
228
+ async execute(message) {
229
+ if (!message.action) {
230
+ throw new Error("Action is required");
231
+ }
232
+ return this._sendRequest(message.action, message.data);
233
+ }
234
+ // ========== Public API Methods ==========
235
+ /**
236
+ * Login with username and password
237
+ */
175
238
  async login(username, password) {
176
239
  return this.sendRequest("login", { username, password });
177
240
  }
241
+ /**
242
+ * Logout from server
243
+ */
178
244
  async logout() {
179
245
  return this.sendRequest("logout", {});
180
246
  }
247
+ /**
248
+ * List all databases
249
+ */
181
250
  async listDatabases() {
182
251
  return this.sendRequest("list-dbs", {});
183
252
  }
253
+ /**
254
+ * Create a new database
255
+ */
184
256
  async createDatabase(name) {
185
257
  return this.sendRequest("create-db", { databaseName: name });
186
258
  }
259
+ /**
260
+ * Remove a database
261
+ */
187
262
  async removeDatabase(name) {
188
263
  return this.sendRequest("remove-db", { databaseName: name });
189
264
  }
265
+ /**
266
+ * Rename a database
267
+ */
190
268
  async renameDatabase(oldName, newName) {
191
269
  return this.sendRequest("rename-db", { databaseName: oldName, newName });
192
270
  }
271
+ /**
272
+ * Execute code in a database
273
+ */
193
274
  async run(code, databaseName) {
194
- return this.sendRequest("script-code", { code, databaseName });
275
+ let stringCode;
276
+ if (typeof code === "function") {
277
+ const funcStr = code.toString();
278
+ const arrowMatch = funcStr.match(/^[\s]*\(?\s*\)?\s*=>\s*{?/);
279
+ const functionMatch = funcStr.match(/^[\s]*function\s*\(?[\w\s]*\)?\s*{/);
280
+ const match = arrowMatch || functionMatch;
281
+ const start = match ? match[0].length : 0;
282
+ const end = funcStr.lastIndexOf("}");
283
+ stringCode = funcStr.substring(start, end);
284
+ stringCode = stringCode.replace(/^[\s\r\n]+/, "").replace(/[\s\r\n]+$/, "");
285
+ stringCode = stringCode.replace(
286
+ /import\s*\(\s*([^)]+?)\s*\)\s*\.from\s*\(\s*(['"])([^'"]+)\2\s*\)/g,
287
+ (_, importArg, quote, modulePath) => {
288
+ const trimmed = importArg.trim();
289
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
290
+ const inner = trimmed.slice(1, -1).trim();
291
+ return `import { ${inner} } from ${quote}${modulePath}${quote}`;
292
+ } else {
293
+ return `import ${trimmed} from ${quote}${modulePath}${quote}`;
294
+ }
295
+ }
296
+ );
297
+ stringCode = stringCode.split("\n").map((line) => line.trim()).join("\n").trim();
298
+ } else {
299
+ stringCode = code;
300
+ }
301
+ return this.sendRequest("script-code", { code: stringCode, databaseName });
195
302
  }
303
+ /**
304
+ * Save a database to disk
305
+ */
196
306
  async saveDatabase(databaseName) {
197
307
  return this.sendRequest("save-db", { databaseName });
198
308
  }
309
+ /**
310
+ * Update database metadata
311
+ */
199
312
  async updateDatabase(databaseName, data) {
200
313
  return this.sendRequest("update-db", { databaseName, ...data });
201
314
  }
315
+ /**
316
+ * Get database content
317
+ */
318
+ async getDatabase(name) {
319
+ return this.sendRequest("get-db", { databaseName: name });
320
+ }
321
+ /**
322
+ * Get server information
323
+ */
202
324
  async getInfo() {
203
325
  return this.sendRequest("get-info", {});
204
326
  }
327
+ /**
328
+ * Execute shell command on server
329
+ */
205
330
  async executeShell(command) {
206
331
  return this.sendRequest("shell-command", { command });
207
332
  }
208
- }
209
- var src_default = BrowserClient;
210
- export {
211
- src_default as default,
212
- BrowserClient
213
333
  };
334
+ var index_default = BrowserClient;
335
+ // Annotate the CommonJS export names for ESM import in node:
336
+ 0 && (module.exports = {
337
+ BrowserClient
338
+ });
339
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Browser-compatible ScriptDB Client\n * \n * This is a lightweight WebSocket client that connects to the ScriptDB WebSocket proxy.\n * The proxy handles all communication with the ScriptDB server using @scriptdb/client.\n */\n\ntype Action = 'script-code' | 'save-db' | 'remove-db' | 'rename-db' | 'login' | 'logout' | 'get-info' | 'list-dbs' | 'create-db' | 'update-db' | 'get-db' | 'shell-command';\n\ninterface Logger {\n debug?: (...args: any[]) => void;\n info?: (...args: any[]) => void;\n warn?: (...args: any[]) => void;\n error?: (...args: any[]) => void;\n}\n\ninterface ClientOptions {\n host?: string;\n port?: number;\n username?: string;\n password?: string;\n logger?: Logger;\n requestTimeout?: number;\n secure?: boolean;\n}\n\ninterface PendingRequest {\n resolve: (value: any) => void;\n reject: (error: Error) => void;\n timer: number | null;\n}\n\ninterface Message {\n id?: number;\n action?: Action;\n message?: string;\n data?: any;\n}\n\nconst noopLogger: Logger = {\n debug: () => { },\n info: () => { },\n warn: () => { },\n error: () => { },\n};\n\nexport class BrowserClient {\n private logger: Logger;\n private host: string;\n private port: number;\n private username: string | null;\n private password: string | null;\n private requestTimeout: number;\n private secure: boolean;\n\n private ws: WebSocket | null = null;\n private _connected: boolean = false;\n private _nextId: number = 1;\n private _pending: Map<number, PendingRequest> = new Map();\n\n constructor(options: ClientOptions) {\n this.logger = options.logger || noopLogger;\n this.host = options.host || 'localhost';\n this.port = options.port || 1234;\n this.username = options.username || null;\n this.password = options.password || null;\n this.requestTimeout = Number.isFinite(options.requestTimeout) ? options.requestTimeout! : 120000; // 2 minutes default\n this.secure = options.secure !== undefined ? options.secure : false;\n }\n\n /**\n * Check if connected\n */\n get connected(): boolean {\n return this._connected;\n }\n\n /**\n * Connect to WebSocket proxy and authenticate\n */\n async connect(): Promise<BrowserClient> {\n return new Promise((resolve, reject) => {\n const wsPort = this.port + 1;\n const wsUrl = `ws://${this.host}:${wsPort}`;\n this.logger.info?.('Connecting to', wsUrl);\n\n try {\n this.ws = new WebSocket(wsUrl);\n } catch (e) {\n const error = e as Error;\n this.logger.error?.(\"Connection failed\", error.message);\n return reject(error);\n }\n\n this.ws.onopen = async () => {\n console.log('WebSocket onopen - browserClient.ts');\n this.logger.info?.('WebSocket connected');\n this._connected = true;\n this._setupListeners();\n\n // Always send login request (even with empty credentials for anonymous access)\n try {\n console.log('Sending login request with credentials:', { username: this.username || '', hasPassword: !!this.password, secure: this.secure });\n await this.sendRequest('login', {\n username: this.username || '',\n password: this.password || '',\n secure: this.secure\n });\n console.log('Authenticated successfully');\n this.logger.info?.('Authenticated successfully');\n resolve(this);\n } catch (err) {\n console.error('Login failed:', err);\n reject(err);\n }\n };\n\n this.ws.onerror = (error) => {\n console.error('WebSocket onerror:', error);\n this.logger.error?.('WebSocket error:', error);\n reject(new Error('WebSocket connection failed'));\n };\n\n this.ws.onclose = () => {\n console.log('WebSocket onclose');\n this.logger.info?.('WebSocket disconnected');\n this._connected = false;\n this._cleanup();\n };\n });\n }\n\n /**\n * Setup message listeners\n */\n private _setupListeners() {\n if (!this.ws) return;\n\n this.ws.onmessage = (event) => {\n console.log('WebSocket onmessage fired - browserClient.ts', event.data);\n try {\n const msg = JSON.parse(event.data) as Message;\n console.log('Parsed message:', msg);\n this._handleMessage(msg);\n } catch (error) {\n console.error('Failed to parse message:', error, event.data);\n this.logger.error?.('Failed to parse message:', error);\n }\n };\n }\n\n /**\n * Handle incoming message\n */\n private _handleMessage(msg: Message) {\n console.log('_handleMessage called with:', msg);\n if (!msg || typeof msg !== \"object\") {\n console.log('Invalid message - not an object');\n return;\n }\n\n this.logger.debug?.('Received message:', msg);\n\n // Handle response with id\n if (typeof msg.id !== \"undefined\") {\n console.log('Message has id:', msg.id);\n const pending = this._pending.get(msg.id);\n console.log('Pending request found:', !!pending, 'total pending:', this._pending.size);\n if (!pending) {\n this.logger.debug?.(\"No pending request for id\", msg.id);\n console.log(\"No pending request for id\", msg.id);\n return;\n }\n\n const { resolve, reject, timer } = pending;\n if (timer) clearTimeout(timer);\n this._pending.delete(msg.id);\n\n console.log('Resolving request with message:', msg.message, 'data:', msg.data);\n\n // Check for errors\n if (msg.message === \"ERROR\" || msg.message === \"AUTH FAILED\" || msg.message === \"AUTH FAIL\") {\n return reject(new Error(typeof msg.data === 'string' ? msg.data : \"Request failed\"));\n }\n\n // Success - AUTH OK, OK, or SUCCESS\n if (msg.message === \"AUTH OK\" || msg.message === \"OK\" || msg.message === \"SUCCESS\") {\n console.log('Calling resolve with data:', msg.data);\n return resolve(msg.data);\n }\n\n // Default to resolve with data\n console.log('Default resolve with data:', msg.data);\n return resolve(msg.data);\n }\n console.log('Message has no id, ignoring');\n }\n\n /**\n * Send request to proxy (internal helper)\n */\n private async _sendRequest(action: Action, data: any = {}): Promise<any> {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error('Not connected');\n }\n\n const id = this._nextId++;\n const request = { id, action, data };\n\n return new Promise((resolve, reject) => {\n let timer: number | null = null;\n if (this.requestTimeout > 0) {\n timer = window.setTimeout(() => {\n if (this._pending.has(id)) {\n this._pending.delete(id);\n reject(new Error(\"Request timeout\"));\n }\n }, this.requestTimeout);\n }\n\n this._pending.set(id, { resolve, reject, timer });\n\n try {\n this.ws?.send(JSON.stringify(request));\n } catch (e) {\n if (timer) clearTimeout(timer);\n this._pending.delete(id);\n reject(e);\n }\n });\n }\n\n /**\n * Cleanup on disconnect\n */\n private _cleanup() {\n this._pending.forEach((pending) => {\n if (pending.timer) clearTimeout(pending.timer);\n try {\n pending.reject(new Error(\"Disconnected\"));\n } catch (e) { }\n });\n this._pending.clear();\n }\n\n /**\n * Close connection\n */\n close() {\n if (this.ws) {\n try {\n this.ws.close();\n } catch (e) { }\n this.ws = null;\n }\n this._cleanup();\n }\n\n /**\n * Disconnect (alias for close)\n */\n async disconnect(): Promise<void> {\n this.close();\n }\n\n /**\n * Send request helper (for public API methods)\n */\n async sendRequest(action: Action, data: any = {}): Promise<any> {\n return this.execute({ action, data });\n }\n\n /**\n * Execute a command. Supports concurrent requests via request id mapping.\n * Returns a Promise resolved with response.data or rejected on ERROR/timeout.\n */\n async execute(message: Message): Promise<any> {\n if (!message.action) {\n throw new Error('Action is required');\n }\n return this._sendRequest(message.action, message.data);\n }\n\n // ========== Public API Methods ==========\n\n /**\n * Login with username and password\n */\n async login(username: string, password: string): Promise<any> {\n return this.sendRequest('login', { username, password });\n }\n\n /**\n * Logout from server\n */\n async logout(): Promise<any> {\n return this.sendRequest('logout', {});\n }\n\n /**\n * List all databases\n */\n async listDatabases(): Promise<any> {\n return this.sendRequest('list-dbs', {});\n }\n\n /**\n * Create a new database\n */\n async createDatabase(name: string): Promise<any> {\n return this.sendRequest('create-db', { databaseName: name });\n }\n\n /**\n * Remove a database\n */\n async removeDatabase(name: string): Promise<any> {\n return this.sendRequest('remove-db', { databaseName: name });\n }\n\n /**\n * Rename a database\n */\n async renameDatabase(oldName: string, newName: string): Promise<any> {\n return this.sendRequest('rename-db', { databaseName: oldName, newName });\n }\n\n /**\n * Execute code in a database\n */\n async run(code: string | Function, databaseName: string): Promise<any> {\n let stringCode: string;\n if (typeof code === 'function') {\n const funcStr = code.toString();\n // ตัด arrow function หรือ function keyword และ opening brace ออก\n const arrowMatch = funcStr.match(/^[\\s]*\\(?\\s*\\)?\\s*=>\\s*{?/);\n const functionMatch = funcStr.match(/^[\\s]*function\\s*\\(?[\\w\\s]*\\)?\\s*{/);\n const match = arrowMatch || functionMatch;\n const start = match ? match[0].length : 0;\n const end = funcStr.lastIndexOf('}');\n stringCode = funcStr.substring(start, end);\n // Trim leading newline, spaces, and trailing\n stringCode = stringCode.replace(/^[\\s\\r\\n]+/, '').replace(/[\\s\\r\\n]+$/, '');\n\n // Transform import(aa).from(\"module\") to import aa from \"module\"\n stringCode = stringCode.replace(\n /import\\s*\\(\\s*([^)]+?)\\s*\\)\\s*\\.from\\s*\\(\\s*(['\"])([^'\"]+)\\2\\s*\\)/g,\n (_, importArg, quote, modulePath) => {\n // Check if importArg is wrapped in braces (destructuring)\n const trimmed = importArg.trim();\n if (trimmed.startsWith('{') && trimmed.endsWith('}')) {\n // Destructuring: import({bb}) -> import { bb }\n const inner = trimmed.slice(1, -1).trim();\n return `import { ${inner} } from ${quote}${modulePath}${quote}`;\n } else {\n // Default: import(aa) -> import aa\n return `import ${trimmed} from ${quote}${modulePath}${quote}`;\n }\n }\n );\n\n // Trim leading whitespace from each line\n stringCode = stringCode.split('\\n').map(line => line.trim()).join('\\n').trim();\n } else {\n stringCode = code;\n }\n\n return this.sendRequest('script-code', { code: stringCode, databaseName });\n }\n\n /**\n * Save a database to disk\n */\n async saveDatabase(databaseName: string): Promise<any> {\n return this.sendRequest('save-db', { databaseName });\n }\n\n /**\n * Update database metadata\n */\n async updateDatabase(databaseName: string, data: any): Promise<any> {\n return this.sendRequest('update-db', { databaseName, ...data });\n }\n\n /**\n * Get database content\n */\n async getDatabase(name: string): Promise<{ success: boolean; databaseName: string; content: string; path?: string }> {\n return this.sendRequest('get-db', { databaseName: name });\n }\n\n /**\n * Get server information\n */\n async getInfo(): Promise<any> {\n return this.sendRequest('get-info', {});\n }\n\n /**\n * Execute shell command on server\n */\n async executeShell(command: string): Promise<{ stdout: string; stderr: string }> {\n return this.sendRequest('shell-command', { command });\n }\n}\n\nexport default BrowserClient;\n\n"],"mappings":"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","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,314 @@
1
+ // src/index.ts
2
+ var noopLogger = {
3
+ debug: () => {
4
+ },
5
+ info: () => {
6
+ },
7
+ warn: () => {
8
+ },
9
+ error: () => {
10
+ }
11
+ };
12
+ var BrowserClient = class {
13
+ constructor(options) {
14
+ this.ws = null;
15
+ this._connected = false;
16
+ this._nextId = 1;
17
+ this._pending = /* @__PURE__ */ new Map();
18
+ this.logger = options.logger || noopLogger;
19
+ this.host = options.host || "localhost";
20
+ this.port = options.port || 1234;
21
+ this.username = options.username || null;
22
+ this.password = options.password || null;
23
+ this.requestTimeout = Number.isFinite(options.requestTimeout) ? options.requestTimeout : 12e4;
24
+ this.secure = options.secure !== void 0 ? options.secure : false;
25
+ }
26
+ /**
27
+ * Check if connected
28
+ */
29
+ get connected() {
30
+ return this._connected;
31
+ }
32
+ /**
33
+ * Connect to WebSocket proxy and authenticate
34
+ */
35
+ async connect() {
36
+ return new Promise((resolve, reject) => {
37
+ const wsPort = this.port + 1;
38
+ const wsUrl = `ws://${this.host}:${wsPort}`;
39
+ this.logger.info?.("Connecting to", wsUrl);
40
+ try {
41
+ this.ws = new WebSocket(wsUrl);
42
+ } catch (e) {
43
+ const error = e;
44
+ this.logger.error?.("Connection failed", error.message);
45
+ return reject(error);
46
+ }
47
+ this.ws.onopen = async () => {
48
+ console.log("WebSocket onopen - browserClient.ts");
49
+ this.logger.info?.("WebSocket connected");
50
+ this._connected = true;
51
+ this._setupListeners();
52
+ try {
53
+ console.log("Sending login request with credentials:", { username: this.username || "", hasPassword: !!this.password, secure: this.secure });
54
+ await this.sendRequest("login", {
55
+ username: this.username || "",
56
+ password: this.password || "",
57
+ secure: this.secure
58
+ });
59
+ console.log("Authenticated successfully");
60
+ this.logger.info?.("Authenticated successfully");
61
+ resolve(this);
62
+ } catch (err) {
63
+ console.error("Login failed:", err);
64
+ reject(err);
65
+ }
66
+ };
67
+ this.ws.onerror = (error) => {
68
+ console.error("WebSocket onerror:", error);
69
+ this.logger.error?.("WebSocket error:", error);
70
+ reject(new Error("WebSocket connection failed"));
71
+ };
72
+ this.ws.onclose = () => {
73
+ console.log("WebSocket onclose");
74
+ this.logger.info?.("WebSocket disconnected");
75
+ this._connected = false;
76
+ this._cleanup();
77
+ };
78
+ });
79
+ }
80
+ /**
81
+ * Setup message listeners
82
+ */
83
+ _setupListeners() {
84
+ if (!this.ws) return;
85
+ this.ws.onmessage = (event) => {
86
+ console.log("WebSocket onmessage fired - browserClient.ts", event.data);
87
+ try {
88
+ const msg = JSON.parse(event.data);
89
+ console.log("Parsed message:", msg);
90
+ this._handleMessage(msg);
91
+ } catch (error) {
92
+ console.error("Failed to parse message:", error, event.data);
93
+ this.logger.error?.("Failed to parse message:", error);
94
+ }
95
+ };
96
+ }
97
+ /**
98
+ * Handle incoming message
99
+ */
100
+ _handleMessage(msg) {
101
+ console.log("_handleMessage called with:", msg);
102
+ if (!msg || typeof msg !== "object") {
103
+ console.log("Invalid message - not an object");
104
+ return;
105
+ }
106
+ this.logger.debug?.("Received message:", msg);
107
+ if (typeof msg.id !== "undefined") {
108
+ console.log("Message has id:", msg.id);
109
+ const pending = this._pending.get(msg.id);
110
+ console.log("Pending request found:", !!pending, "total pending:", this._pending.size);
111
+ if (!pending) {
112
+ this.logger.debug?.("No pending request for id", msg.id);
113
+ console.log("No pending request for id", msg.id);
114
+ return;
115
+ }
116
+ const { resolve, reject, timer } = pending;
117
+ if (timer) clearTimeout(timer);
118
+ this._pending.delete(msg.id);
119
+ console.log("Resolving request with message:", msg.message, "data:", msg.data);
120
+ if (msg.message === "ERROR" || msg.message === "AUTH FAILED" || msg.message === "AUTH FAIL") {
121
+ return reject(new Error(typeof msg.data === "string" ? msg.data : "Request failed"));
122
+ }
123
+ if (msg.message === "AUTH OK" || msg.message === "OK" || msg.message === "SUCCESS") {
124
+ console.log("Calling resolve with data:", msg.data);
125
+ return resolve(msg.data);
126
+ }
127
+ console.log("Default resolve with data:", msg.data);
128
+ return resolve(msg.data);
129
+ }
130
+ console.log("Message has no id, ignoring");
131
+ }
132
+ /**
133
+ * Send request to proxy (internal helper)
134
+ */
135
+ async _sendRequest(action, data = {}) {
136
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
137
+ throw new Error("Not connected");
138
+ }
139
+ const id = this._nextId++;
140
+ const request = { id, action, data };
141
+ return new Promise((resolve, reject) => {
142
+ let timer = null;
143
+ if (this.requestTimeout > 0) {
144
+ timer = window.setTimeout(() => {
145
+ if (this._pending.has(id)) {
146
+ this._pending.delete(id);
147
+ reject(new Error("Request timeout"));
148
+ }
149
+ }, this.requestTimeout);
150
+ }
151
+ this._pending.set(id, { resolve, reject, timer });
152
+ try {
153
+ this.ws?.send(JSON.stringify(request));
154
+ } catch (e) {
155
+ if (timer) clearTimeout(timer);
156
+ this._pending.delete(id);
157
+ reject(e);
158
+ }
159
+ });
160
+ }
161
+ /**
162
+ * Cleanup on disconnect
163
+ */
164
+ _cleanup() {
165
+ this._pending.forEach((pending) => {
166
+ if (pending.timer) clearTimeout(pending.timer);
167
+ try {
168
+ pending.reject(new Error("Disconnected"));
169
+ } catch (e) {
170
+ }
171
+ });
172
+ this._pending.clear();
173
+ }
174
+ /**
175
+ * Close connection
176
+ */
177
+ close() {
178
+ if (this.ws) {
179
+ try {
180
+ this.ws.close();
181
+ } catch (e) {
182
+ }
183
+ this.ws = null;
184
+ }
185
+ this._cleanup();
186
+ }
187
+ /**
188
+ * Disconnect (alias for close)
189
+ */
190
+ async disconnect() {
191
+ this.close();
192
+ }
193
+ /**
194
+ * Send request helper (for public API methods)
195
+ */
196
+ async sendRequest(action, data = {}) {
197
+ return this.execute({ action, data });
198
+ }
199
+ /**
200
+ * Execute a command. Supports concurrent requests via request id mapping.
201
+ * Returns a Promise resolved with response.data or rejected on ERROR/timeout.
202
+ */
203
+ async execute(message) {
204
+ if (!message.action) {
205
+ throw new Error("Action is required");
206
+ }
207
+ return this._sendRequest(message.action, message.data);
208
+ }
209
+ // ========== Public API Methods ==========
210
+ /**
211
+ * Login with username and password
212
+ */
213
+ async login(username, password) {
214
+ return this.sendRequest("login", { username, password });
215
+ }
216
+ /**
217
+ * Logout from server
218
+ */
219
+ async logout() {
220
+ return this.sendRequest("logout", {});
221
+ }
222
+ /**
223
+ * List all databases
224
+ */
225
+ async listDatabases() {
226
+ return this.sendRequest("list-dbs", {});
227
+ }
228
+ /**
229
+ * Create a new database
230
+ */
231
+ async createDatabase(name) {
232
+ return this.sendRequest("create-db", { databaseName: name });
233
+ }
234
+ /**
235
+ * Remove a database
236
+ */
237
+ async removeDatabase(name) {
238
+ return this.sendRequest("remove-db", { databaseName: name });
239
+ }
240
+ /**
241
+ * Rename a database
242
+ */
243
+ async renameDatabase(oldName, newName) {
244
+ return this.sendRequest("rename-db", { databaseName: oldName, newName });
245
+ }
246
+ /**
247
+ * Execute code in a database
248
+ */
249
+ async run(code, databaseName) {
250
+ let stringCode;
251
+ if (typeof code === "function") {
252
+ const funcStr = code.toString();
253
+ const arrowMatch = funcStr.match(/^[\s]*\(?\s*\)?\s*=>\s*{?/);
254
+ const functionMatch = funcStr.match(/^[\s]*function\s*\(?[\w\s]*\)?\s*{/);
255
+ const match = arrowMatch || functionMatch;
256
+ const start = match ? match[0].length : 0;
257
+ const end = funcStr.lastIndexOf("}");
258
+ stringCode = funcStr.substring(start, end);
259
+ stringCode = stringCode.replace(/^[\s\r\n]+/, "").replace(/[\s\r\n]+$/, "");
260
+ stringCode = stringCode.replace(
261
+ /import\s*\(\s*([^)]+?)\s*\)\s*\.from\s*\(\s*(['"])([^'"]+)\2\s*\)/g,
262
+ (_, importArg, quote, modulePath) => {
263
+ const trimmed = importArg.trim();
264
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
265
+ const inner = trimmed.slice(1, -1).trim();
266
+ return `import { ${inner} } from ${quote}${modulePath}${quote}`;
267
+ } else {
268
+ return `import ${trimmed} from ${quote}${modulePath}${quote}`;
269
+ }
270
+ }
271
+ );
272
+ stringCode = stringCode.split("\n").map((line) => line.trim()).join("\n").trim();
273
+ } else {
274
+ stringCode = code;
275
+ }
276
+ return this.sendRequest("script-code", { code: stringCode, databaseName });
277
+ }
278
+ /**
279
+ * Save a database to disk
280
+ */
281
+ async saveDatabase(databaseName) {
282
+ return this.sendRequest("save-db", { databaseName });
283
+ }
284
+ /**
285
+ * Update database metadata
286
+ */
287
+ async updateDatabase(databaseName, data) {
288
+ return this.sendRequest("update-db", { databaseName, ...data });
289
+ }
290
+ /**
291
+ * Get database content
292
+ */
293
+ async getDatabase(name) {
294
+ return this.sendRequest("get-db", { databaseName: name });
295
+ }
296
+ /**
297
+ * Get server information
298
+ */
299
+ async getInfo() {
300
+ return this.sendRequest("get-info", {});
301
+ }
302
+ /**
303
+ * Execute shell command on server
304
+ */
305
+ async executeShell(command) {
306
+ return this.sendRequest("shell-command", { command });
307
+ }
308
+ };
309
+ var index_default = BrowserClient;
310
+ export {
311
+ BrowserClient,
312
+ index_default as default
313
+ };
314
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Browser-compatible ScriptDB Client\n * \n * This is a lightweight WebSocket client that connects to the ScriptDB WebSocket proxy.\n * The proxy handles all communication with the ScriptDB server using @scriptdb/client.\n */\n\ntype Action = 'script-code' | 'save-db' | 'remove-db' | 'rename-db' | 'login' | 'logout' | 'get-info' | 'list-dbs' | 'create-db' | 'update-db' | 'get-db' | 'shell-command';\n\ninterface Logger {\n debug?: (...args: any[]) => void;\n info?: (...args: any[]) => void;\n warn?: (...args: any[]) => void;\n error?: (...args: any[]) => void;\n}\n\ninterface ClientOptions {\n host?: string;\n port?: number;\n username?: string;\n password?: string;\n logger?: Logger;\n requestTimeout?: number;\n secure?: boolean;\n}\n\ninterface PendingRequest {\n resolve: (value: any) => void;\n reject: (error: Error) => void;\n timer: number | null;\n}\n\ninterface Message {\n id?: number;\n action?: Action;\n message?: string;\n data?: any;\n}\n\nconst noopLogger: Logger = {\n debug: () => { },\n info: () => { },\n warn: () => { },\n error: () => { },\n};\n\nexport class BrowserClient {\n private logger: Logger;\n private host: string;\n private port: number;\n private username: string | null;\n private password: string | null;\n private requestTimeout: number;\n private secure: boolean;\n\n private ws: WebSocket | null = null;\n private _connected: boolean = false;\n private _nextId: number = 1;\n private _pending: Map<number, PendingRequest> = new Map();\n\n constructor(options: ClientOptions) {\n this.logger = options.logger || noopLogger;\n this.host = options.host || 'localhost';\n this.port = options.port || 1234;\n this.username = options.username || null;\n this.password = options.password || null;\n this.requestTimeout = Number.isFinite(options.requestTimeout) ? options.requestTimeout! : 120000; // 2 minutes default\n this.secure = options.secure !== undefined ? options.secure : false;\n }\n\n /**\n * Check if connected\n */\n get connected(): boolean {\n return this._connected;\n }\n\n /**\n * Connect to WebSocket proxy and authenticate\n */\n async connect(): Promise<BrowserClient> {\n return new Promise((resolve, reject) => {\n const wsPort = this.port + 1;\n const wsUrl = `ws://${this.host}:${wsPort}`;\n this.logger.info?.('Connecting to', wsUrl);\n\n try {\n this.ws = new WebSocket(wsUrl);\n } catch (e) {\n const error = e as Error;\n this.logger.error?.(\"Connection failed\", error.message);\n return reject(error);\n }\n\n this.ws.onopen = async () => {\n console.log('WebSocket onopen - browserClient.ts');\n this.logger.info?.('WebSocket connected');\n this._connected = true;\n this._setupListeners();\n\n // Always send login request (even with empty credentials for anonymous access)\n try {\n console.log('Sending login request with credentials:', { username: this.username || '', hasPassword: !!this.password, secure: this.secure });\n await this.sendRequest('login', {\n username: this.username || '',\n password: this.password || '',\n secure: this.secure\n });\n console.log('Authenticated successfully');\n this.logger.info?.('Authenticated successfully');\n resolve(this);\n } catch (err) {\n console.error('Login failed:', err);\n reject(err);\n }\n };\n\n this.ws.onerror = (error) => {\n console.error('WebSocket onerror:', error);\n this.logger.error?.('WebSocket error:', error);\n reject(new Error('WebSocket connection failed'));\n };\n\n this.ws.onclose = () => {\n console.log('WebSocket onclose');\n this.logger.info?.('WebSocket disconnected');\n this._connected = false;\n this._cleanup();\n };\n });\n }\n\n /**\n * Setup message listeners\n */\n private _setupListeners() {\n if (!this.ws) return;\n\n this.ws.onmessage = (event) => {\n console.log('WebSocket onmessage fired - browserClient.ts', event.data);\n try {\n const msg = JSON.parse(event.data) as Message;\n console.log('Parsed message:', msg);\n this._handleMessage(msg);\n } catch (error) {\n console.error('Failed to parse message:', error, event.data);\n this.logger.error?.('Failed to parse message:', error);\n }\n };\n }\n\n /**\n * Handle incoming message\n */\n private _handleMessage(msg: Message) {\n console.log('_handleMessage called with:', msg);\n if (!msg || typeof msg !== \"object\") {\n console.log('Invalid message - not an object');\n return;\n }\n\n this.logger.debug?.('Received message:', msg);\n\n // Handle response with id\n if (typeof msg.id !== \"undefined\") {\n console.log('Message has id:', msg.id);\n const pending = this._pending.get(msg.id);\n console.log('Pending request found:', !!pending, 'total pending:', this._pending.size);\n if (!pending) {\n this.logger.debug?.(\"No pending request for id\", msg.id);\n console.log(\"No pending request for id\", msg.id);\n return;\n }\n\n const { resolve, reject, timer } = pending;\n if (timer) clearTimeout(timer);\n this._pending.delete(msg.id);\n\n console.log('Resolving request with message:', msg.message, 'data:', msg.data);\n\n // Check for errors\n if (msg.message === \"ERROR\" || msg.message === \"AUTH FAILED\" || msg.message === \"AUTH FAIL\") {\n return reject(new Error(typeof msg.data === 'string' ? msg.data : \"Request failed\"));\n }\n\n // Success - AUTH OK, OK, or SUCCESS\n if (msg.message === \"AUTH OK\" || msg.message === \"OK\" || msg.message === \"SUCCESS\") {\n console.log('Calling resolve with data:', msg.data);\n return resolve(msg.data);\n }\n\n // Default to resolve with data\n console.log('Default resolve with data:', msg.data);\n return resolve(msg.data);\n }\n console.log('Message has no id, ignoring');\n }\n\n /**\n * Send request to proxy (internal helper)\n */\n private async _sendRequest(action: Action, data: any = {}): Promise<any> {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error('Not connected');\n }\n\n const id = this._nextId++;\n const request = { id, action, data };\n\n return new Promise((resolve, reject) => {\n let timer: number | null = null;\n if (this.requestTimeout > 0) {\n timer = window.setTimeout(() => {\n if (this._pending.has(id)) {\n this._pending.delete(id);\n reject(new Error(\"Request timeout\"));\n }\n }, this.requestTimeout);\n }\n\n this._pending.set(id, { resolve, reject, timer });\n\n try {\n this.ws?.send(JSON.stringify(request));\n } catch (e) {\n if (timer) clearTimeout(timer);\n this._pending.delete(id);\n reject(e);\n }\n });\n }\n\n /**\n * Cleanup on disconnect\n */\n private _cleanup() {\n this._pending.forEach((pending) => {\n if (pending.timer) clearTimeout(pending.timer);\n try {\n pending.reject(new Error(\"Disconnected\"));\n } catch (e) { }\n });\n this._pending.clear();\n }\n\n /**\n * Close connection\n */\n close() {\n if (this.ws) {\n try {\n this.ws.close();\n } catch (e) { }\n this.ws = null;\n }\n this._cleanup();\n }\n\n /**\n * Disconnect (alias for close)\n */\n async disconnect(): Promise<void> {\n this.close();\n }\n\n /**\n * Send request helper (for public API methods)\n */\n async sendRequest(action: Action, data: any = {}): Promise<any> {\n return this.execute({ action, data });\n }\n\n /**\n * Execute a command. Supports concurrent requests via request id mapping.\n * Returns a Promise resolved with response.data or rejected on ERROR/timeout.\n */\n async execute(message: Message): Promise<any> {\n if (!message.action) {\n throw new Error('Action is required');\n }\n return this._sendRequest(message.action, message.data);\n }\n\n // ========== Public API Methods ==========\n\n /**\n * Login with username and password\n */\n async login(username: string, password: string): Promise<any> {\n return this.sendRequest('login', { username, password });\n }\n\n /**\n * Logout from server\n */\n async logout(): Promise<any> {\n return this.sendRequest('logout', {});\n }\n\n /**\n * List all databases\n */\n async listDatabases(): Promise<any> {\n return this.sendRequest('list-dbs', {});\n }\n\n /**\n * Create a new database\n */\n async createDatabase(name: string): Promise<any> {\n return this.sendRequest('create-db', { databaseName: name });\n }\n\n /**\n * Remove a database\n */\n async removeDatabase(name: string): Promise<any> {\n return this.sendRequest('remove-db', { databaseName: name });\n }\n\n /**\n * Rename a database\n */\n async renameDatabase(oldName: string, newName: string): Promise<any> {\n return this.sendRequest('rename-db', { databaseName: oldName, newName });\n }\n\n /**\n * Execute code in a database\n */\n async run(code: string | Function, databaseName: string): Promise<any> {\n let stringCode: string;\n if (typeof code === 'function') {\n const funcStr = code.toString();\n // ตัด arrow function หรือ function keyword และ opening brace ออก\n const arrowMatch = funcStr.match(/^[\\s]*\\(?\\s*\\)?\\s*=>\\s*{?/);\n const functionMatch = funcStr.match(/^[\\s]*function\\s*\\(?[\\w\\s]*\\)?\\s*{/);\n const match = arrowMatch || functionMatch;\n const start = match ? match[0].length : 0;\n const end = funcStr.lastIndexOf('}');\n stringCode = funcStr.substring(start, end);\n // Trim leading newline, spaces, and trailing\n stringCode = stringCode.replace(/^[\\s\\r\\n]+/, '').replace(/[\\s\\r\\n]+$/, '');\n\n // Transform import(aa).from(\"module\") to import aa from \"module\"\n stringCode = stringCode.replace(\n /import\\s*\\(\\s*([^)]+?)\\s*\\)\\s*\\.from\\s*\\(\\s*(['\"])([^'\"]+)\\2\\s*\\)/g,\n (_, importArg, quote, modulePath) => {\n // Check if importArg is wrapped in braces (destructuring)\n const trimmed = importArg.trim();\n if (trimmed.startsWith('{') && trimmed.endsWith('}')) {\n // Destructuring: import({bb}) -> import { bb }\n const inner = trimmed.slice(1, -1).trim();\n return `import { ${inner} } from ${quote}${modulePath}${quote}`;\n } else {\n // Default: import(aa) -> import aa\n return `import ${trimmed} from ${quote}${modulePath}${quote}`;\n }\n }\n );\n\n // Trim leading whitespace from each line\n stringCode = stringCode.split('\\n').map(line => line.trim()).join('\\n').trim();\n } else {\n stringCode = code;\n }\n\n return this.sendRequest('script-code', { code: stringCode, databaseName });\n }\n\n /**\n * Save a database to disk\n */\n async saveDatabase(databaseName: string): Promise<any> {\n return this.sendRequest('save-db', { databaseName });\n }\n\n /**\n * Update database metadata\n */\n async updateDatabase(databaseName: string, data: any): Promise<any> {\n return this.sendRequest('update-db', { databaseName, ...data });\n }\n\n /**\n * Get database content\n */\n async getDatabase(name: string): Promise<{ success: boolean; databaseName: string; content: string; path?: string }> {\n return this.sendRequest('get-db', { databaseName: name });\n }\n\n /**\n * Get server information\n */\n async getInfo(): Promise<any> {\n return this.sendRequest('get-info', {});\n }\n\n /**\n * Execute shell command on server\n */\n async executeShell(command: string): Promise<{ stdout: string; stderr: string }> {\n return this.sendRequest('shell-command', { command });\n }\n}\n\nexport default BrowserClient;\n\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scriptdb/browser-client",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Browser WebSocket client for ScriptDB",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -17,10 +17,7 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "dev": "bun --watch src/index.ts",
20
- "build": "bun build src/index.ts --outdir dist --target browser --format esm --splitting",
21
- "build:cjs": "bun build src/index.ts --outdir dist --target browser --format cjs --outfile dist/index.js",
22
- "build:types": "tsc --emitDeclarationOnly",
23
- "build:all": "bun run build && bun run build:cjs && bun run build:types",
20
+ "build": "tsup",
24
21
  "typecheck": "tsc --noEmit",
25
22
  "clean": "rm -rf dist"
26
23
  },