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.
- package/bin/note.js +57 -42
- 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://
|
|
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
|
-
|
|
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/${
|
|
211
|
+
let res = await apiFetch(config, `/api/notes/room/${targetRoom}/${targetCode}`);
|
|
200
212
|
|
|
201
213
|
if (res.status === 404) {
|
|
202
|
-
error(`Note "${
|
|
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/${
|
|
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: /${
|
|
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}/${
|
|
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/${
|
|
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/${
|
|
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 "${
|
|
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(
|
|
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
|
-
|
|
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/${
|
|
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(
|
|
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/${
|
|
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_${
|
|
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/${
|
|
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 /${
|
|
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
|
|
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 /${
|
|
435
|
+
info(`Deleting note /${targetRoom}/${targetCode}...`);
|
|
421
436
|
try {
|
|
422
|
-
const res = await apiFetch(config, `/api/rooms/${
|
|
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 "${
|
|
442
|
+
success(`Note "${targetCode}" deleted successfully from room "${targetRoom}".`);
|
|
428
443
|
} else {
|
|
429
444
|
error(`Failed to delete note. Status: ${res.status}`);
|
|
430
445
|
}
|