open-notepad 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/note.js +57 -42
  2. package/package.json +1 -1
package/bin/note.js CHANGED
@@ -87,7 +87,7 @@ async function loadConfig() {
87
87
  }
88
88
  }
89
89
  return {
90
- apiUrl: 'https://api-yuulabs-v1.notepad.web.id',
90
+ apiUrl: 'https://notepad.web.id',
91
91
  roomId: '',
92
92
  apiKey: ''
93
93
  };
@@ -102,6 +102,17 @@ async function saveConfig(config) {
102
102
  }
103
103
  }
104
104
 
105
+ function resolveTarget(code, config) {
106
+ let targetRoom = config.roomId;
107
+ let targetCode = code;
108
+ if (code && code.includes(':')) {
109
+ const parts = code.split(':');
110
+ targetRoom = parts[0];
111
+ targetCode = parts[1];
112
+ }
113
+ return { targetRoom, targetCode };
114
+ }
115
+
105
116
  // HTTP request wrappers
106
117
  async function apiFetch(config, endpoint, options = {}) {
107
118
  const url = `${config.apiUrl.replace(/\/$/, '')}${endpoint}`;
@@ -184,22 +195,23 @@ async function handleList() {
184
195
 
185
196
  async function handleView(codeArg) {
186
197
  const config = await loadConfig();
187
- if (!config.roomId) {
188
- warning('Not configured. Please run `note login` first.');
189
- return;
190
- }
191
-
192
198
  const code = codeArg || await ask('Enter note code to view');
193
199
  if (!code) return;
194
200
 
195
- info(`Loading note ${colors.bold}/${config.roomId}/${code}${colors.reset}...`);
201
+ const { targetRoom, targetCode } = resolveTarget(code, config);
202
+ if (!targetRoom) {
203
+ warning('No room specified. Please run `note login` or specify room:code.');
204
+ return;
205
+ }
206
+
207
+ info(`Loading note ${colors.bold}/${targetRoom}/${targetCode}${colors.reset}...`);
196
208
 
197
209
  try {
198
210
  // Attempt standard fetch with API key
199
- let res = await apiFetch(config, `/api/notes/room/${config.roomId}/${code}`);
211
+ let res = await apiFetch(config, `/api/notes/room/${targetRoom}/${targetCode}`);
200
212
 
201
213
  if (res.status === 404) {
202
- error(`Note "${code}" not found.`);
214
+ error(`Note "${targetCode}" not found in room "${targetRoom}".`);
203
215
  return;
204
216
  }
205
217
 
@@ -211,7 +223,7 @@ async function handleView(codeArg) {
211
223
 
212
224
  // Note: We bypass API Key header if providing note password for private notes
213
225
  // because backend rejects (is_api = true && private_note = true) outright.
214
- res = await apiFetch(config, `/api/notes/room/${config.roomId}/${code}`, {
226
+ res = await apiFetch(config, `/api/notes/room/${targetRoom}/${targetCode}`, {
215
227
  headers: { 'x-note-password': pwd },
216
228
  skipApiKey: true
217
229
  });
@@ -229,7 +241,7 @@ async function handleView(codeArg) {
229
241
  }
230
242
 
231
243
  clearScreen();
232
- log(`${colors.bold}${colors.blue}Note: /${config.roomId}/${code}${colors.reset}`);
244
+ log(`${colors.bold}${colors.blue}Note: /${targetRoom}/${targetCode}${colors.reset}`);
233
245
  log(`${colors.dim}------------------------------------------------------------${colors.reset}`);
234
246
  log(noteData.content || `${colors.dim}(Empty note)${colors.reset}`);
235
247
  log(`${colors.dim}------------------------------------------------------------${colors.reset}`);
@@ -240,14 +252,15 @@ async function handleView(codeArg) {
240
252
 
241
253
  async function handleCreate(codeArg) {
242
254
  const config = await loadConfig();
243
- if (!config.roomId) {
244
- warning('Not configured. Please run `note login` first.');
245
- return;
246
- }
247
-
248
255
  const code = codeArg || await ask('Enter new note code');
249
256
  if (!code) return;
250
257
 
258
+ const { targetRoom, targetCode } = resolveTarget(code, config);
259
+ if (!targetRoom) {
260
+ warning('No room specified. Please run `note login` or specify room:code.');
261
+ return;
262
+ }
263
+
251
264
  const isPublicStr = await ask('Make note public? (y/n)', 'y');
252
265
  const isPublic = isPublicStr.toLowerCase().startsWith('y');
253
266
 
@@ -265,11 +278,11 @@ async function handleCreate(codeArg) {
265
278
  }
266
279
  }
267
280
 
268
- info(`Creating note ${colors.bold}/${config.roomId}/${code}${colors.reset}...`);
281
+ info(`Creating note ${colors.bold}/${targetRoom}/${targetCode}${colors.reset}...`);
269
282
 
270
283
  try {
271
284
  // 1. Create/Save note with empty content (must send API key)
272
- let saveRes = await apiFetch(config, `/api/notes/room/${config.roomId}/${code}`, {
285
+ let saveRes = await apiFetch(config, `/api/notes/room/${targetRoom}/${targetCode}`, {
273
286
  method: 'POST',
274
287
  body: JSON.stringify({ content: '' })
275
288
  });
@@ -280,7 +293,7 @@ async function handleCreate(codeArg) {
280
293
  }
281
294
 
282
295
  // 2. Set visibility and password (calls settings endpoint)
283
- const settingsRes = await apiFetch(config, `/api/notes/room/${config.roomId}/${code}/settings`, {
296
+ const settingsRes = await apiFetch(config, `/api/notes/room/${targetRoom}/${targetCode}/settings`, {
284
297
  method: 'POST',
285
298
  body: JSON.stringify({
286
299
  is_public: isPublic,
@@ -293,11 +306,11 @@ async function handleCreate(codeArg) {
293
306
  return;
294
307
  }
295
308
 
296
- success(`Note "${code}" created successfully!`);
309
+ success(`Note "${targetCode}" created successfully in room "${targetRoom}"!`);
297
310
 
298
311
  const editNow = await ask('Open editor to write content now? (y/n)', 'y');
299
312
  if (editNow.toLowerCase().startsWith('y')) {
300
- await handleEdit(code);
313
+ await handleEdit(`${targetRoom}:${targetCode}`);
301
314
  }
302
315
  } catch (e) {
303
316
  error(e.message);
@@ -306,25 +319,26 @@ async function handleCreate(codeArg) {
306
319
 
307
320
  async function handleEdit(codeArg) {
308
321
  const config = await loadConfig();
309
- if (!config.roomId) {
310
- warning('Not configured. Please run `note login` first.');
311
- return;
312
- }
313
-
314
322
  const code = codeArg || await ask('Enter note code to edit');
315
323
  if (!code) return;
316
324
 
317
- info(`Fetching current content of /${config.roomId}/${code}...`);
325
+ const { targetRoom, targetCode } = resolveTarget(code, config);
326
+ if (!targetRoom) {
327
+ warning('No room specified. Please run `note login` or specify room:code.');
328
+ return;
329
+ }
330
+
331
+ info(`Fetching current content of /${targetRoom}/${targetCode}...`);
318
332
 
319
333
  try {
320
334
  let notePassword = '';
321
- let res = await apiFetch(config, `/api/notes/room/${config.roomId}/${code}`);
335
+ let res = await apiFetch(config, `/api/notes/room/${targetRoom}/${targetCode}`);
322
336
 
323
337
  // If it doesn't exist, offer to create it
324
338
  if (res.status === 404) {
325
339
  const create = await ask('Note does not exist. Create it? (y/n)', 'y');
326
340
  if (create.toLowerCase().startsWith('y')) {
327
- await handleCreate(code);
341
+ await handleCreate(`${targetRoom}:${targetCode}`);
328
342
  }
329
343
  return;
330
344
  }
@@ -335,7 +349,7 @@ async function handleEdit(codeArg) {
335
349
  if (noteData.has_password && (!noteData.content || res.status === 403)) {
336
350
  notePassword = await askPassword('Enter note password to edit');
337
351
 
338
- res = await apiFetch(config, `/api/notes/room/${config.roomId}/${code}`, {
352
+ res = await apiFetch(config, `/api/notes/room/${targetRoom}/${targetCode}`, {
339
353
  headers: { 'x-note-password': notePassword },
340
354
  skipApiKey: true
341
355
  });
@@ -356,7 +370,7 @@ async function handleEdit(codeArg) {
356
370
 
357
371
  // Create temp file
358
372
  const tempDir = os.tmpdir();
359
- const tempFilePath = path.join(tempDir, `note_${config.roomId}_${code}.txt`);
373
+ const tempFilePath = path.join(tempDir, `note_${targetRoom}_${targetCode}.txt`);
360
374
  await fs.writeFile(tempFilePath, initialContent, 'utf-8');
361
375
 
362
376
  // Open editor
@@ -380,7 +394,7 @@ async function handleEdit(codeArg) {
380
394
  info('Saving changes back to server...');
381
395
 
382
396
  // Save note
383
- const saveRes = await apiFetch(config, `/api/notes/room/${config.roomId}/${code}`, {
397
+ const saveRes = await apiFetch(config, `/api/notes/room/${targetRoom}/${targetCode}`, {
384
398
  method: 'POST',
385
399
  headers: notePassword ? { 'x-note-password': notePassword } : {},
386
400
  skipApiKey: !!notePassword, // Skip API key header if note password is used
@@ -388,7 +402,7 @@ async function handleEdit(codeArg) {
388
402
  });
389
403
 
390
404
  if (saveRes.ok) {
391
- success(`Saved /${config.roomId}/${code} successfully!`);
405
+ success(`Saved /${targetRoom}/${targetCode} successfully!`);
392
406
  } else {
393
407
  error(`Failed to save changes. Server returned status: ${saveRes.status}`);
394
408
  }
@@ -403,28 +417,29 @@ async function handleEdit(codeArg) {
403
417
 
404
418
  async function handleDelete(codeArg) {
405
419
  const config = await loadConfig();
406
- if (!config.roomId) {
407
- warning('Not configured. Please run `note login` first.');
408
- return;
409
- }
410
-
411
420
  const code = codeArg || await ask('Enter note code to delete');
412
421
  if (!code) return;
413
422
 
414
- const confirm = await ask(`Are you sure you want to delete /${config.roomId}/${code}? (y/n)`, 'n');
423
+ const { targetRoom, targetCode } = resolveTarget(code, config);
424
+ if (!targetRoom) {
425
+ warning('No room specified. Please run `note login` or specify room:code.');
426
+ return;
427
+ }
428
+
429
+ const confirm = await ask(`Are you sure you want to delete /${targetRoom}/${targetCode}? (y/n)`, 'n');
415
430
  if (!confirm.toLowerCase().startsWith('y')) {
416
431
  info('Delete canceled.');
417
432
  return;
418
433
  }
419
434
 
420
- info(`Deleting note /${config.roomId}/${code}...`);
435
+ info(`Deleting note /${targetRoom}/${targetCode}...`);
421
436
  try {
422
- const res = await apiFetch(config, `/api/rooms/${config.roomId}/notes/${code}`, {
437
+ const res = await apiFetch(config, `/api/rooms/${targetRoom}/notes/${targetCode}`, {
423
438
  method: 'DELETE'
424
439
  });
425
440
 
426
441
  if (res.ok) {
427
- success(`Note "${code}" deleted successfully.`);
442
+ success(`Note "${targetCode}" deleted successfully from room "${targetRoom}".`);
428
443
  } else {
429
444
  error(`Failed to delete note. Status: ${res.status}`);
430
445
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-notepad",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "CLI tool for notepad.web.id to access, edit, create, and list room notes interactively.",
5
5
  "type": "module",
6
6
  "bin": {