freshjots 0.3.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/README.md +60 -46
- package/cli.js +137 -15
- package/index.d.ts +22 -1
- package/index.js +41 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,46 +1,8 @@
|
|
|
1
|
-
# freshjots —
|
|
1
|
+
# freshjots — JS, TS, Windows CLI
|
|
2
2
|
|
|
3
3
|
Tiny JavaScript client for the [Fresh Jots](https://freshjots.com) API.
|
|
4
4
|
One file, zero dependencies (uses Node 18's global `fetch`).
|
|
5
5
|
|
|
6
|
-
## Install
|
|
7
|
-
|
|
8
|
-
```sh
|
|
9
|
-
npm install freshjots
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
(Or `pnpm add freshjots`, `yarn add freshjots`, `bun add freshjots`.)
|
|
13
|
-
|
|
14
|
-
## Use
|
|
15
|
-
|
|
16
|
-
```js
|
|
17
|
-
import { Client } from "freshjots";
|
|
18
|
-
|
|
19
|
-
// Reads FRESHJOTS_TOKEN from the environment by default.
|
|
20
|
-
const client = new Client();
|
|
21
|
-
|
|
22
|
-
// Append text to a note (creates it if missing).
|
|
23
|
-
await client.append("cron-jobs-prod", "backup ok");
|
|
24
|
-
|
|
25
|
-
// Read a note's body.
|
|
26
|
-
const note = await client.note("cron-jobs-prod");
|
|
27
|
-
console.log(note.plain_body);
|
|
28
|
-
|
|
29
|
-
// List your notes.
|
|
30
|
-
const notes = await client.notes();
|
|
31
|
-
for (const n of notes) console.log(`${n.filename}\t${n.title}`);
|
|
32
|
-
|
|
33
|
-
// Create a note. The API derives the filename from the title — for a
|
|
34
|
-
// note addressable by an exact filename, use append() instead.
|
|
35
|
-
const created = await client.create({ title: "Research 2026 Q2", body: "Initial outline." });
|
|
36
|
-
console.log(created.filename); // server-derived stream name
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
The whole API is four methods: `notes()`, `note(filename)`,
|
|
40
|
-
`create({ title, body })`, `append(filename, text)`. `note()` and
|
|
41
|
-
`create()` return the note object directly (no `{ note: … }` wrapper);
|
|
42
|
-
`notes()` returns the array.
|
|
43
|
-
|
|
44
6
|
## CLI
|
|
45
7
|
|
|
46
8
|
Installing the package globally puts a `freshjots` command on your
|
|
@@ -51,16 +13,27 @@ automatically.
|
|
|
51
13
|
|
|
52
14
|
```sh
|
|
53
15
|
npm install -g freshjots
|
|
54
|
-
|
|
16
|
+
|
|
17
|
+
# Persist the token for every new shell (macOS defaults to zsh; use ~/.bashrc on bash):
|
|
18
|
+
echo 'export FRESHJOTS_TOKEN=mn_…' >> ~/.zshrc && source ~/.zshrc
|
|
19
|
+
# Windows PowerShell: [Environment]::SetEnvironmentVariable("FRESHJOTS_TOKEN", "mn_…", "User")
|
|
55
20
|
```
|
|
56
21
|
|
|
57
|
-
The CLI
|
|
22
|
+
The CLI covers reading, writing, and organizing notes:
|
|
58
23
|
|
|
59
24
|
```sh
|
|
60
|
-
freshjots
|
|
61
|
-
freshjots
|
|
62
|
-
freshjots
|
|
25
|
+
freshjots ls # prints "<id>\t<filename>\t<title>" per row
|
|
26
|
+
freshjots ls -n 10 --sort created # last 10 by creation (--sort created|updated|appended)
|
|
27
|
+
freshjots ls --folder Work # filter by folder id or name; --root for un-foldered
|
|
28
|
+
freshjots ls --all -l # every page, long format (id, updated, lock, folder, …)
|
|
29
|
+
freshjots get 42 # full note as JSON
|
|
30
|
+
freshjots cat cron-jobs-prod # note body, by id or filename
|
|
31
|
+
freshjots create "Research 2026 Q2" # body from stdin or --body
|
|
63
32
|
freshjots append cron-jobs-prod "ok" # text may also be piped on stdin
|
|
33
|
+
freshjots rm cron-jobs-prod # delete by id or filename
|
|
34
|
+
freshjots mv cron-jobs-prod Work # move into a folder (id or name); --root to un-folder
|
|
35
|
+
freshjots folders # prints "<id>\t<name>" per row
|
|
36
|
+
freshjots --version # print version (--help for full usage)
|
|
64
37
|
```
|
|
65
38
|
|
|
66
39
|
Both `create` and `append` read from stdin when the body or text isn't
|
|
@@ -82,6 +55,47 @@ Exit codes: `0` on success, `1` on runtime errors (missing token,
|
|
|
82
55
|
network failure, non-2xx API response — printed as `Error: HTTP <status>
|
|
83
56
|
<code>: <message>`), `2` on usage errors.
|
|
84
57
|
|
|
58
|
+
## Install
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
npm install freshjots
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
(Or `pnpm add freshjots`, `yarn add freshjots`, `bun add freshjots`.)
|
|
65
|
+
|
|
66
|
+
## Use
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
import { Client } from "freshjots";
|
|
70
|
+
|
|
71
|
+
// Reads FRESHJOTS_TOKEN from the environment by default.
|
|
72
|
+
const client = new Client();
|
|
73
|
+
|
|
74
|
+
// Append text to a note (creates it if missing).
|
|
75
|
+
await client.append("cron-jobs-prod", "backup ok");
|
|
76
|
+
|
|
77
|
+
// Read a note's body.
|
|
78
|
+
const note = await client.note("cron-jobs-prod");
|
|
79
|
+
console.log(note.plain_body);
|
|
80
|
+
|
|
81
|
+
// List your notes (most recent activity first). Pass options to sort/filter:
|
|
82
|
+
const notes = await client.notes({ sort: "created", folderId: 3, limit: 20 });
|
|
83
|
+
for (const n of notes) console.log(`${n.id}\t${n.filename}\t${n.title}`);
|
|
84
|
+
|
|
85
|
+
// Create a note. The API derives the filename from the title — for a
|
|
86
|
+
// note addressable by an exact filename, use append() instead.
|
|
87
|
+
const created = await client.create({ title: "Research 2026 Q2", body: "Initial outline." });
|
|
88
|
+
console.log(created.filename); // server-derived stream name
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Client methods: `notes({ sort, folderId, limit, offset })`,
|
|
92
|
+
`note(filename)`, `noteById(id)`, `create({ title, body })`,
|
|
93
|
+
`append(filename, text)`, `remove(id)`, `move(id, folderId)`, and
|
|
94
|
+
`folders()`. `note()`/`noteById()`/`create()` return the note object
|
|
95
|
+
directly (no `{ note: … }` wrapper); `notes()` and `folders()` return
|
|
96
|
+
arrays. For `notes()`, `sort` is `created|updated|appended` and
|
|
97
|
+
`folderId` may be a folder id or `"none"` (un-foldered only).
|
|
98
|
+
|
|
85
99
|
## TypeScript
|
|
86
100
|
|
|
87
101
|
Types ship with the package — no `@types/freshjots` needed, no `.d.ts`
|
|
@@ -133,8 +147,8 @@ Stable error codes: `unauthenticated`, `forbidden`, `not_found`,
|
|
|
133
147
|
|
|
134
148
|
## Auth
|
|
135
149
|
|
|
136
|
-
Mint a token at <https://freshjots.com/settings/api_tokens> (
|
|
137
|
-
|
|
150
|
+
Mint a token at <https://freshjots.com/settings/api_tokens> (Pro or
|
|
151
|
+
Team tier required). Set it once:
|
|
138
152
|
|
|
139
153
|
```sh
|
|
140
154
|
export FRESHJOTS_TOKEN=<your-token>
|
package/cli.js
CHANGED
|
@@ -8,10 +8,19 @@ import { Client, ApiError, VERSION } from "./index.js";
|
|
|
8
8
|
const USAGE = `freshjots — Fresh Jots CLI
|
|
9
9
|
|
|
10
10
|
Usage:
|
|
11
|
-
freshjots
|
|
12
|
-
|
|
11
|
+
freshjots ls [flags] List notes as id<TAB>filename<TAB>title.
|
|
12
|
+
-n N | --limit N
|
|
13
|
+
--sort created|updated|appended
|
|
14
|
+
--folder <id|name> | --root
|
|
15
|
+
--all fetch every page (past the 200 cap)
|
|
16
|
+
-l|--long id, updated_at, lock, folder, name, title
|
|
17
|
+
freshjots get <id> Print a note as JSON (full metadata).
|
|
18
|
+
freshjots cat <id|filename> Print a note's body.
|
|
13
19
|
freshjots create <title> [--body <text>]
|
|
14
20
|
freshjots append <filename> [<text>]
|
|
21
|
+
freshjots rm <id|filename> Delete a note.
|
|
22
|
+
freshjots mv <id|filename> <folder-id|name|--root>
|
|
23
|
+
freshjots folders List folders as id<TAB>name.
|
|
15
24
|
freshjots --help | --version
|
|
16
25
|
|
|
17
26
|
Notes:
|
|
@@ -20,6 +29,9 @@ Notes:
|
|
|
20
29
|
https://freshjots.com/settings/api_tokens.
|
|
21
30
|
`;
|
|
22
31
|
|
|
32
|
+
const isNumeric = (s) => /^\d+$/.test(s);
|
|
33
|
+
const errResult = (message) => ({ command: "error", message });
|
|
34
|
+
|
|
23
35
|
export function parseArgs(argv) {
|
|
24
36
|
if (argv.length === 0) return { command: "help", exitCode: 2 };
|
|
25
37
|
const [first, ...rest] = argv;
|
|
@@ -30,13 +42,38 @@ export function parseArgs(argv) {
|
|
|
30
42
|
if (first === "-v" || first === "--version" || first === "version") {
|
|
31
43
|
return { command: "version" };
|
|
32
44
|
}
|
|
33
|
-
if (first === "list") {
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
if (first === "list" || first === "ls") {
|
|
46
|
+
const opts = { command: "list", limit: null, sort: null, folder: null, all: false, long: false };
|
|
47
|
+
for (let i = 0; i < rest.length; i++) {
|
|
48
|
+
const a = rest[i];
|
|
49
|
+
if (a === "-n" || a === "--limit") {
|
|
50
|
+
if (i + 1 >= rest.length) return errResult("--limit requires a value");
|
|
51
|
+
opts.limit = rest[++i];
|
|
52
|
+
} else if (a === "--sort") {
|
|
53
|
+
if (i + 1 >= rest.length) return errResult("--sort requires a value");
|
|
54
|
+
opts.sort = rest[++i];
|
|
55
|
+
} else if (a === "--folder") {
|
|
56
|
+
if (i + 1 >= rest.length) return errResult("--folder requires a value");
|
|
57
|
+
opts.folder = rest[++i];
|
|
58
|
+
} else if (a === "--root") {
|
|
59
|
+
opts.folder = "none";
|
|
60
|
+
} else if (a === "--all") {
|
|
61
|
+
opts.all = true;
|
|
62
|
+
} else if (a === "-l" || a === "--long") {
|
|
63
|
+
opts.long = true;
|
|
64
|
+
} else {
|
|
65
|
+
return errResult(`unknown flag for list: ${a}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return opts;
|
|
69
|
+
}
|
|
70
|
+
if (first === "get") {
|
|
71
|
+
if (rest.length !== 1) return errResult("get requires exactly one <id>");
|
|
72
|
+
return { command: "get", id: rest[0] };
|
|
36
73
|
}
|
|
37
|
-
if (first === "show") {
|
|
38
|
-
if (rest.length !== 1) return {
|
|
39
|
-
return { command: "show",
|
|
74
|
+
if (first === "show" || first === "cat") {
|
|
75
|
+
if (rest.length !== 1) return errResult(`${first} requires exactly one <id|filename>`);
|
|
76
|
+
return { command: "show", target: rest[0] };
|
|
40
77
|
}
|
|
41
78
|
if (first === "create") {
|
|
42
79
|
let body;
|
|
@@ -44,7 +81,7 @@ export function parseArgs(argv) {
|
|
|
44
81
|
for (let i = 0; i < rest.length; i++) {
|
|
45
82
|
const a = rest[i];
|
|
46
83
|
if (a === "--body" || a === "-b") {
|
|
47
|
-
if (i + 1 >= rest.length) return
|
|
84
|
+
if (i + 1 >= rest.length) return errResult("--body requires a value");
|
|
48
85
|
body = rest[++i];
|
|
49
86
|
} else if (a.startsWith("--body=")) {
|
|
50
87
|
body = a.slice("--body=".length);
|
|
@@ -52,16 +89,28 @@ export function parseArgs(argv) {
|
|
|
52
89
|
positional.push(a);
|
|
53
90
|
}
|
|
54
91
|
}
|
|
55
|
-
if (positional.length !== 1) return
|
|
92
|
+
if (positional.length !== 1) return errResult("create requires exactly one <title>");
|
|
56
93
|
return { command: "create", title: positional[0], body };
|
|
57
94
|
}
|
|
58
95
|
if (first === "append") {
|
|
59
96
|
if (rest.length < 1 || rest.length > 2) {
|
|
60
|
-
return
|
|
97
|
+
return errResult("append requires <filename> and optional <text>");
|
|
61
98
|
}
|
|
62
99
|
return { command: "append", filename: rest[0], text: rest[1] };
|
|
63
100
|
}
|
|
64
|
-
|
|
101
|
+
if (first === "rm" || first === "delete") {
|
|
102
|
+
if (rest.length !== 1) return errResult(`${first} requires exactly one <id|filename>`);
|
|
103
|
+
return { command: "rm", target: rest[0] };
|
|
104
|
+
}
|
|
105
|
+
if (first === "mv" || first === "move") {
|
|
106
|
+
if (rest.length !== 2) return errResult(`${first} requires <id|filename> <folder-id|name|--root>`);
|
|
107
|
+
return { command: "mv", target: rest[0], dest: rest[1] };
|
|
108
|
+
}
|
|
109
|
+
if (first === "folders") {
|
|
110
|
+
if (rest.length) return errResult("folders takes no arguments");
|
|
111
|
+
return { command: "folders" };
|
|
112
|
+
}
|
|
113
|
+
return errResult(`unknown command: ${first}`);
|
|
65
114
|
}
|
|
66
115
|
|
|
67
116
|
async function readStdin(stdin) {
|
|
@@ -73,6 +122,34 @@ async function readStdin(stdin) {
|
|
|
73
122
|
return buf;
|
|
74
123
|
}
|
|
75
124
|
|
|
125
|
+
// A note argument may be a numeric id (used as-is) or a filename/title,
|
|
126
|
+
// resolved to an id via the by-filename lookup (which carries .id).
|
|
127
|
+
async function resolveNoteId(client, target) {
|
|
128
|
+
if (isNumeric(target)) return target;
|
|
129
|
+
return (await client.note(target)).id;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// A folder NAME resolves to its id via GET /folders; ambiguous or unknown
|
|
133
|
+
// names are an error (disambiguate with the numeric id).
|
|
134
|
+
async function resolveFolderName(client, name) {
|
|
135
|
+
const matches = (await client.folders()).filter((f) => f.name === name);
|
|
136
|
+
if (matches.length === 0) throw new Error(`no folder named '${name}' (see: freshjots folders)`);
|
|
137
|
+
if (matches.length > 1) throw new Error(`ambiguous folder name '${name}' — use its numeric id`);
|
|
138
|
+
return matches[0].id;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function printNotes(notes, long, stdout) {
|
|
142
|
+
for (const n of notes) {
|
|
143
|
+
const title = n.title ?? "(untitled)";
|
|
144
|
+
if (long) {
|
|
145
|
+
const lock = n.append_only ? "L" : "-";
|
|
146
|
+
stdout(`${n.id}\t${n.updated_at}\t${lock}\t${n.folder_id ?? "-"}\t${n.filename}\t${title}\n`);
|
|
147
|
+
} else {
|
|
148
|
+
stdout(`${n.id}\t${n.filename}\t${title}\n`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
76
153
|
export async function run(argv, deps = {}) {
|
|
77
154
|
const env = deps.env ?? process.env;
|
|
78
155
|
const stdout = deps.stdout ?? ((s) => process.stdout.write(s));
|
|
@@ -111,12 +188,40 @@ export async function run(argv, deps = {}) {
|
|
|
111
188
|
|
|
112
189
|
try {
|
|
113
190
|
if (parsed.command === "list") {
|
|
114
|
-
|
|
115
|
-
|
|
191
|
+
let folderId;
|
|
192
|
+
if (parsed.folder) {
|
|
193
|
+
if (parsed.folder === "none") folderId = "none";
|
|
194
|
+
else if (isNumeric(parsed.folder)) folderId = parsed.folder;
|
|
195
|
+
else folderId = await resolveFolderName(client, parsed.folder);
|
|
196
|
+
}
|
|
197
|
+
let notes;
|
|
198
|
+
if (parsed.all) {
|
|
199
|
+
notes = [];
|
|
200
|
+
let offset = 0;
|
|
201
|
+
for (;;) {
|
|
202
|
+
const page = await client.notes({ sort: parsed.sort, folderId, limit: 200, offset });
|
|
203
|
+
notes.push(...page);
|
|
204
|
+
if (page.length < 200) break;
|
|
205
|
+
offset += 200;
|
|
206
|
+
if (offset >= 100000) {
|
|
207
|
+
stderr("stopping at 100000 notes (safety cap) — narrow with --folder or --sort\n");
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
notes = await client.notes({ sort: parsed.sort, folderId, limit: parsed.limit ?? undefined });
|
|
213
|
+
}
|
|
214
|
+
printNotes(notes, parsed.long, stdout);
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
if (parsed.command === "get") {
|
|
218
|
+
stdout(`${JSON.stringify(await client.noteById(parsed.id), null, 2)}\n`);
|
|
116
219
|
return 0;
|
|
117
220
|
}
|
|
118
221
|
if (parsed.command === "show") {
|
|
119
|
-
const note =
|
|
222
|
+
const note = isNumeric(parsed.target)
|
|
223
|
+
? await client.noteById(parsed.target)
|
|
224
|
+
: await client.note(parsed.target);
|
|
120
225
|
stdout(note.plain_body ?? "");
|
|
121
226
|
return 0;
|
|
122
227
|
}
|
|
@@ -137,6 +242,23 @@ export async function run(argv, deps = {}) {
|
|
|
137
242
|
await client.append(parsed.filename, text);
|
|
138
243
|
return 0;
|
|
139
244
|
}
|
|
245
|
+
if (parsed.command === "rm") {
|
|
246
|
+
await client.remove(await resolveNoteId(client, parsed.target));
|
|
247
|
+
return 0;
|
|
248
|
+
}
|
|
249
|
+
if (parsed.command === "mv") {
|
|
250
|
+
const id = await resolveNoteId(client, parsed.target);
|
|
251
|
+
let folderId;
|
|
252
|
+
if (["--root", "root", "none", "null"].includes(parsed.dest)) folderId = null;
|
|
253
|
+
else if (isNumeric(parsed.dest)) folderId = parsed.dest;
|
|
254
|
+
else folderId = await resolveFolderName(client, parsed.dest);
|
|
255
|
+
await client.move(id, folderId);
|
|
256
|
+
return 0;
|
|
257
|
+
}
|
|
258
|
+
if (parsed.command === "folders") {
|
|
259
|
+
for (const f of await client.folders()) stdout(`${f.id}\t${f.name}\n`);
|
|
260
|
+
return 0;
|
|
261
|
+
}
|
|
140
262
|
} catch (e) {
|
|
141
263
|
if (e instanceof ApiError) {
|
|
142
264
|
stderr(`Error: HTTP ${e.status} ${e.code}: ${e.message}\n`);
|
package/index.d.ts
CHANGED
|
@@ -56,6 +56,23 @@ declare module "freshjots" {
|
|
|
56
56
|
constructor(opts: { status: number; code: ApiErrorCode; message: string; details?: unknown });
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/** A folder, as returned by `folders()`. */
|
|
60
|
+
export interface Folder {
|
|
61
|
+
id: number;
|
|
62
|
+
name: string;
|
|
63
|
+
created_at: string;
|
|
64
|
+
updated_at: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Options for `notes()` — mirror the API's list query params. */
|
|
68
|
+
export interface ListOptions {
|
|
69
|
+
sort?: "created" | "updated" | "appended";
|
|
70
|
+
/** A folder id, or "none" for un-foldered notes only. */
|
|
71
|
+
folderId?: number | string;
|
|
72
|
+
limit?: number;
|
|
73
|
+
offset?: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
59
76
|
export interface ClientOptions {
|
|
60
77
|
token?: string;
|
|
61
78
|
baseUrl?: string;
|
|
@@ -75,9 +92,13 @@ declare module "freshjots" {
|
|
|
75
92
|
token: string;
|
|
76
93
|
baseUrl: string;
|
|
77
94
|
constructor(options?: ClientOptions);
|
|
78
|
-
notes(): Promise<NoteSummary[]>;
|
|
95
|
+
notes(options?: ListOptions): Promise<NoteSummary[]>;
|
|
79
96
|
note(filename: string): Promise<Note>;
|
|
97
|
+
noteById(id: number | string): Promise<Note>;
|
|
80
98
|
create(input: CreateInput): Promise<Note>;
|
|
81
99
|
append(filename: string, text: string): Promise<true>;
|
|
100
|
+
remove(id: number | string): Promise<true>;
|
|
101
|
+
move(id: number | string, folderId: number | string | null): Promise<Note>;
|
|
102
|
+
folders(): Promise<Folder[]>;
|
|
82
103
|
}
|
|
83
104
|
}
|
package/index.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// payload ({ "notes": [...] }). show / show-by-filename / create return
|
|
19
19
|
// the note object at the TOP LEVEL — there is no { "note": ... } wrapper.
|
|
20
20
|
|
|
21
|
-
export const VERSION = "0.
|
|
21
|
+
export const VERSION = "1.0.1";
|
|
22
22
|
const DEFAULT_BASE_URL = "https://freshjots.com/api/v1";
|
|
23
23
|
|
|
24
24
|
export class ApiError extends Error {
|
|
@@ -40,8 +40,20 @@ export class Client {
|
|
|
40
40
|
this.baseUrl = baseUrl;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// List notes (summary projection). Options mirror the API query params:
|
|
44
|
+
// sort: "created" | "updated" | "appended" (default updated)
|
|
45
|
+
// folderId: a folder id, or "none" for un-foldered notes only
|
|
46
|
+
// limit/offset: pagination (server caps a page at 200)
|
|
47
|
+
async notes({ sort, folderId, limit, offset } = {}) {
|
|
48
|
+
const qs = new URLSearchParams();
|
|
49
|
+
if (sort) qs.set("sort", sort);
|
|
50
|
+
if (folderId !== undefined && folderId !== null && folderId !== "") {
|
|
51
|
+
qs.set("folder_id", String(folderId));
|
|
52
|
+
}
|
|
53
|
+
if (limit !== undefined && limit !== null && limit !== "") qs.set("limit", String(limit));
|
|
54
|
+
if (offset !== undefined && offset !== null && offset !== "") qs.set("offset", String(offset));
|
|
55
|
+
const q = qs.toString();
|
|
56
|
+
return (await this._request("GET", q ? `/notes?${q}` : "/notes")).notes;
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
async note(filename) {
|
|
@@ -51,6 +63,32 @@ export class Client {
|
|
|
51
63
|
return await this._request("GET", path);
|
|
52
64
|
}
|
|
53
65
|
|
|
66
|
+
// Full note by numeric id (GET /notes/:id) — top-level serializer.
|
|
67
|
+
async noteById(id) {
|
|
68
|
+
return await this._request("GET", `/notes/${encodeURIComponent(id)}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Delete a note by id. Locked (append-only) notes are refused by the
|
|
72
|
+
// API with note_locked. Returns true on success (204).
|
|
73
|
+
async remove(id) {
|
|
74
|
+
await this._request("DELETE", `/notes/${encodeURIComponent(id)}`);
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Move a note into a folder (or to the root with folderId null/"none").
|
|
79
|
+
async move(id, folderId) {
|
|
80
|
+
const folder_id =
|
|
81
|
+
folderId === null || folderId === undefined || folderId === "" || folderId === "none"
|
|
82
|
+
? null
|
|
83
|
+
: folderId;
|
|
84
|
+
return await this._request("POST", `/notes/${encodeURIComponent(id)}/move`, { folder_id });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// List folders ({ folders: [...] } envelope).
|
|
88
|
+
async folders() {
|
|
89
|
+
return (await this._request("GET", "/folders")).folders;
|
|
90
|
+
}
|
|
91
|
+
|
|
54
92
|
// Create a note. The API permits note[title, plain_body, format, ...]
|
|
55
93
|
// — NOT filename: the server DERIVES the filename from the title. For
|
|
56
94
|
// a note addressable by an exact, caller-chosen filename, use append()
|
package/package.json
CHANGED