thinkncollab-shell 0.0.7 → 0.0.9

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.
@@ -1,100 +1,100 @@
1
- /**
2
- * src/core/project-config.js
3
- *
4
- * Shell-side reader for .tncproject binary files.
5
- * NO crypto code — shell only reads the plaintext roomId prefix,
6
- * then sends the raw file to the server for decryption.
7
- *
8
- * File layout (written by server):
9
- * [4 bytes] "TNCP" magic
10
- * [1 byte] version 0x01
11
- * [24 bytes] roomId ASCII hex ← only readable part
12
- * [12 bytes] AES-GCM IV ← opaque
13
- * [16 bytes] AES-GCM auth tag ← opaque
14
- * [N bytes] encrypted payload ← opaque
15
- */
16
-
17
- const fs = require('fs-extra');
18
- const path = require('path');
19
- const os = require('os');
20
-
21
- const CONFIG_FILE = 'tncproject';
22
- const MAGIC = Buffer.from('TNCP');
23
- const ROOM_ID_SIZE = 24;
24
- const MIN_SIZE = 4 + 1 + ROOM_ID_SIZE + 12 + 16 + 2; // 59 bytes minimum
25
-
26
- function findConfigFile(startDir = process.cwd()) {
27
- let dir = path.resolve(startDir);
28
- const root = path.parse(dir).root;
29
-
30
- while (true) {
31
- const candidate = path.join(dir, CONFIG_FILE);
32
- if (fs.existsSync(candidate)) return candidate;
33
- if (dir === root || dir === os.homedir()) break;
34
- dir = path.dirname(dir);
35
- }
36
- return null;
37
- }
38
-
39
- /**
40
- * Read and lightly validate a .tncproject file.
41
- * Returns { filePath, roomId, fileBase64 } — no decryption.
42
- *
43
- * @throws if file is missing, wrong format, or roomId looks wrong
44
- */
45
- function loadProjectConfig(startDir = process.cwd()) {
46
- const filePath = findConfigFile(startDir);
47
-
48
- if (!filePath) {
49
- throw new Error(
50
- 'No .tncproject file found in this directory or any parent.\n' +
51
- ' Download it from: ThinkNCollab → Room → Project Config'
52
- );
53
- }
54
-
55
- const buf = fs.readFileSync(filePath);
56
-
57
- if (buf.length < MIN_SIZE) {
58
- throw new Error(
59
- 'Invalid .tncproject — file too small or corrupted.\n' +
60
- ' Re-download it from the dashboard.'
61
- );
62
- }
63
-
64
- if (!buf.slice(0, 4).equals(MAGIC)) {
65
- throw new Error(
66
- 'Not a ThinkNCollab project config file.\n' +
67
- ' Re-download from the dashboard.'
68
- );
69
- }
70
-
71
- const version = buf.readUInt8(4);
72
- if (version !== 0x01) {
73
- throw new Error(
74
- `Unsupported .tncproject version (${version}).\n` +
75
- ' Update thinkncollab-shell: npm update -g thinkncollab-shell'
76
- );
77
- }
78
-
79
- // Read roomId from plaintext prefix — bytes 5..28
80
- const roomId = buf.slice(5, 5 + ROOM_ID_SIZE).toString('ascii').trim();
81
-
82
- if (!/^[a-f0-9]{24}$/i.test(roomId)) {
83
- throw new Error(
84
- 'Corrupted .tncproject — invalid roomId.\n' +
85
- ' Re-download it from the dashboard.'
86
- );
87
- }
88
-
89
- return {
90
- filePath,
91
- roomId,
92
- fileBase64: buf.toString('base64'), // sent as-is to server
93
- };
94
- }
95
-
96
- function hasProjectConfig(startDir = process.cwd()) {
97
- return !!findConfigFile(startDir);
98
- }
99
-
1
+ /*
2
+ src/core/project-config.js
3
+
4
+ Shell-side reader for .tncproject binary files.
5
+ NO crypto code — shell only reads the plaintext roomId prefix,
6
+ then sends the raw file to the server for decryption.
7
+
8
+ File layout (written by server):
9
+ [4 bytes] "TNCP" magic
10
+ [1 byte] version 0x01
11
+ [24 bytes] roomId ASCII hex ← only readable part
12
+ [12 bytes] AES-GCM IV ← opaque
13
+ [16 bytes] AES-GCM auth tag ← opaque
14
+ [N bytes] encrypted payload ← opaque
15
+ */
16
+
17
+ const fs = require('fs-extra');
18
+ const path = require('path');
19
+ const os = require('os');
20
+
21
+ const CONFIG_FILE = 'tncproject';
22
+ const MAGIC = Buffer.from('TNCP');
23
+ const ROOM_ID_SIZE = 24;
24
+ const MIN_SIZE = 4 + 1 + ROOM_ID_SIZE + 12 + 16 + 2; // 59 bytes minimum
25
+
26
+ function findConfigFile(startDir = process.cwd()) {
27
+ let dir = path.resolve(startDir);
28
+ const root = path.parse(dir).root;
29
+
30
+ while (true) {
31
+ const candidate = path.join(dir, CONFIG_FILE);
32
+ if (fs.existsSync(candidate)) return candidate;
33
+ if (dir === root || dir === os.homedir()) break;
34
+ dir = path.dirname(dir);
35
+ }
36
+ return null;
37
+ }
38
+
39
+ /*
40
+ Read and lightly validate a .tncproject file.
41
+ Returns { filePath, roomId, fileBase64 } — no decryption.
42
+
43
+ @throws if file is missing, wrong format, or roomId looks wrong http://localhost:3001
44
+ */
45
+ function loadProjectConfig(startDir = process.cwd()) {
46
+ const filePath = findConfigFile(startDir);
47
+
48
+ if (!filePath) {
49
+ throw new Error(
50
+ 'No .tncproject file found in this directory or any parent.\n' +
51
+ ' Download it from: ThinkNCollab → Room → Project Config'
52
+ );
53
+ }
54
+
55
+ const buf = fs.readFileSync(filePath);
56
+
57
+ if (buf.length < MIN_SIZE) {
58
+ throw new Error(
59
+ 'Invalid .tncproject — file too small or corrupted.\n' +
60
+ ' Re-download it from the dashboard.'
61
+ );
62
+ }
63
+
64
+ if (!buf.slice(0, 4).equals(MAGIC)) {
65
+ throw new Error(
66
+ 'Not a ThinkNCollab project config file.\n' +
67
+ ' Re-download from the dashboard.'
68
+ );
69
+ }
70
+
71
+ const version = buf.readUInt8(4);
72
+ if (version !== 0x01) {
73
+ throw new Error(
74
+ `Unsupported .tncproject version (${version}).\n` +
75
+ ' Update thinkncollab-shell: npm update -g thinkncollab-shell'
76
+ );
77
+ }
78
+
79
+ // Read roomId from plaintext prefix — bytes 5..28
80
+ const roomId = buf.slice(5, 5 + ROOM_ID_SIZE).toString('ascii').trim();
81
+
82
+ if (!/^[a-f0-9]{24}$/i.test(roomId)) {
83
+ throw new Error(
84
+ 'Corrupted .tncproject — invalid roomId.\n' +
85
+ ' Re-download it from the dashboard.'
86
+ );
87
+ }
88
+
89
+ return {
90
+ filePath,
91
+ roomId,
92
+ fileBase64: buf.toString('base64'), // sent as-is to server
93
+ };
94
+ }
95
+
96
+ function hasProjectConfig(startDir = process.cwd()) {
97
+ return !!findConfigFile(startDir);
98
+ }
99
+
100
100
  module.exports = { loadProjectConfig, hasProjectConfig, CONFIG_FILE };
package/src/core/shell.js CHANGED
@@ -35,7 +35,7 @@ class ThinkNCollabShell extends EventEmitter {
35
35
  configDir: path.join(os.homedir(), '.thinkncollab'),
36
36
  maxHistory: 1000,
37
37
  websocket: {
38
- serverUrl: options.serverUrl || 'http://localhost:3001',
38
+ serverUrl: options.serverUrl || 'https://thinkncollab.com',
39
39
  autoConnect: options.autoConnect || false
40
40
  },
41
41
  ...options
@@ -54,15 +54,15 @@ class ThinkNCollabShell extends EventEmitter {
54
54
  this.tcpServer = null;
55
55
 
56
56
  this.api = new ThinkNCollabAPI({
57
- apiUrl: options.apiUrl || 'http://localhost:3001',
58
- wsUrl: options.wsUrl || 'http://localhost:3001'
57
+ apiUrl: options.apiUrl || 'https://thinkncollab.com',
58
+ wsUrl: options.wsUrl || 'https://thinkncollab.com'
59
59
  });
60
60
 
61
61
  this.commands = new Map();
62
62
  this.aliases = new Map();
63
63
  this.variables = new Map();
64
64
 
65
- // ★ Restore persisted session on startup
65
+ // Restore persisted session on startup
66
66
  // Handles both .tncproject boot AND manual login from a previous session
67
67
  if (this.api.isAuthenticated()) {
68
68
  this.ws.setUser(this.api.getUser(), this.api.getToken());
@@ -101,40 +101,166 @@ class ThinkNCollabShell extends EventEmitter {
101
101
  }
102
102
 
103
103
  // ─── Spawn notification window ────────────────────────────────────────────
104
+ spawnNotificationWindow() {
105
+ const notifyScript = path.join(__dirname, 'notification-window.js');
106
+ const port = this.notifyPort;
107
+ const env = { ...process.env, THINKNSH_NOTIFY_PORT: String(port) };
108
+
109
+ const isWSL = process.platform === 'linux' &&
110
+ (() => { try { return fs.readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft'); } catch { return false; } })();
111
+
112
+ const fallback = () => {
113
+ console.log(chalk.yellow(`\n ⚠️ Could not open notification window.`));
114
+ console.log(chalk.dim(` Open a new terminal and run:`));
115
+ console.log(chalk.cyan(` THINKNSH_NOTIFY_PORT=${port} node "${notifyScript}"\n`));
116
+ };
117
+
118
+ try {
119
+ // ── WSL ──────────────────────────────────────────────────────────────
120
+ if (isWSL) {
121
+ const winScript = notifyScript
122
+ .replace(/^\/mnt\/([a-z])/, (_, d) => `${d.toUpperCase()}:`)
123
+ .replace(/\//g, '\\');
124
+
125
+ const launchWinNode = (winExe) => {
126
+ const p = spawn(
127
+ `start cmd.exe /k ""${winExe}" "${winScript}""`,
128
+ [],
129
+ { detached: true, stdio: 'ignore', env, shell: true }
130
+ );
131
+ p.on('error', fallback);
132
+ p.unref();
133
+ };
134
+
135
+ // 1. Known paths — instant
136
+ const known = [
137
+ '/mnt/c/Program Files/nodejs/node.exe',
138
+ '/mnt/c/Program Files (x86)/nodejs/node.exe',
139
+ ];
140
+ const found = known.find(p => { try { return fs.existsSync(p); } catch { return false; } });
141
+
142
+ if (found) {
143
+ const winExe = found
144
+ .replace(/^\/mnt\/([a-z])/, (_, d) => `${d.toUpperCase()}:`)
145
+ .replace(/\//g, '\\');
146
+ launchWinNode(winExe);
147
+ } else {
148
+ // 2. Async where node
149
+ const child = spawn('cmd.exe', ['/c', 'where', 'node'], {
150
+ stdio: ['ignore', 'pipe', 'ignore']
151
+ });
152
+ let out = '';
153
+ child.stdout.on('data', d => out += d);
154
+ child.on('close', () => {
155
+ const winExe = out.trim().split('\n')[0]?.trim();
156
+ if (winExe?.endsWith('.exe')) {
157
+ launchWinNode(winExe);
158
+ } else {
159
+ // 3. Last resort
160
+ const p = spawn(
161
+ `start cmd.exe /k "wsl.exe -- bash -c 'THINKNSH_NOTIFY_PORT=${port} node \\"${notifyScript}\\"; read'"`,
162
+ [],
163
+ { detached: true, stdio: 'ignore', shell: true }
164
+ );
165
+ p.on('error', fallback);
166
+ p.unref();
167
+ }
168
+ });
169
+ }
104
170
 
105
- spawnNotificationWindow() {
106
- const notifyScript = path.join(__dirname, 'notification-window.js');
107
- const env = { ...process.env, THINKNSH_NOTIFY_PORT: String(this.notifyPort) };
171
+ // ── Windows native ────────────────────────────────────────────────────
172
+ } else if (process.platform === 'win32') {
173
+ const nodeExe = process.execPath;
174
+ const isVSCode = process.env.TERM_PROGRAM === 'vscode';
175
+
176
+ if (isVSCode) {
177
+ console.log(chalk.yellow('\n VS Code detected — open a new terminal tab and run:'));
178
+ console.log(chalk.cyan(` $env:THINKNSH_NOTIFY_PORT=${port}; node "${notifyScript}"\n`));
179
+ } else {
180
+ const launchCmd = () => {
181
+ // shell:true — Windows quoting issues handle ho jaate hain
182
+ const p = spawn(
183
+ `start cmd.exe /k ""${nodeExe}" "${notifyScript}""`,
184
+ [],
185
+ { detached: true, stdio: 'ignore', env, shell: true }
186
+ );
187
+ p.on('error', fallback);
188
+ p.unref();
189
+ };
108
190
 
109
- try {
110
- if (process.platform === 'win32') {
111
- const isVSCode = process.env.TERM_PROGRAM === 'vscode';
112
- if (isVSCode) {
113
- console.log(chalk.yellow('\n VS Code detected — open a new terminal tab and run:'));
114
- console.log(chalk.cyan(` $env:THINKNSH_NOTIFY_PORT=${this.notifyPort}; node "${notifyScript}"\n`));
115
- } else {
116
- const nodeExe = process.execPath;
117
- spawn('cmd.exe', ['/c', 'start', 'cmd.exe', '/k', `"${nodeExe}" "${notifyScript}"`],
118
- { detached: true, stdio: 'ignore', env, shell: false }).unref();
119
- }
120
- } else if (process.platform === 'darwin') {
121
- const script = `tell application "Terminal" to do script "THINKNSH_NOTIFY_PORT=${this.notifyPort} node '${notifyScript}'"`;
122
- spawn('osascript', ['-e', script], { detached: true, stdio: 'ignore' }).unref();
123
- } else {
124
- const terminals = [
125
- ['gnome-terminal', ['--', 'node', notifyScript]],
126
- ['xterm', ['-e', `node "${notifyScript}"`]],
127
- ['konsole', ['--noclose', '-e', 'node', notifyScript]],
128
- ];
129
- for (const [cmd, args] of terminals) {
130
- try { spawn(cmd, args, { detached: true, stdio: 'ignore', env }).unref(); break; } catch {}
131
- }
191
+ const wt = spawn('wt.exe', [
192
+ 'cmd.exe', '/k', `"${nodeExe}" "${notifyScript}"`
193
+ ], { detached: true, stdio: 'ignore', env });
194
+ wt.on('error', launchCmd);
195
+ wt.unref();
196
+ }
197
+ // ── macOS ─────────────────────────────────────────────────────────────
198
+ } else if (process.platform === 'darwin') {
199
+ const nodeExe = process.execPath;
200
+ const isVSCode = process.env.TERM_PROGRAM === 'vscode';
201
+ if (isVSCode) {
202
+ console.log(chalk.yellow(`\n VS Code detected — open a new terminal tab and run:`));
203
+ console.log(chalk.cyan(` THINKNSH_NOTIFY_PORT=${port} node "${notifyScript}"\n`));
204
+ return;
205
+ }
206
+ const terminalScript = `
207
+ tell application "Terminal"
208
+ do script "THINKNSH_NOTIFY_PORT=${port} '${nodeExe}' '${notifyScript}'"
209
+ activate
210
+ end tell
211
+ `;
212
+ try {
213
+ spawn('osascript', ['-e', terminalScript], {
214
+ detached: true, stdio: 'ignore'
215
+ }).unref();
216
+ } catch {
217
+ // iTerm2 fallback
218
+ const itermScript = `
219
+ tell application "iTerm2"
220
+ tell current window
221
+ create tab with default profile
222
+ tell current session of current tab
223
+ write text "THINKNSH_NOTIFY_PORT=${port} '${nodeExe}' '${notifyScript}'"
224
+ end tell
225
+ end tell
226
+ end tell
227
+ `;
228
+ try {
229
+ spawn('osascript', ['-e', itermScript], {
230
+ detached: true, stdio: 'ignore'
231
+ }).unref();
232
+ } catch { fallback(); }
132
233
  }
133
- } catch (err) {
134
- console.log(chalk.yellow(`⚠️ Could not spawn notification window: ${err.message}`));
135
- console.log(chalk.dim(` Run manually: node "${notifyScript}"`));
234
+
235
+ // ── Linux native ──────────────────────────────────────────────────────
236
+ } else {
237
+ const nodeExe = process.execPath;
238
+ const bashCmd = `THINKNSH_NOTIFY_PORT=${port} '${nodeExe}' '${notifyScript}'; read`;
239
+ const terminals = [
240
+ ['gnome-terminal', ['--', 'bash', '-c', bashCmd]],
241
+ ['konsole', ['--noclose', '-e', 'bash', '-c', bashCmd]],
242
+ ['xfce4-terminal', ['--hold', '-e', `bash -c "${bashCmd}"`]],
243
+ ['tilix', ['-e', `bash -c "${bashCmd}"`]],
244
+ ['alacritty', ['-e', 'bash', '-c', bashCmd]],
245
+ ['kitty', ['bash', '-c', bashCmd]],
246
+ ['xterm', ['-hold', '-e', `bash -c "${bashCmd}"`]],
247
+ ];
248
+
249
+ let spawned = false;
250
+ for (const [bin, args] of terminals) {
251
+ try {
252
+ spawn(bin, args, { detached: true, stdio: 'ignore', env }).unref();
253
+ spawned = true;
254
+ break;
255
+ } catch {}
256
+ }
257
+ if (!spawned) fallback();
136
258
  }
259
+
260
+ } catch (err) {
261
+ fallback();
137
262
  }
263
+ }
138
264
 
139
265
  // ─── WebSocket → Shell + TCP bridge ──────────────────────────────────────
140
266
 
@@ -308,8 +434,6 @@ setupWebSocketHandlers() {
308
434
  return true;
309
435
  }
310
436
 
311
- // ─── Execute ──────────────────────────────────────────────────────────────
312
- // shell.js — execute() mein ye change karo
313
437
  async execute(input) {
314
438
  if (!input.trim()) return;
315
439
 
@@ -317,6 +441,12 @@ async execute(input) {
317
441
  const cmdName = args[0].toLowerCase();
318
442
  const cmdArgs = args.slice(1);
319
443
 
444
+ // Skip sensitive commands
445
+ const skipLog = ['login', 'logout', 'set', 'unset'];
446
+ if (!skipLog.includes(cmdName)) {
447
+ await this.api.logEvent('command', null, { cmd: cmdName });
448
+ }
449
+
320
450
  if (this.commands.has(cmdName)) {
321
451
  try { await this.commands.get(cmdName).handler(cmdArgs, this); }
322
452
  catch (err) { console.log(chalk.red(`Error: ${err.message}`)); }
@@ -332,8 +462,7 @@ async execute(input) {
332
462
  }
333
463
  }
334
464
 
335
- // ★ Windows pe known-useless OS commands block karo
336
- const blockedOnWindows = [ 'open', 'which', 'grep', 'touch', 'cat'];
465
+ const blockedOnWindows = ['open', 'which', 'grep', 'touch', 'cat'];
337
466
  if (process.platform === 'win32' && blockedOnWindows.includes(cmdName)) {
338
467
  console.log(chalk.red(`'${cmdName}' is not a thinknsh command.`));
339
468
  console.log(chalk.dim(` Type 'help' to see available commands.`));
@@ -523,7 +652,7 @@ async execute(input) {
523
652
  stdio: 'inherit'
524
653
  });
525
654
  child.on('close', (code) => {
526
- // Update currentDir in case command changed it (cd won't but others might)
655
+ // Update currentDir in case command changed it (cd won't but others might) https://thinkncollab.com
527
656
  try { this.currentDir = process.cwd(); } catch {}
528
657
  process.stdout.write('\r\n');
529
658
  resolve();
@@ -539,7 +668,7 @@ async execute(input) {
539
668
  try { const figlet = require('figlet'); console.log(chalk.cyan(figlet.textSync('ThinkNCollab', { font: 'Standard' }))); } catch {}
540
669
  console.log(chalk.cyan(`
541
670
  ╔══════════════════════════════════════════════════════╗
542
- ║ ThinkNCollab Shell v0.0.6 ║
671
+ ║ ThinkNCollab Shell v0.0.08 ║
543
672
  ║ Type 'help' for commands ║
544
673
  ╚══════════════════════════════════════════════════════╝`));
545
674
  }
@@ -1,5 +1,5 @@
1
- /**
2
- * src/core/websocket.js — WebSocket Manager for ThinkNCollab Shell
1
+ /*
2
+ src/core/websocket.js — WebSocket Manager for ThinkNCollab Shell
3
3
  */
4
4
 
5
5
  const { io } = require('socket.io-client');
@@ -10,7 +10,7 @@ class WebSocketManager extends EventEmitter {
10
10
  constructor(config = {}) {
11
11
  super();
12
12
  this.config = {
13
- serverUrl: config.serverUrl || 'http://localhost:3001',
13
+ serverUrl: config.serverUrl || 'https://thinkncollab.com',
14
14
  reconnectAttempts: config.reconnectAttempts || 5,
15
15
  reconnectDelay: config.reconnectDelay || 1000,
16
16
  ...config
@@ -1,5 +1,5 @@
1
- /**
2
- * Notification System for ThinkNCollab Shell
1
+ /*
2
+ Notification System for ThinkNCollab Shell
3
3
  */
4
4
 
5
5
  const EventEmitter = require('events');
@@ -20,8 +20,7 @@ class NotificationManager extends EventEmitter {
20
20
  this.unreadCount = 0;
21
21
  }
22
22
 
23
- /**
24
- * Show a notification
23
+ /* Show a notification
25
24
  */
26
25
  show(notification) {
27
26
  const notif = {
@@ -61,8 +60,7 @@ class NotificationManager extends EventEmitter {
61
60
  return notif;
62
61
  }
63
62
 
64
- /**
65
- * Show notification in console
63
+ /* Show notification in console
66
64
  */
67
65
  showInConsole(notification) {
68
66
  let color = chalk.blue;
@@ -91,8 +89,7 @@ class NotificationManager extends EventEmitter {
91
89
  console.log(color(`${symbol} ${notification.title}: ${notification.message}`));
92
90
  }
93
91
 
94
- /**
95
- * Show desktop notification (if supported)
92
+ /* Show desktop notification (if supported)
96
93
  */
97
94
  showDesktopNotification(notification) {
98
95
  // Check if running in Electron
@@ -110,16 +107,14 @@ class NotificationManager extends EventEmitter {
110
107
  }
111
108
  }
112
109
 
113
- /**
114
- * Play notification sound
110
+ /* Play notification sound
115
111
  */
116
112
  playSound() {
117
113
  // TODO: Implement sound playing
118
114
  // This would use 'sound-play' or similar package
119
115
  }
120
116
 
121
- /**
122
- * Mark notification as read
117
+ /* Mark notification as read
123
118
  */
124
119
  markAsRead(id) {
125
120
  const notif = this.notifications.find(n => n.id === id);
@@ -130,8 +125,7 @@ class NotificationManager extends EventEmitter {
130
125
  }
131
126
  }
132
127
 
133
- /**
134
- * Mark all as read
128
+ /* Mark all as read
135
129
  */
136
130
  markAllAsRead() {
137
131
  this.notifications.forEach(n => {
@@ -143,22 +137,19 @@ class NotificationManager extends EventEmitter {
143
137
  this.emit('allRead');
144
138
  }
145
139
 
146
- /**
147
- * Get unread notifications
140
+ /* Get unread notifications
148
141
  */
149
142
  getUnread() {
150
143
  return this.notifications.filter(n => !n.read);
151
144
  }
152
145
 
153
- /**
154
- * Get all notifications
146
+ /* Get all notifications
155
147
  */
156
148
  getAll() {
157
149
  return this.notifications;
158
150
  }
159
151
 
160
- /**
161
- * Clear all notifications
152
+ /* Clear all notifications
162
153
  */
163
154
  clear() {
164
155
  this.notifications = [];
@@ -166,29 +157,25 @@ class NotificationManager extends EventEmitter {
166
157
  this.emit('cleared');
167
158
  }
168
159
 
169
- /**
170
- * Create success notification
160
+ /* Create success notification
171
161
  */
172
162
  success(title, message, data = {}) {
173
163
  return this.show({ type: 'success', title, message, data });
174
164
  }
175
165
 
176
- /**
177
- * Create error notification
166
+ /* Create error notification
178
167
  */
179
168
  error(title, message, data = {}) {
180
169
  return this.show({ type: 'error', title, message, data });
181
170
  }
182
171
 
183
- /**
184
- * Create warning notification
172
+ /* Create warning notification
185
173
  */
186
174
  warning(title, message, data = {}) {
187
175
  return this.show({ type: 'warning', title, message, data });
188
176
  }
189
177
 
190
- /**
191
- * Create info notification
178
+ /* Create info notification
192
179
  */
193
180
  info(title, message, data = {}) {
194
181
  return this.show({ type: 'info', title, message, data });