notefeed 0.5.0 → 0.7.0
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 +12 -0
- package/dist/cli.js +36 -7
- package/dist/client.d.ts +45 -6
- package/dist/client.js +67 -13
- package/dist/generated/index.d.ts +2 -2
- package/dist/generated/index.js +1 -1
- package/dist/generated/sdk.gen.d.ts +56 -2
- package/dist/generated/sdk.gen.js +104 -1
- package/dist/generated/types.gen.d.ts +549 -9
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@ export NOTEFEED_URL=https://notes.example.com NOTEFEED_FEED=homelab-7f3k2q9x4m8w
|
|
|
8
8
|
npx notefeed post "# Backup finished"
|
|
9
9
|
backup.sh 2>&1 | npx notefeed post -
|
|
10
10
|
npx notefeed notes --limit 5
|
|
11
|
+
npx notefeed edit 20260929T140512Z-backup-finished "# Backup finished, verified"
|
|
12
|
+
npx notefeed delete 20260929T140512Z-backup-finished
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
```js
|
|
@@ -19,6 +21,16 @@ console.log(created.url, created.read_url);
|
|
|
19
21
|
for await (const note of client.notes()) console.log(note.created_at, note.title); // newest first, page by page
|
|
20
22
|
```
|
|
21
23
|
|
|
24
|
+
`read_url` is `null` for a feed without a read link (rare; see the operations docs).
|
|
25
|
+
|
|
22
26
|
`Client.fromEnv()` reads `NOTEFEED_URL` / `NOTEFEED_FEED` / `NOTEFEED_PASSWORD`; so does the `notefeed` command, unless given `--url` / `--feed` / `--password`.
|
|
23
27
|
|
|
28
|
+
A feed can have its own password, which gates reading, listing and posting to it. Pass `feedPassword: "..."` to `new Client(...)` (or per call, e.g. `client.post(text, { feedPassword })`), or set `NOTEFEED_FEED_PASSWORD`, which `fromEnv()` and the `notefeed` command both read (there is deliberately no flag, so it stays out of shell history). It is sent as `X-Feed-Password`; `Authorization` stays the instance password. A feed password is 1 to 256 printable ASCII characters with no space at the start or end; an empty one is the same as none.
|
|
29
|
+
|
|
30
|
+
A posted note can be changed or removed: `await client.edit(id, markdown)` replaces its text and returns the note (its id and URLs stay), and `await client.delete(id)` removes it. Both take the same `{ feed, feedPassword }` options as `post`, and a missing note is a `NotFoundError`. `notefeed edit <id> <text | - | --file PATH>` prints the note URL; `notefeed delete <id>` prints nothing. Anyone who can post to a feed can edit and delete its notes, and deleting is permanent.
|
|
31
|
+
|
|
32
|
+
A feed can have a title and a description, and can be deleted: `await client.feedInfo()` returns `{ name, title, description, protected, read_url }`, `await client.updateFeed({ title, description })` replaces both (an empty string clears one) and returns the feed, and `await client.deleteFeed()` removes the feed with all its notes for good. All three take the same `{ feed, feedPassword }` options as `post`, and a feed that doesn't exist is a `NotFoundError`. Anyone who can post to a feed can do this, and deleting is permanent; there are no `notefeed` commands for it.
|
|
33
|
+
|
|
34
|
+
An image can be uploaded to an existing feed and then used in a note: `const { file, url, markdown } = await client.uploadImage(bytes)` takes a `Uint8Array` or a `Blob` (PNG, JPEG, GIF or WebP; the server recognizes the format by the bytes), takes the same `{ feed, feedPassword }` options as `post`, and returns the image's `url` and `markdown` (``), which you put in a note. The feed must already have a note, and an image that is too large is a `NoteTooLargeError`. `await client.updateFeed({ title, description, image: file })` makes an uploaded image the feed's title image (`image: ""` removes it; leaving `image` out keeps it). `notefeed image <PATH>` uploads a file and prints the markdown. Images are public to anyone with the feed's read link, and metadata such as EXIF is not removed.
|
|
35
|
+
|
|
24
36
|
Full documentation: https://docs.notefeed.me/clients/
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** `notefeed post
|
|
1
|
+
/** `notefeed post`, `edit`, `delete`, `notes` and `image`: post, change, remove and read notes, and upload images, from the command line. */
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
@@ -6,8 +6,11 @@ import { Client, ConfigError, NotefeedError } from "./client.js";
|
|
|
6
6
|
class UsageError extends Error {
|
|
7
7
|
}
|
|
8
8
|
const USAGE = [
|
|
9
|
-
"usage: notefeed post <text | - | --file PATH> [--url URL] [--feed FEED] [--password PASSWORD]",
|
|
10
|
-
" notefeed
|
|
9
|
+
"usage: notefeed post <text | - | --file PATH> [--tag TAG]... [--url URL] [--feed FEED] [--password PASSWORD]",
|
|
10
|
+
" notefeed edit <id> <text | - | --file PATH> [--url URL] [--feed FEED] [--password PASSWORD]",
|
|
11
|
+
" notefeed delete <id> [--url URL] [--feed FEED] [--password PASSWORD]",
|
|
12
|
+
" notefeed image <PATH> [--url URL] [--feed FEED] [--password PASSWORD]",
|
|
13
|
+
" notefeed notes [--limit N] [--tag TAG] [--json] [--url URL] [--feed FEED] [--password PASSWORD]",
|
|
11
14
|
].join("\n");
|
|
12
15
|
/** Returns the exit code: 0 ok, 1 server/network error, 2 usage/config error. */
|
|
13
16
|
export async function main(argv, io = process) {
|
|
@@ -20,6 +23,7 @@ export async function main(argv, io = process) {
|
|
|
20
23
|
feed: { type: "string" },
|
|
21
24
|
password: { type: "string" },
|
|
22
25
|
file: { type: "string" },
|
|
26
|
+
tag: { type: "string", multiple: true },
|
|
23
27
|
limit: { type: "string" },
|
|
24
28
|
json: { type: "boolean" },
|
|
25
29
|
version: { type: "boolean" },
|
|
@@ -38,16 +42,36 @@ export async function main(argv, io = process) {
|
|
|
38
42
|
const [command, text, ...rest] = positionals;
|
|
39
43
|
if (command === "post" && !rest.length) {
|
|
40
44
|
const markdown = await read(text, values.file, io);
|
|
41
|
-
const note = await client(values).post(markdown);
|
|
45
|
+
const note = await client(values).post(markdown, { tags: values.tag });
|
|
42
46
|
io.stdout.write(`${note.url}\n`);
|
|
43
47
|
return 0;
|
|
44
48
|
}
|
|
49
|
+
if (command === "edit" && text !== undefined && rest.length <= 1) {
|
|
50
|
+
const note = await client(values).edit(text, await read(rest[0], values.file, io));
|
|
51
|
+
io.stdout.write(`${note.url}\n`);
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
if (command === "delete" && text !== undefined && !rest.length) {
|
|
55
|
+
await client(values).delete(text);
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
if (command === "image" && text !== undefined && !rest.length) {
|
|
59
|
+
let bytes;
|
|
60
|
+
try {
|
|
61
|
+
bytes = await readFile(text);
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
throw new UsageError(`cannot read ${text}: ${e.code ?? e.message}`);
|
|
65
|
+
}
|
|
66
|
+
io.stdout.write(`${(await client(values).uploadImage(bytes)).markdown}\n`);
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
45
69
|
if (command === "notes" && text === undefined) {
|
|
46
70
|
const limit = Number(values.limit ?? 20);
|
|
47
71
|
if (!Number.isInteger(limit) || limit < 1)
|
|
48
72
|
throw new UsageError("--limit must be a whole number, 1 or more");
|
|
49
73
|
let left = limit;
|
|
50
|
-
for await (const n of client(values).notes({ pageSize: Math.min(limit, 100) })) {
|
|
74
|
+
for await (const n of client(values).notes({ pageSize: Math.min(limit, 100), tag: values.tag?.[0] })) {
|
|
51
75
|
// To the second, UTC: the same form as the Python CLI, so scripts read either the same way.
|
|
52
76
|
const when = new Date(n.created_at).toISOString().replace(/\.\d+Z$/, "Z");
|
|
53
77
|
// --json: exactly the documented fields, like the Python CLI, even if the server adds more.
|
|
@@ -69,7 +93,7 @@ export async function main(argv, io = process) {
|
|
|
69
93
|
return 2; // parseArgs rejects unknown options with a TypeError
|
|
70
94
|
}
|
|
71
95
|
}
|
|
72
|
-
// Flags win over NOTEFEED_URL, NOTEFEED_FEED and NOTEFEED_PASSWORD.
|
|
96
|
+
// Flags win over NOTEFEED_URL, NOTEFEED_FEED and NOTEFEED_PASSWORD. NOTEFEED_FEED_PASSWORD has no flag: it would end up in shell history.
|
|
73
97
|
function client(values) {
|
|
74
98
|
const url = values.url || process.env.NOTEFEED_URL;
|
|
75
99
|
const feed = values.feed || process.env.NOTEFEED_FEED;
|
|
@@ -77,7 +101,12 @@ function client(values) {
|
|
|
77
101
|
throw new UsageError("no URL given; pass --url or set NOTEFEED_URL");
|
|
78
102
|
if (!feed)
|
|
79
103
|
throw new UsageError("no feed given; pass --feed or set NOTEFEED_FEED");
|
|
80
|
-
return new Client({
|
|
104
|
+
return new Client({
|
|
105
|
+
url,
|
|
106
|
+
feed,
|
|
107
|
+
password: values.password || process.env.NOTEFEED_PASSWORD,
|
|
108
|
+
feedPassword: process.env.NOTEFEED_FEED_PASSWORD,
|
|
109
|
+
});
|
|
81
110
|
}
|
|
82
111
|
async function read(text, file, io) {
|
|
83
112
|
if (file) {
|
package/dist/client.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type { Created, Error as ApiError, Note } from "./generated/types.gen.js";
|
|
1
|
+
import type { Created, Error as ApiError, Feed, FeedSettings, ImageUploaded, Note } from "./generated/types.gen.js";
|
|
2
2
|
/** The stable error codes the API answers with. */
|
|
3
3
|
export type ErrorCode = NonNullable<ApiError["code"]>;
|
|
4
|
-
export type { Created, Note };
|
|
4
|
+
export type { Created, Feed, FeedSettings, ImageUploaded, Note };
|
|
5
5
|
/** `timeoutMs` (default 10000) limits each whole request, including reading the answer. */
|
|
6
6
|
export type ClientOptions = {
|
|
7
7
|
url: string;
|
|
8
8
|
feed?: string;
|
|
9
9
|
password?: string;
|
|
10
|
+
feedPassword?: string;
|
|
10
11
|
timeoutMs?: number;
|
|
11
12
|
};
|
|
12
13
|
/** Any failure talking to notefeed. `status` and `code` are null when there was no API answer. */
|
|
@@ -29,10 +30,10 @@ export declare class RateLimitedError extends NotefeedError {
|
|
|
29
30
|
/** No such note, or a malformed read id. */
|
|
30
31
|
export declare class NotFoundError extends NotefeedError {
|
|
31
32
|
}
|
|
32
|
-
/** The instance's feed or note limit is reached. */
|
|
33
|
+
/** The instance's feed or note limit, or the feed's image limit, is reached. */
|
|
33
34
|
export declare class LimitReachedError extends NotefeedError {
|
|
34
35
|
}
|
|
35
|
-
/** The note is over the server's size limit. */
|
|
36
|
+
/** The note or image is over the server's size limit. */
|
|
36
37
|
export declare class NoteTooLargeError extends NotefeedError {
|
|
37
38
|
}
|
|
38
39
|
/** The server refused the request itself: invalid or reserved feed, empty note, bad body or parameter. */
|
|
@@ -43,24 +44,62 @@ export declare class Client {
|
|
|
43
44
|
readonly feed: string | null;
|
|
44
45
|
private readonly api;
|
|
45
46
|
private readonly timeoutMs;
|
|
47
|
+
private readonly feedPassword;
|
|
46
48
|
/** A notefeed server. The feed set here is the default for every call; each call can override it. */
|
|
47
49
|
constructor(options: ClientOptions);
|
|
48
|
-
/** NOTEFEED_URL, NOTEFEED_FEED and
|
|
50
|
+
/** NOTEFEED_URL, NOTEFEED_FEED, NOTEFEED_PASSWORD and NOTEFEED_FEED_PASSWORD. */
|
|
49
51
|
static fromEnv(env?: Record<string, string | undefined>): Client;
|
|
52
|
+
/** `feedPassword` overrides the client's, for a feed that has its own password. `tags` label the note (at most 10, each 1 to 32 characters of letters, digits, `-`, `_`, `.`, `:`; not verified). */
|
|
50
53
|
post(markdown: string, options?: {
|
|
51
54
|
feed?: string;
|
|
55
|
+
feedPassword?: string;
|
|
56
|
+
tags?: string[];
|
|
52
57
|
}): Promise<Created>;
|
|
53
|
-
/**
|
|
58
|
+
/** Upload a PNG, JPEG, GIF or WebP image to an existing feed. The server decides the format by the bytes, so no content type is needed. `markdown` in the answer is ``, to put in a note. Same options as post(). */
|
|
59
|
+
uploadImage(data: Uint8Array | Blob, options?: {
|
|
60
|
+
feed?: string;
|
|
61
|
+
feedPassword?: string;
|
|
62
|
+
}): Promise<ImageUploaded>;
|
|
63
|
+
/** Replace a note's markdown; its id and URLs stay. Same options as post(). */
|
|
64
|
+
edit(id: string, markdown: string, options?: {
|
|
65
|
+
feed?: string;
|
|
66
|
+
feedPassword?: string;
|
|
67
|
+
}): Promise<Note>;
|
|
68
|
+
/** Remove a note for good. The feed stays, even with no notes left. Same options as post(). */
|
|
69
|
+
delete(id: string, options?: {
|
|
70
|
+
feed?: string;
|
|
71
|
+
feedPassword?: string;
|
|
72
|
+
}): Promise<void>;
|
|
73
|
+
/** The feed's name, title, description, whether it has a password, and its read link (null while it has no notes). Same options as post(). */
|
|
74
|
+
feedInfo(options?: {
|
|
75
|
+
feed?: string;
|
|
76
|
+
feedPassword?: string;
|
|
77
|
+
}): Promise<Feed>;
|
|
78
|
+
/** Replace the feed's title and description (both; an empty string clears one), and set (`image`: a file name from uploadImage) or clear (`""`) the title image; leave `image` out to keep it. The feed must already exist. Same options as post(). */
|
|
79
|
+
updateFeed(settings: FeedSettings, options?: {
|
|
80
|
+
feed?: string;
|
|
81
|
+
feedPassword?: string;
|
|
82
|
+
}): Promise<Feed>;
|
|
83
|
+
/** Delete the feed with all its notes, settings and password, for good; its name is free again. Same options as post(). */
|
|
84
|
+
deleteFeed(options?: {
|
|
85
|
+
feed?: string;
|
|
86
|
+
feedPassword?: string;
|
|
87
|
+
}): Promise<void>;
|
|
88
|
+
/** Every note in the feed, newest first, fetched a page at a time; stop iterating whenever you like. `tag`: only notes carrying it. */
|
|
54
89
|
notes(options?: {
|
|
55
90
|
feed?: string;
|
|
91
|
+
feedPassword?: string;
|
|
56
92
|
pageSize?: number;
|
|
93
|
+
tag?: string;
|
|
57
94
|
}): AsyncGenerator<Note>;
|
|
58
95
|
note(id: string, options?: {
|
|
59
96
|
feed?: string;
|
|
97
|
+
feedPassword?: string;
|
|
60
98
|
}): Promise<Note>;
|
|
61
99
|
/** Like notes(), by the feed's read id: public, read-only, needs no password. */
|
|
62
100
|
readNotes(readId: string, options?: {
|
|
63
101
|
pageSize?: number;
|
|
102
|
+
tag?: string;
|
|
64
103
|
}): AsyncGenerator<Note>;
|
|
65
104
|
readNote(readId: string, id: string): Promise<Note>;
|
|
66
105
|
private feedFor;
|
package/dist/client.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* OpenAPI description (./generated, `npm run generate` in the repo). No runtime dependencies.
|
|
4
4
|
*/
|
|
5
5
|
import { createClient, createConfig } from "./generated/client/index.js";
|
|
6
|
-
import { getNote, getReadNote, listNotes, listReadNotes, postNote } from "./generated/sdk.gen.js";
|
|
6
|
+
import { deleteFeed, deleteNote, editNote, getFeed, getNote, getReadNote, listNotes, listReadNotes, postNote, updateFeed, uploadImage } from "./generated/sdk.gen.js";
|
|
7
7
|
/** Any failure talking to notefeed. `status` and `code` are null when there was no API answer. */
|
|
8
8
|
export class NotefeedError extends Error {
|
|
9
9
|
status;
|
|
@@ -32,10 +32,10 @@ export class RateLimitedError extends NotefeedError {
|
|
|
32
32
|
/** No such note, or a malformed read id. */
|
|
33
33
|
export class NotFoundError extends NotefeedError {
|
|
34
34
|
}
|
|
35
|
-
/** The instance's feed or note limit is reached. */
|
|
35
|
+
/** The instance's feed or note limit, or the feed's image limit, is reached. */
|
|
36
36
|
export class LimitReachedError extends NotefeedError {
|
|
37
37
|
}
|
|
38
|
-
/** The note is over the server's size limit. */
|
|
38
|
+
/** The note or image is over the server's size limit. */
|
|
39
39
|
export class NoteTooLargeError extends NotefeedError {
|
|
40
40
|
}
|
|
41
41
|
/** The server refused the request itself: invalid or reserved feed, empty note, bad body or parameter. */
|
|
@@ -46,12 +46,14 @@ const BY_CODE = {
|
|
|
46
46
|
not_found: NotFoundError,
|
|
47
47
|
feed_limit: LimitReachedError,
|
|
48
48
|
note_limit: LimitReachedError,
|
|
49
|
+
image_limit: LimitReachedError,
|
|
49
50
|
too_large: NoteTooLargeError,
|
|
50
51
|
invalid_feed: InvalidRequestError,
|
|
51
52
|
reserved_feed: InvalidRequestError,
|
|
52
53
|
empty_note: InvalidRequestError,
|
|
53
54
|
invalid_body: InvalidRequestError,
|
|
54
55
|
invalid_request: InvalidRequestError,
|
|
56
|
+
feed_exists: InvalidRequestError,
|
|
55
57
|
unsupported_type: InvalidRequestError,
|
|
56
58
|
};
|
|
57
59
|
const FEED_RE = /^[a-z0-9_-]{1,64}$/; // same rule as the server; reserved names still come back as a 400
|
|
@@ -60,9 +62,10 @@ export class Client {
|
|
|
60
62
|
feed;
|
|
61
63
|
api;
|
|
62
64
|
timeoutMs;
|
|
65
|
+
feedPassword;
|
|
63
66
|
/** A notefeed server. The feed set here is the default for every call; each call can override it. */
|
|
64
67
|
constructor(options) {
|
|
65
|
-
const { url, feed, password, timeoutMs } = options ?? {};
|
|
68
|
+
const { url, feed, password, feedPassword, timeoutMs } = options ?? {};
|
|
66
69
|
if (!url)
|
|
67
70
|
throw new ConfigError("no url given");
|
|
68
71
|
this.url = url.replace(/\/+$/, "");
|
|
@@ -71,29 +74,70 @@ export class Client {
|
|
|
71
74
|
// Never echo the value: it would end up in terminals and CI logs.
|
|
72
75
|
if (pw && /[\x00-\x1f\x7f]/.test(pw))
|
|
73
76
|
throw new ConfigError("password contains invalid characters");
|
|
77
|
+
this.feedPassword = checkFeedPassword(feedPassword);
|
|
74
78
|
this.timeoutMs = timeoutMs ?? 10_000;
|
|
75
79
|
this.api = createClient(createConfig({ baseUrl: this.url, headers: pw ? { Authorization: `Bearer ${pw}` } : {} }));
|
|
76
80
|
}
|
|
77
|
-
/** NOTEFEED_URL, NOTEFEED_FEED and
|
|
81
|
+
/** NOTEFEED_URL, NOTEFEED_FEED, NOTEFEED_PASSWORD and NOTEFEED_FEED_PASSWORD. */
|
|
78
82
|
static fromEnv(env = process.env) {
|
|
79
|
-
return new Client({
|
|
83
|
+
return new Client({
|
|
84
|
+
url: env.NOTEFEED_URL ?? "",
|
|
85
|
+
feed: env.NOTEFEED_FEED || undefined,
|
|
86
|
+
password: env.NOTEFEED_PASSWORD,
|
|
87
|
+
feedPassword: env.NOTEFEED_FEED_PASSWORD,
|
|
88
|
+
});
|
|
80
89
|
}
|
|
90
|
+
/** `feedPassword` overrides the client's, for a feed that has its own password. `tags` label the note (at most 10, each 1 to 32 characters of letters, digits, `-`, `_`, `.`, `:`; not verified). */
|
|
81
91
|
async post(markdown, options = {}) {
|
|
82
92
|
const feed = this.feedFor(options.feed);
|
|
83
|
-
|
|
93
|
+
const body = { markdown, ...(options.tags?.length && { tags: options.tags }) };
|
|
94
|
+
return this.call(postNote({ client: this.api, path: { feed }, body, ...this.opts(options.feedPassword) }));
|
|
84
95
|
}
|
|
85
|
-
/**
|
|
96
|
+
/** Upload a PNG, JPEG, GIF or WebP image to an existing feed. The server decides the format by the bytes, so no content type is needed. `markdown` in the answer is ``, to put in a note. Same options as post(). */
|
|
97
|
+
async uploadImage(data, options = {}) {
|
|
98
|
+
const feed = this.feedFor(options.feed);
|
|
99
|
+
const body = data instanceof Blob ? data : new Blob([data]);
|
|
100
|
+
const headers = { ...this.opts(options.feedPassword).headers, "Content-Type": "application/octet-stream" };
|
|
101
|
+
return this.call(uploadImage({ client: this.api, path: { feed }, body, signal: AbortSignal.timeout(this.timeoutMs), headers }));
|
|
102
|
+
}
|
|
103
|
+
/** Replace a note's markdown; its id and URLs stay. Same options as post(). */
|
|
104
|
+
async edit(id, markdown, options = {}) {
|
|
105
|
+
const feed = this.feedFor(options.feed);
|
|
106
|
+
return this.call(editNote({ client: this.api, path: { feed, id }, body: { markdown }, ...this.opts(options.feedPassword) }));
|
|
107
|
+
}
|
|
108
|
+
/** Remove a note for good. The feed stays, even with no notes left. Same options as post(). */
|
|
109
|
+
async delete(id, options = {}) {
|
|
110
|
+
const feed = this.feedFor(options.feed);
|
|
111
|
+
await this.call(deleteNote({ client: this.api, path: { feed, id }, ...this.opts(options.feedPassword) }));
|
|
112
|
+
}
|
|
113
|
+
/** The feed's name, title, description, whether it has a password, and its read link (null while it has no notes). Same options as post(). */
|
|
114
|
+
async feedInfo(options = {}) {
|
|
115
|
+
const feed = this.feedFor(options.feed);
|
|
116
|
+
return this.call(getFeed({ client: this.api, path: { feed }, ...this.opts(options.feedPassword) }));
|
|
117
|
+
}
|
|
118
|
+
/** Replace the feed's title and description (both; an empty string clears one), and set (`image`: a file name from uploadImage) or clear (`""`) the title image; leave `image` out to keep it. The feed must already exist. Same options as post(). */
|
|
119
|
+
async updateFeed(settings, options = {}) {
|
|
120
|
+
const feed = this.feedFor(options.feed);
|
|
121
|
+
const body = { title: settings.title, description: settings.description, ...(settings.image === undefined ? {} : { image: settings.image }) };
|
|
122
|
+
return this.call(updateFeed({ client: this.api, path: { feed }, body, ...this.opts(options.feedPassword) }));
|
|
123
|
+
}
|
|
124
|
+
/** Delete the feed with all its notes, settings and password, for good; its name is free again. Same options as post(). */
|
|
125
|
+
async deleteFeed(options = {}) {
|
|
126
|
+
const feed = this.feedFor(options.feed);
|
|
127
|
+
await this.call(deleteFeed({ client: this.api, path: { feed }, ...this.opts(options.feedPassword) }));
|
|
128
|
+
}
|
|
129
|
+
/** Every note in the feed, newest first, fetched a page at a time; stop iterating whenever you like. `tag`: only notes carrying it. */
|
|
86
130
|
notes(options = {}) {
|
|
87
131
|
const feed = this.feedFor(options.feed);
|
|
88
|
-
return this.pages((before) => listNotes({ client: this.api, path: { feed }, query: { limit: options.pageSize, before }, ...this.opts() }));
|
|
132
|
+
return this.pages((before) => listNotes({ client: this.api, path: { feed }, query: { limit: options.pageSize, before, tag: options.tag }, ...this.opts(options.feedPassword) }));
|
|
89
133
|
}
|
|
90
134
|
async note(id, options = {}) {
|
|
91
135
|
const feed = this.feedFor(options.feed);
|
|
92
|
-
return this.call(getNote({ client: this.api, path: { feed, id }, ...this.opts() }));
|
|
136
|
+
return this.call(getNote({ client: this.api, path: { feed, id }, ...this.opts(options.feedPassword) }));
|
|
93
137
|
}
|
|
94
138
|
/** Like notes(), by the feed's read id: public, read-only, needs no password. */
|
|
95
139
|
readNotes(readId, options = {}) {
|
|
96
|
-
return this.pages((before) => listReadNotes({ client: this.api, path: { readId }, query: { limit: options.pageSize, before }, ...this.opts() }));
|
|
140
|
+
return this.pages((before) => listReadNotes({ client: this.api, path: { readId }, query: { limit: options.pageSize, before, tag: options.tag }, ...this.opts() }));
|
|
97
141
|
}
|
|
98
142
|
async readNote(readId, id) {
|
|
99
143
|
return this.call(getReadNote({ client: this.api, path: { readId, id }, ...this.opts() }));
|
|
@@ -104,8 +148,9 @@ export class Client {
|
|
|
104
148
|
throw new ConfigError("no feed given");
|
|
105
149
|
return checkFeed(f);
|
|
106
150
|
}
|
|
107
|
-
opts() {
|
|
108
|
-
|
|
151
|
+
opts(feedPassword) {
|
|
152
|
+
const fp = checkFeedPassword(feedPassword) ?? this.feedPassword;
|
|
153
|
+
return { signal: AbortSignal.timeout(this.timeoutMs), headers: fp ? { "X-Feed-Password": fp } : {} };
|
|
109
154
|
}
|
|
110
155
|
// `before` is the previous page's `next`: older notes only, so notes posted meanwhile never repeat.
|
|
111
156
|
async *pages(fetchPage) {
|
|
@@ -128,6 +173,8 @@ export class Client {
|
|
|
128
173
|
if (response.redirected) {
|
|
129
174
|
throw new NotefeedError(`${this.url} redirected to ${new URL(response.url).origin}: use that address as the URL`, response.status);
|
|
130
175
|
}
|
|
176
|
+
if (response.status === 204 && error === undefined)
|
|
177
|
+
return undefined; // delete: no body
|
|
131
178
|
if (response.ok) {
|
|
132
179
|
if (error === undefined && isObject(data))
|
|
133
180
|
return data;
|
|
@@ -155,3 +202,10 @@ function checkFeed(feed) {
|
|
|
155
202
|
throw new ConfigError("invalid feed name: use 1-64 of a-z, 0-9, _ and -");
|
|
156
203
|
return feed;
|
|
157
204
|
}
|
|
205
|
+
function checkFeedPassword(value) {
|
|
206
|
+
const v = value?.trim() || null;
|
|
207
|
+
// Never echo the value: it would end up in terminals and CI logs.
|
|
208
|
+
if (v && /[\x00-\x1f\x7f]/.test(v))
|
|
209
|
+
throw new ConfigError("feed password contains invalid characters");
|
|
210
|
+
return v;
|
|
211
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { getNote, getOpenApi, getReadNote, listNotes, listReadNotes, type Options, postNote } from './sdk.gen.js';
|
|
2
|
-
export type { ClientOptions, Created, Error, GetNoteData, GetNoteError, GetNoteErrors, GetNoteResponse, GetNoteResponses, GetOpenApiData, GetOpenApiResponse, GetOpenApiResponses, GetReadNoteData, GetReadNoteError, GetReadNoteErrors, GetReadNoteResponse, GetReadNoteResponses, ListNotesData, ListNotesError, ListNotesErrors, ListNotesResponse, ListNotesResponses, ListReadNotesData, ListReadNotesError, ListReadNotesErrors, ListReadNotesResponse, ListReadNotesResponses, Note, NoteList, PostForm, PostJson, PostNoteData, PostNoteError, PostNoteErrors, PostNoteResponse, PostNoteResponses } from './types.gen.js';
|
|
1
|
+
export { changeFeedPassword, deleteFeed, deleteNote, editNote, getFeed, getNote, getOpenApi, getReadFeed, getReadNote, listNotes, listReadNotes, type Options, postNote, removeFeedPassword, updateFeed, uploadImage } from './sdk.gen.js';
|
|
2
|
+
export type { ChangeFeedPasswordData, ChangeFeedPasswordError, ChangeFeedPasswordErrors, ChangeFeedPasswordResponse, ChangeFeedPasswordResponses, ClientOptions, Created, DeleteFeedData, DeleteFeedError, DeleteFeedErrors, DeleteFeedResponse, DeleteFeedResponses, DeleteNoteData, DeleteNoteError, DeleteNoteErrors, DeleteNoteResponse, DeleteNoteResponses, EditNoteData, EditNoteError, EditNoteErrors, EditNoteResponse, EditNoteResponses, Error, Feed, FeedSettings, GetFeedData, GetFeedError, GetFeedErrors, GetFeedResponse, GetFeedResponses, GetNoteData, GetNoteError, GetNoteErrors, GetNoteResponse, GetNoteResponses, GetOpenApiData, GetOpenApiResponse, GetOpenApiResponses, GetReadFeedData, GetReadFeedError, GetReadFeedErrors, GetReadFeedResponse, GetReadFeedResponses, GetReadNoteData, GetReadNoteError, GetReadNoteErrors, GetReadNoteResponse, GetReadNoteResponses, ImageUploaded, ListNotesData, ListNotesError, ListNotesErrors, ListNotesResponse, ListNotesResponses, ListReadNotesData, ListReadNotesError, ListReadNotesErrors, ListReadNotesResponse, ListReadNotesResponses, Note, NoteList, PasswordJson, PostForm, PostJson, PostNoteData, PostNoteError, PostNoteErrors, PostNoteResponse, PostNoteResponses, ReadFeed, RemoveFeedPasswordData, RemoveFeedPasswordError, RemoveFeedPasswordErrors, RemoveFeedPasswordResponse, RemoveFeedPasswordResponses, UpdateFeedData, UpdateFeedError, UpdateFeedErrors, UpdateFeedResponse, UpdateFeedResponses, UploadImageData, UploadImageError, UploadImageErrors, UploadImageResponse, UploadImageResponses } from './types.gen.js';
|
package/dist/generated/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is auto-generated by @hey-api/openapi-ts
|
|
2
|
-
export { getNote, getOpenApi, getReadNote, listNotes, listReadNotes, postNote } from './sdk.gen.js';
|
|
2
|
+
export { changeFeedPassword, deleteFeed, deleteNote, editNote, getFeed, getNote, getOpenApi, getReadFeed, getReadNote, listNotes, listReadNotes, postNote, removeFeedPassword, updateFeed, uploadImage } from './sdk.gen.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Client, ClientMeta, Options as Options2, RequestResult, TDataShape } from './client/index.js';
|
|
2
|
-
import type { GetNoteData, GetNoteErrors, GetNoteResponses, GetOpenApiData, GetOpenApiResponses, GetReadNoteData, GetReadNoteErrors, GetReadNoteResponses, ListNotesData, ListNotesErrors, ListNotesResponses, ListReadNotesData, ListReadNotesErrors, ListReadNotesResponses, PostNoteData, PostNoteErrors, PostNoteResponses } from './types.gen.js';
|
|
2
|
+
import type { ChangeFeedPasswordData, ChangeFeedPasswordErrors, ChangeFeedPasswordResponses, DeleteFeedData, DeleteFeedErrors, DeleteFeedResponses, DeleteNoteData, DeleteNoteErrors, DeleteNoteResponses, EditNoteData, EditNoteErrors, EditNoteResponses, GetFeedData, GetFeedErrors, GetFeedResponses, GetNoteData, GetNoteErrors, GetNoteResponses, GetOpenApiData, GetOpenApiResponses, GetReadFeedData, GetReadFeedErrors, GetReadFeedResponses, GetReadNoteData, GetReadNoteErrors, GetReadNoteResponses, ListNotesData, ListNotesErrors, ListNotesResponses, ListReadNotesData, ListReadNotesErrors, ListReadNotesResponses, PostNoteData, PostNoteErrors, PostNoteResponses, RemoveFeedPasswordData, RemoveFeedPasswordErrors, RemoveFeedPasswordResponses, UpdateFeedData, UpdateFeedErrors, UpdateFeedResponses, UploadImageData, UploadImageErrors, UploadImageResponses } from './types.gen.js';
|
|
3
3
|
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown> = Options2<TData, ThrowOnError, TResponse> & {
|
|
4
4
|
/**
|
|
5
5
|
* You can provide a client instance returned by `createClient()` instead of
|
|
@@ -22,13 +22,67 @@ export declare const listNotes: <ThrowOnError extends boolean = false>(options:
|
|
|
22
22
|
/**
|
|
23
23
|
* Post a note
|
|
24
24
|
*
|
|
25
|
-
* Creates the feed with its first note. Also served at `POST /{feed}`, the short form the client packages and curl one-liners use. The body is at most 102400 bytes and must be UTF-8. `application/x-www-form-urlencoded` (what `curl -d` sends) is read as raw markdown, not as form fields.
|
|
25
|
+
* Creates the feed with its first note, optionally protected by its own password (`X-Feed-Password` header or a `password` field in the JSON or form body; 1 to 256 printable ASCII characters, with no space at the start or end). Posting to a protected feed needs that password. Also served at `POST /{feed}`, the short form the client packages and curl one-liners use. The body is at most 102400 bytes and must be UTF-8. `application/x-www-form-urlencoded` (what `curl -d` sends) is read as raw markdown, not as form fields. Tags (at most 10 tags, each 1 to 32 characters of letters, digits, `-`, `_`, `.` and `:`; case is folded to lowercase, duplicates are removed) go in the JSON `tags` array, a repeated `tags` form field, or, for a raw body, the `X-Note-Tags` header.
|
|
26
26
|
*/
|
|
27
27
|
export declare const postNote: <ThrowOnError extends boolean = false>(options: Options<PostNoteData, ThrowOnError>) => RequestResult<PostNoteResponses, PostNoteErrors, ThrowOnError>;
|
|
28
|
+
/**
|
|
29
|
+
* Delete a note
|
|
30
|
+
*
|
|
31
|
+
* Needs the feed's password if it has one, and counts against the post rate limit. The feed stays, even with no notes left. Read links can't delete.
|
|
32
|
+
*/
|
|
33
|
+
export declare const deleteNote: <ThrowOnError extends boolean = false>(options: Options<DeleteNoteData, ThrowOnError>) => RequestResult<DeleteNoteResponses, DeleteNoteErrors, ThrowOnError>;
|
|
28
34
|
/**
|
|
29
35
|
* Get one note
|
|
30
36
|
*/
|
|
31
37
|
export declare const getNote: <ThrowOnError extends boolean = false>(options: Options<GetNoteData, ThrowOnError>) => RequestResult<GetNoteResponses, GetNoteErrors, ThrowOnError>;
|
|
38
|
+
/**
|
|
39
|
+
* Edit a note
|
|
40
|
+
*
|
|
41
|
+
* Replaces the note's markdown; its id and creation time stay, the title follows the new text. Needs the feed's password if it has one, and counts against the post rate limit. Read links can't edit. The body is as for posting: at most 102400 bytes, UTF-8, a `password` field is ignored.
|
|
42
|
+
*/
|
|
43
|
+
export declare const editNote: <ThrowOnError extends boolean = false>(options: Options<EditNoteData, ThrowOnError>) => RequestResult<EditNoteResponses, EditNoteErrors, ThrowOnError>;
|
|
44
|
+
/**
|
|
45
|
+
* Upload an image
|
|
46
|
+
*
|
|
47
|
+
* The body is the image itself: PNG, JPEG, GIF or WebP, recognized by its first bytes, whatever `Content-Type` is sent (SVG is refused). Stored byte-for-byte, with no resizing and no metadata stripped (EXIF such as GPS position stays in the file), as the first 32 hex characters of its SHA-256 plus an extension: the same bytes always give the same URL. The URL is under the feed's read id, so it works in the feed page, the read-only view and RSS readers without any password. Needs the same credentials as posting and counts against the post rate limit. The feed must exist: it is created by its first note. The size limit is NOTEFEED_MAX_IMAGE_BYTES (default 5 MiB); images deleted only with the feed.
|
|
48
|
+
*/
|
|
49
|
+
export declare const uploadImage: <ThrowOnError extends boolean = false>(options: Options<UploadImageData, ThrowOnError>) => RequestResult<UploadImageResponses, UploadImageErrors, ThrowOnError>;
|
|
50
|
+
/**
|
|
51
|
+
* Delete a feed
|
|
52
|
+
*
|
|
53
|
+
* Deletes the feed with all its notes, its settings, its password and its read link, for good: there is no undo. The name is free again; a feed created there later gets a new read link, and the old one answers like an unknown one. Needs the feed's password if it has one, and counts against the post rate limit.
|
|
54
|
+
*/
|
|
55
|
+
export declare const deleteFeed: <ThrowOnError extends boolean = false>(options: Options<DeleteFeedData, ThrowOnError>) => RequestResult<DeleteFeedResponses, DeleteFeedErrors, ThrowOnError>;
|
|
56
|
+
/**
|
|
57
|
+
* Get a feed's settings
|
|
58
|
+
*
|
|
59
|
+
* The title and description, the title image, whether the feed is protected, and its read link (null while it has no notes). A feed exists once its first note is posted.
|
|
60
|
+
*/
|
|
61
|
+
export declare const getFeed: <ThrowOnError extends boolean = false>(options: Options<GetFeedData, ThrowOnError>) => RequestResult<GetFeedResponses, GetFeedErrors, ThrowOnError>;
|
|
62
|
+
/**
|
|
63
|
+
* Change a feed's settings
|
|
64
|
+
*
|
|
65
|
+
* Replaces both the title (at most 100 characters) and the description (at most 500); surrounding whitespace is trimmed and control characters are refused. `show_sender` (default true) shows who posted each note to readers; omitted leaves it as it is. `image` is the file name `uploadImage` returned for this feed (title image), empty to remove it, or omitted to leave it as it is; any other value is a 400. Needs the feed's password if it has one, and counts against the post rate limit. Only on a feed that exists: it is created by its first note. Read links can't change settings.
|
|
66
|
+
*/
|
|
67
|
+
export declare const updateFeed: <ThrowOnError extends boolean = false>(options: Options<UpdateFeedData, ThrowOnError>) => RequestResult<UpdateFeedResponses, UpdateFeedErrors, ThrowOnError>;
|
|
68
|
+
/**
|
|
69
|
+
* Remove a feed's password
|
|
70
|
+
*
|
|
71
|
+
* Needs the current password in `X-Feed-Password`. The feed stays, open to anyone who knows its name. An open feed answers 409.
|
|
72
|
+
*/
|
|
73
|
+
export declare const removeFeedPassword: <ThrowOnError extends boolean = false>(options: Options<RemoveFeedPasswordData, ThrowOnError>) => RequestResult<RemoveFeedPasswordResponses, RemoveFeedPasswordErrors, ThrowOnError>;
|
|
74
|
+
/**
|
|
75
|
+
* Change a feed's password
|
|
76
|
+
*
|
|
77
|
+
* Needs the current password in `X-Feed-Password`. A feed can only get a password when it is created, so an open feed answers 409.
|
|
78
|
+
*/
|
|
79
|
+
export declare const changeFeedPassword: <ThrowOnError extends boolean = false>(options: Options<ChangeFeedPasswordData, ThrowOnError>) => RequestResult<ChangeFeedPasswordResponses, ChangeFeedPasswordErrors, ThrowOnError>;
|
|
80
|
+
/**
|
|
81
|
+
* Get a feed's title and description by its read id
|
|
82
|
+
*
|
|
83
|
+
* Public, even on an instance with a password, and never reveals the feed's name. An unknown read id has an empty title and description, so read ids can't be probed.
|
|
84
|
+
*/
|
|
85
|
+
export declare const getReadFeed: <ThrowOnError extends boolean = false>(options: Options<GetReadFeedData, ThrowOnError>) => RequestResult<GetReadFeedResponses, GetReadFeedErrors, ThrowOnError>;
|
|
32
86
|
/**
|
|
33
87
|
* List a feed's notes by its read id
|
|
34
88
|
*
|
|
@@ -13,7 +13,7 @@ export const listNotes = (options) => (options.client ?? client).get({
|
|
|
13
13
|
/**
|
|
14
14
|
* Post a note
|
|
15
15
|
*
|
|
16
|
-
* Creates the feed with its first note. Also served at `POST /{feed}`, the short form the client packages and curl one-liners use. The body is at most 102400 bytes and must be UTF-8. `application/x-www-form-urlencoded` (what `curl -d` sends) is read as raw markdown, not as form fields.
|
|
16
|
+
* Creates the feed with its first note, optionally protected by its own password (`X-Feed-Password` header or a `password` field in the JSON or form body; 1 to 256 printable ASCII characters, with no space at the start or end). Posting to a protected feed needs that password. Also served at `POST /{feed}`, the short form the client packages and curl one-liners use. The body is at most 102400 bytes and must be UTF-8. `application/x-www-form-urlencoded` (what `curl -d` sends) is read as raw markdown, not as form fields. Tags (at most 10 tags, each 1 to 32 characters of letters, digits, `-`, `_`, `.` and `:`; case is folded to lowercase, duplicates are removed) go in the JSON `tags` array, a repeated `tags` form field, or, for a raw body, the `X-Note-Tags` header.
|
|
17
17
|
*/
|
|
18
18
|
export const postNote = (options) => (options.client ?? client).post({
|
|
19
19
|
security: [{ scheme: 'bearer', type: 'http' }],
|
|
@@ -24,6 +24,16 @@ export const postNote = (options) => (options.client ?? client).post({
|
|
|
24
24
|
...options.headers
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
|
+
/**
|
|
28
|
+
* Delete a note
|
|
29
|
+
*
|
|
30
|
+
* Needs the feed's password if it has one, and counts against the post rate limit. The feed stays, even with no notes left. Read links can't delete.
|
|
31
|
+
*/
|
|
32
|
+
export const deleteNote = (options) => (options.client ?? client).delete({
|
|
33
|
+
security: [{ scheme: 'bearer', type: 'http' }],
|
|
34
|
+
url: '/api/v1/feeds/{feed}/notes/{id}',
|
|
35
|
+
...options
|
|
36
|
+
});
|
|
27
37
|
/**
|
|
28
38
|
* Get one note
|
|
29
39
|
*/
|
|
@@ -32,6 +42,99 @@ export const getNote = (options) => (options.client ?? client).get({
|
|
|
32
42
|
url: '/api/v1/feeds/{feed}/notes/{id}',
|
|
33
43
|
...options
|
|
34
44
|
});
|
|
45
|
+
/**
|
|
46
|
+
* Edit a note
|
|
47
|
+
*
|
|
48
|
+
* Replaces the note's markdown; its id and creation time stay, the title follows the new text. Needs the feed's password if it has one, and counts against the post rate limit. Read links can't edit. The body is as for posting: at most 102400 bytes, UTF-8, a `password` field is ignored.
|
|
49
|
+
*/
|
|
50
|
+
export const editNote = (options) => (options.client ?? client).put({
|
|
51
|
+
security: [{ scheme: 'bearer', type: 'http' }],
|
|
52
|
+
url: '/api/v1/feeds/{feed}/notes/{id}',
|
|
53
|
+
...options,
|
|
54
|
+
headers: {
|
|
55
|
+
'Content-Type': 'application/json',
|
|
56
|
+
...options.headers
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* Upload an image
|
|
61
|
+
*
|
|
62
|
+
* The body is the image itself: PNG, JPEG, GIF or WebP, recognized by its first bytes, whatever `Content-Type` is sent (SVG is refused). Stored byte-for-byte, with no resizing and no metadata stripped (EXIF such as GPS position stays in the file), as the first 32 hex characters of its SHA-256 plus an extension: the same bytes always give the same URL. The URL is under the feed's read id, so it works in the feed page, the read-only view and RSS readers without any password. Needs the same credentials as posting and counts against the post rate limit. The feed must exist: it is created by its first note. The size limit is NOTEFEED_MAX_IMAGE_BYTES (default 5 MiB); images deleted only with the feed.
|
|
63
|
+
*/
|
|
64
|
+
export const uploadImage = (options) => (options.client ?? client).post({
|
|
65
|
+
bodySerializer: null,
|
|
66
|
+
security: [{ scheme: 'bearer', type: 'http' }],
|
|
67
|
+
url: '/api/v1/feeds/{feed}/images',
|
|
68
|
+
...options,
|
|
69
|
+
headers: {
|
|
70
|
+
'Content-Type': 'image/png',
|
|
71
|
+
...options.headers
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* Delete a feed
|
|
76
|
+
*
|
|
77
|
+
* Deletes the feed with all its notes, its settings, its password and its read link, for good: there is no undo. The name is free again; a feed created there later gets a new read link, and the old one answers like an unknown one. Needs the feed's password if it has one, and counts against the post rate limit.
|
|
78
|
+
*/
|
|
79
|
+
export const deleteFeed = (options) => (options.client ?? client).delete({
|
|
80
|
+
security: [{ scheme: 'bearer', type: 'http' }],
|
|
81
|
+
url: '/api/v1/feeds/{feed}',
|
|
82
|
+
...options
|
|
83
|
+
});
|
|
84
|
+
/**
|
|
85
|
+
* Get a feed's settings
|
|
86
|
+
*
|
|
87
|
+
* The title and description, the title image, whether the feed is protected, and its read link (null while it has no notes). A feed exists once its first note is posted.
|
|
88
|
+
*/
|
|
89
|
+
export const getFeed = (options) => (options.client ?? client).get({
|
|
90
|
+
security: [{ scheme: 'bearer', type: 'http' }],
|
|
91
|
+
url: '/api/v1/feeds/{feed}',
|
|
92
|
+
...options
|
|
93
|
+
});
|
|
94
|
+
/**
|
|
95
|
+
* Change a feed's settings
|
|
96
|
+
*
|
|
97
|
+
* Replaces both the title (at most 100 characters) and the description (at most 500); surrounding whitespace is trimmed and control characters are refused. `show_sender` (default true) shows who posted each note to readers; omitted leaves it as it is. `image` is the file name `uploadImage` returned for this feed (title image), empty to remove it, or omitted to leave it as it is; any other value is a 400. Needs the feed's password if it has one, and counts against the post rate limit. Only on a feed that exists: it is created by its first note. Read links can't change settings.
|
|
98
|
+
*/
|
|
99
|
+
export const updateFeed = (options) => (options.client ?? client).put({
|
|
100
|
+
security: [{ scheme: 'bearer', type: 'http' }],
|
|
101
|
+
url: '/api/v1/feeds/{feed}',
|
|
102
|
+
...options,
|
|
103
|
+
headers: {
|
|
104
|
+
'Content-Type': 'application/json',
|
|
105
|
+
...options.headers
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
/**
|
|
109
|
+
* Remove a feed's password
|
|
110
|
+
*
|
|
111
|
+
* Needs the current password in `X-Feed-Password`. The feed stays, open to anyone who knows its name. An open feed answers 409.
|
|
112
|
+
*/
|
|
113
|
+
export const removeFeedPassword = (options) => (options.client ?? client).delete({
|
|
114
|
+
security: [{ scheme: 'bearer', type: 'http' }],
|
|
115
|
+
url: '/api/v1/feeds/{feed}/password',
|
|
116
|
+
...options
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* Change a feed's password
|
|
120
|
+
*
|
|
121
|
+
* Needs the current password in `X-Feed-Password`. A feed can only get a password when it is created, so an open feed answers 409.
|
|
122
|
+
*/
|
|
123
|
+
export const changeFeedPassword = (options) => (options.client ?? client).put({
|
|
124
|
+
security: [{ scheme: 'bearer', type: 'http' }],
|
|
125
|
+
url: '/api/v1/feeds/{feed}/password',
|
|
126
|
+
...options,
|
|
127
|
+
headers: {
|
|
128
|
+
'Content-Type': 'application/json',
|
|
129
|
+
...options.headers
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
/**
|
|
133
|
+
* Get a feed's title and description by its read id
|
|
134
|
+
*
|
|
135
|
+
* Public, even on an instance with a password, and never reveals the feed's name. An unknown read id has an empty title and description, so read ids can't be probed.
|
|
136
|
+
*/
|
|
137
|
+
export const getReadFeed = (options) => (options.client ?? client).get({ url: '/api/v1/read/{readId}', ...options });
|
|
35
138
|
/**
|
|
36
139
|
* List a feed's notes by its read id
|
|
37
140
|
*
|
|
@@ -22,6 +22,14 @@ export type Note = {
|
|
|
22
22
|
* The note's page in the web UI
|
|
23
23
|
*/
|
|
24
24
|
url: string;
|
|
25
|
+
/**
|
|
26
|
+
* Verified sign-in name of the poster; absent when the note was posted without a sign-in
|
|
27
|
+
*/
|
|
28
|
+
sender?: string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Labels the poster gave the note (not verified, and shown to readers like the note itself); empty when none
|
|
31
|
+
*/
|
|
32
|
+
tags: Array<string>;
|
|
25
33
|
};
|
|
26
34
|
export type NoteList = {
|
|
27
35
|
/**
|
|
@@ -44,9 +52,23 @@ export type Created = {
|
|
|
44
52
|
*/
|
|
45
53
|
feed_url: string;
|
|
46
54
|
/**
|
|
47
|
-
* The feed's read-only RSS link, safe to share
|
|
55
|
+
* The feed's read-only RSS link, safe to share; null only if the server can't read the feed's stored read id, or if that id and the derived one both belong to other feeds
|
|
56
|
+
*/
|
|
57
|
+
read_url: string | null;
|
|
58
|
+
};
|
|
59
|
+
export type ImageUploaded = {
|
|
60
|
+
/**
|
|
61
|
+
* The stored file's name: 32 hex characters of the SHA-256 plus the extension. Pass it as a feed's `image` setting
|
|
62
|
+
*/
|
|
63
|
+
file: string;
|
|
64
|
+
/**
|
|
65
|
+
* Where the image is served, absolute, under the feed's read id; public like the read link
|
|
66
|
+
*/
|
|
67
|
+
url: string;
|
|
68
|
+
/**
|
|
69
|
+
* ``, to paste into a note
|
|
48
70
|
*/
|
|
49
|
-
|
|
71
|
+
markdown: string;
|
|
50
72
|
};
|
|
51
73
|
export type Error = {
|
|
52
74
|
/**
|
|
@@ -56,16 +78,106 @@ export type Error = {
|
|
|
56
78
|
/**
|
|
57
79
|
* Stable machine-readable code; absent only on a 500
|
|
58
80
|
*/
|
|
59
|
-
code?: 'invalid_feed' | 'reserved_feed' | 'auth' | 'rate_limited' | 'too_many_attempts' | 'feed_limit' | 'note_limit' | 'empty_note' | 'too_large' | 'unsupported_type' | 'invalid_body' | 'invalid_request' | 'not_found';
|
|
81
|
+
code?: 'invalid_feed' | 'reserved_feed' | 'auth' | 'rate_limited' | 'too_many_attempts' | 'feed_limit' | 'note_limit' | 'image_limit' | 'empty_note' | 'too_large' | 'unsupported_type' | 'invalid_body' | 'invalid_request' | 'not_found' | 'feed_exists';
|
|
60
82
|
};
|
|
61
83
|
export type PostJson = {
|
|
62
84
|
markdown: string;
|
|
85
|
+
/**
|
|
86
|
+
* Protects the feed: 1 to 256 printable ASCII characters, with no space at the start or end. Only honored on the post that creates the feed; an existing open feed answers 409. Empty is the same as leaving it out.
|
|
87
|
+
*/
|
|
88
|
+
password?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Labels for the note: at most 10 tags, each 1 to 32 characters of letters, digits, `-`, `_`, `.` and `:`; case is folded to lowercase, duplicates are removed. Free labels, not verified, shown with the note (also to readers of the read link and RSS). Ignored when editing a note: an edit keeps its tags.
|
|
91
|
+
*/
|
|
92
|
+
tags?: Array<string>;
|
|
63
93
|
};
|
|
64
94
|
export type PostForm = {
|
|
65
95
|
markdown: string;
|
|
96
|
+
/**
|
|
97
|
+
* Protects the feed: 1 to 256 printable ASCII characters, with no space at the start or end. Only honored on the post that creates the feed; an existing open feed answers 409. Empty is the same as leaving it out.
|
|
98
|
+
*/
|
|
99
|
+
password?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Labels for the note: at most 10 tags, each 1 to 32 characters of letters, digits, `-`, `_`, `.` and `:`; case is folded to lowercase, duplicates are removed. Free labels, not verified, shown with the note (also to readers of the read link and RSS). Ignored when editing a note: an edit keeps its tags.
|
|
102
|
+
*/
|
|
103
|
+
tags?: Array<string>;
|
|
104
|
+
};
|
|
105
|
+
export type PasswordJson = {
|
|
106
|
+
/**
|
|
107
|
+
* The new password: 1 to 256 printable ASCII characters, with no space at the start or end
|
|
108
|
+
*/
|
|
109
|
+
password: string;
|
|
110
|
+
};
|
|
111
|
+
export type FeedSettings = {
|
|
112
|
+
/**
|
|
113
|
+
* Display title, at most 100 characters, one line; empty means none (the feed's name is shown)
|
|
114
|
+
*/
|
|
115
|
+
title: string;
|
|
116
|
+
/**
|
|
117
|
+
* Description, at most 500 characters, one line; may be empty
|
|
118
|
+
*/
|
|
119
|
+
description: string;
|
|
120
|
+
/**
|
|
121
|
+
* The file name of an image uploaded to this feed (see uploadImage), shown as the feed's title image; empty removes it, omitted leaves it as it is
|
|
122
|
+
*/
|
|
123
|
+
image?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Whether readers (RSS, the read API and pages) see who posted each note; omitted leaves it as it is, a new feed starts with true
|
|
126
|
+
*/
|
|
127
|
+
show_sender?: boolean;
|
|
128
|
+
};
|
|
129
|
+
export type Feed = {
|
|
130
|
+
/**
|
|
131
|
+
* The feed's name
|
|
132
|
+
*/
|
|
133
|
+
name: string;
|
|
134
|
+
/**
|
|
135
|
+
* Display title, at most 100 characters, one line; empty means none (the feed's name is shown)
|
|
136
|
+
*/
|
|
137
|
+
title: string;
|
|
138
|
+
/**
|
|
139
|
+
* Description, at most 500 characters, one line; may be empty
|
|
140
|
+
*/
|
|
141
|
+
description: string;
|
|
142
|
+
/**
|
|
143
|
+
* Whether the feed has its own password
|
|
144
|
+
*/
|
|
145
|
+
protected: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* The feed's read-only RSS link; null while the feed has no notes, or if the server can't read the feed's stored read id
|
|
148
|
+
*/
|
|
149
|
+
read_url: string | null;
|
|
150
|
+
/**
|
|
151
|
+
* The feed's title image (absolute URL, served under the read id), or null
|
|
152
|
+
*/
|
|
153
|
+
image_url: string | null;
|
|
154
|
+
/**
|
|
155
|
+
* Whether readers see who posted each note
|
|
156
|
+
*/
|
|
157
|
+
show_sender: boolean;
|
|
158
|
+
};
|
|
159
|
+
export type ReadFeed = {
|
|
160
|
+
/**
|
|
161
|
+
* Display title, at most 100 characters, one line; empty means none (the feed's name is shown)
|
|
162
|
+
*/
|
|
163
|
+
title: string;
|
|
164
|
+
/**
|
|
165
|
+
* Description, at most 500 characters, one line; may be empty
|
|
166
|
+
*/
|
|
167
|
+
description: string;
|
|
168
|
+
/**
|
|
169
|
+
* The feed's title image (absolute URL, served under the read id), or null
|
|
170
|
+
*/
|
|
171
|
+
image_url: string | null;
|
|
66
172
|
};
|
|
67
173
|
export type ListNotesData = {
|
|
68
174
|
body?: never;
|
|
175
|
+
headers?: {
|
|
176
|
+
/**
|
|
177
|
+
* The feed's own password, when it has one: to post, list or get, and (as the current password) to change or remove it. On the `POST` that creates a feed it sets the feed's password; on a `POST` to an existing feed that has none it answers 409. An empty value is the same as no header, so a `POST` with an empty one creates an open feed.
|
|
178
|
+
*/
|
|
179
|
+
'X-Feed-Password'?: string;
|
|
180
|
+
};
|
|
69
181
|
path: {
|
|
70
182
|
/**
|
|
71
183
|
* The feed's name. It is the write key: anyone who knows it can post.
|
|
@@ -81,6 +193,10 @@ export type ListNotesData = {
|
|
|
81
193
|
* Only notes older than this id: the previous page's `next`
|
|
82
194
|
*/
|
|
83
195
|
before?: string;
|
|
196
|
+
/**
|
|
197
|
+
* Only notes carrying this tag
|
|
198
|
+
*/
|
|
199
|
+
tag?: string;
|
|
84
200
|
};
|
|
85
201
|
url: '/api/v1/feeds/{feed}/notes';
|
|
86
202
|
};
|
|
@@ -90,7 +206,7 @@ export type ListNotesErrors = {
|
|
|
90
206
|
*/
|
|
91
207
|
400: Error;
|
|
92
208
|
/**
|
|
93
|
-
* The instance has a password and it is missing or wrong
|
|
209
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
94
210
|
*/
|
|
95
211
|
401: Error;
|
|
96
212
|
/**
|
|
@@ -108,6 +224,16 @@ export type ListNotesResponses = {
|
|
|
108
224
|
export type ListNotesResponse = ListNotesResponses[keyof ListNotesResponses];
|
|
109
225
|
export type PostNoteData = {
|
|
110
226
|
body: PostJson;
|
|
227
|
+
headers?: {
|
|
228
|
+
/**
|
|
229
|
+
* The feed's own password, when it has one: to post, list or get, and (as the current password) to change or remove it. On the `POST` that creates a feed it sets the feed's password; on a `POST` to an existing feed that has none it answers 409. An empty value is the same as no header, so a `POST` with an empty one creates an open feed.
|
|
230
|
+
*/
|
|
231
|
+
'X-Feed-Password'?: string;
|
|
232
|
+
/**
|
|
233
|
+
* Tags for the note, comma-separated (`ci,deploy`): at most 10 tags, each 1 to 32 characters of letters, digits, `-`, `_`, `.` and `:`; case is folded to lowercase, duplicates are removed. For a raw markdown body; a JSON or form body's own `tags` wins. Empty is none.
|
|
234
|
+
*/
|
|
235
|
+
'X-Note-Tags'?: string;
|
|
236
|
+
};
|
|
111
237
|
path: {
|
|
112
238
|
/**
|
|
113
239
|
* The feed's name. It is the write key: anyone who knows it can post.
|
|
@@ -119,13 +245,17 @@ export type PostNoteData = {
|
|
|
119
245
|
};
|
|
120
246
|
export type PostNoteErrors = {
|
|
121
247
|
/**
|
|
122
|
-
* Invalid or reserved feed name; empty note; bad JSON, form or UTF-8
|
|
248
|
+
* Invalid or reserved feed name; empty note; bad JSON, form or UTF-8; a new password that is not printable ASCII; invalid tags
|
|
123
249
|
*/
|
|
124
250
|
400: Error;
|
|
125
251
|
/**
|
|
126
|
-
* The instance has a password and it is missing or wrong
|
|
252
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
127
253
|
*/
|
|
128
254
|
401: Error;
|
|
255
|
+
/**
|
|
256
|
+
* A password was sent for a feed that already exists without one: it can't be claimed
|
|
257
|
+
*/
|
|
258
|
+
409: Error;
|
|
129
259
|
/**
|
|
130
260
|
* Body over 102400 bytes
|
|
131
261
|
*/
|
|
@@ -151,8 +281,61 @@ export type PostNoteResponses = {
|
|
|
151
281
|
201: Created;
|
|
152
282
|
};
|
|
153
283
|
export type PostNoteResponse = PostNoteResponses[keyof PostNoteResponses];
|
|
284
|
+
export type DeleteNoteData = {
|
|
285
|
+
body?: never;
|
|
286
|
+
headers?: {
|
|
287
|
+
/**
|
|
288
|
+
* The feed's own password, when it has one: to post, list or get, and (as the current password) to change or remove it. On the `POST` that creates a feed it sets the feed's password; on a `POST` to an existing feed that has none it answers 409. An empty value is the same as no header, so a `POST` with an empty one creates an open feed.
|
|
289
|
+
*/
|
|
290
|
+
'X-Feed-Password'?: string;
|
|
291
|
+
};
|
|
292
|
+
path: {
|
|
293
|
+
/**
|
|
294
|
+
* The feed's name. It is the write key: anyone who knows it can post.
|
|
295
|
+
*/
|
|
296
|
+
feed: string;
|
|
297
|
+
/**
|
|
298
|
+
* The note's id
|
|
299
|
+
*/
|
|
300
|
+
id: string;
|
|
301
|
+
};
|
|
302
|
+
query?: never;
|
|
303
|
+
url: '/api/v1/feeds/{feed}/notes/{id}';
|
|
304
|
+
};
|
|
305
|
+
export type DeleteNoteErrors = {
|
|
306
|
+
/**
|
|
307
|
+
* Invalid or reserved feed name
|
|
308
|
+
*/
|
|
309
|
+
400: Error;
|
|
310
|
+
/**
|
|
311
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
312
|
+
*/
|
|
313
|
+
401: Error;
|
|
314
|
+
/**
|
|
315
|
+
* No such note
|
|
316
|
+
*/
|
|
317
|
+
404: Error;
|
|
318
|
+
/**
|
|
319
|
+
* Too many posts, edits and deletes, or wrong passwords, from this client
|
|
320
|
+
*/
|
|
321
|
+
429: Error;
|
|
322
|
+
};
|
|
323
|
+
export type DeleteNoteError = DeleteNoteErrors[keyof DeleteNoteErrors];
|
|
324
|
+
export type DeleteNoteResponses = {
|
|
325
|
+
/**
|
|
326
|
+
* Deleted
|
|
327
|
+
*/
|
|
328
|
+
204: void;
|
|
329
|
+
};
|
|
330
|
+
export type DeleteNoteResponse = DeleteNoteResponses[keyof DeleteNoteResponses];
|
|
154
331
|
export type GetNoteData = {
|
|
155
332
|
body?: never;
|
|
333
|
+
headers?: {
|
|
334
|
+
/**
|
|
335
|
+
* The feed's own password, when it has one: to post, list or get, and (as the current password) to change or remove it. On the `POST` that creates a feed it sets the feed's password; on a `POST` to an existing feed that has none it answers 409. An empty value is the same as no header, so a `POST` with an empty one creates an open feed.
|
|
336
|
+
*/
|
|
337
|
+
'X-Feed-Password'?: string;
|
|
338
|
+
};
|
|
156
339
|
path: {
|
|
157
340
|
/**
|
|
158
341
|
* The feed's name. It is the write key: anyone who knows it can post.
|
|
@@ -172,7 +355,7 @@ export type GetNoteErrors = {
|
|
|
172
355
|
*/
|
|
173
356
|
400: Error;
|
|
174
357
|
/**
|
|
175
|
-
* The instance has a password and it is missing or wrong
|
|
358
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
176
359
|
*/
|
|
177
360
|
401: Error;
|
|
178
361
|
/**
|
|
@@ -192,11 +375,364 @@ export type GetNoteResponses = {
|
|
|
192
375
|
200: Note;
|
|
193
376
|
};
|
|
194
377
|
export type GetNoteResponse = GetNoteResponses[keyof GetNoteResponses];
|
|
378
|
+
export type EditNoteData = {
|
|
379
|
+
body: PostJson;
|
|
380
|
+
headers?: {
|
|
381
|
+
/**
|
|
382
|
+
* The feed's own password, when it has one: to post, list or get, and (as the current password) to change or remove it. On the `POST` that creates a feed it sets the feed's password; on a `POST` to an existing feed that has none it answers 409. An empty value is the same as no header, so a `POST` with an empty one creates an open feed.
|
|
383
|
+
*/
|
|
384
|
+
'X-Feed-Password'?: string;
|
|
385
|
+
};
|
|
386
|
+
path: {
|
|
387
|
+
/**
|
|
388
|
+
* The feed's name. It is the write key: anyone who knows it can post.
|
|
389
|
+
*/
|
|
390
|
+
feed: string;
|
|
391
|
+
/**
|
|
392
|
+
* The note's id
|
|
393
|
+
*/
|
|
394
|
+
id: string;
|
|
395
|
+
};
|
|
396
|
+
query?: never;
|
|
397
|
+
url: '/api/v1/feeds/{feed}/notes/{id}';
|
|
398
|
+
};
|
|
399
|
+
export type EditNoteErrors = {
|
|
400
|
+
/**
|
|
401
|
+
* Invalid or reserved feed name; empty note; bad JSON, form or UTF-8
|
|
402
|
+
*/
|
|
403
|
+
400: Error;
|
|
404
|
+
/**
|
|
405
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
406
|
+
*/
|
|
407
|
+
401: Error;
|
|
408
|
+
/**
|
|
409
|
+
* No such note
|
|
410
|
+
*/
|
|
411
|
+
404: Error;
|
|
412
|
+
/**
|
|
413
|
+
* Body over 102400 bytes
|
|
414
|
+
*/
|
|
415
|
+
413: Error;
|
|
416
|
+
/**
|
|
417
|
+
* Unsupported content type
|
|
418
|
+
*/
|
|
419
|
+
415: Error;
|
|
420
|
+
/**
|
|
421
|
+
* Too many posts, edits and deletes, or wrong passwords, from this client
|
|
422
|
+
*/
|
|
423
|
+
429: Error;
|
|
424
|
+
};
|
|
425
|
+
export type EditNoteError = EditNoteErrors[keyof EditNoteErrors];
|
|
426
|
+
export type EditNoteResponses = {
|
|
427
|
+
/**
|
|
428
|
+
* The note as it is now
|
|
429
|
+
*/
|
|
430
|
+
200: Note;
|
|
431
|
+
};
|
|
432
|
+
export type EditNoteResponse = EditNoteResponses[keyof EditNoteResponses];
|
|
433
|
+
export type UploadImageData = {
|
|
434
|
+
/**
|
|
435
|
+
* The image's bytes: PNG, JPEG, GIF or WebP, recognized by their first bytes, not by the Content-Type
|
|
436
|
+
*/
|
|
437
|
+
body: Blob | File;
|
|
438
|
+
headers?: {
|
|
439
|
+
/**
|
|
440
|
+
* The feed's own password, when it has one: to post, list or get, and (as the current password) to change or remove it. On the `POST` that creates a feed it sets the feed's password; on a `POST` to an existing feed that has none it answers 409. An empty value is the same as no header, so a `POST` with an empty one creates an open feed.
|
|
441
|
+
*/
|
|
442
|
+
'X-Feed-Password'?: string;
|
|
443
|
+
};
|
|
444
|
+
path: {
|
|
445
|
+
/**
|
|
446
|
+
* The feed's name. It is the write key: anyone who knows it can post.
|
|
447
|
+
*/
|
|
448
|
+
feed: string;
|
|
449
|
+
};
|
|
450
|
+
query?: never;
|
|
451
|
+
url: '/api/v1/feeds/{feed}/images';
|
|
452
|
+
};
|
|
453
|
+
export type UploadImageErrors = {
|
|
454
|
+
/**
|
|
455
|
+
* Invalid or reserved feed name
|
|
456
|
+
*/
|
|
457
|
+
400: Error;
|
|
458
|
+
/**
|
|
459
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
460
|
+
*/
|
|
461
|
+
401: Error;
|
|
462
|
+
/**
|
|
463
|
+
* No such feed
|
|
464
|
+
*/
|
|
465
|
+
404: Error;
|
|
466
|
+
/**
|
|
467
|
+
* Body over NOTEFEED_MAX_IMAGE_BYTES
|
|
468
|
+
*/
|
|
469
|
+
413: Error;
|
|
470
|
+
/**
|
|
471
|
+
* Not a PNG, JPEG, GIF or WebP image
|
|
472
|
+
*/
|
|
473
|
+
415: Error;
|
|
474
|
+
/**
|
|
475
|
+
* Too many posts, uploads, edits and deletes, or wrong passwords, from this client
|
|
476
|
+
*/
|
|
477
|
+
429: Error;
|
|
478
|
+
/**
|
|
479
|
+
* NOTEFEED_MAX_IMAGES_PER_FEED reached
|
|
480
|
+
*/
|
|
481
|
+
507: Error;
|
|
482
|
+
};
|
|
483
|
+
export type UploadImageError = UploadImageErrors[keyof UploadImageErrors];
|
|
484
|
+
export type UploadImageResponses = {
|
|
485
|
+
/**
|
|
486
|
+
* Stored (or already there)
|
|
487
|
+
*/
|
|
488
|
+
201: ImageUploaded;
|
|
489
|
+
};
|
|
490
|
+
export type UploadImageResponse = UploadImageResponses[keyof UploadImageResponses];
|
|
491
|
+
export type DeleteFeedData = {
|
|
492
|
+
body?: never;
|
|
493
|
+
headers?: {
|
|
494
|
+
/**
|
|
495
|
+
* The feed's own password, when it has one: to post, list or get, and (as the current password) to change or remove it. On the `POST` that creates a feed it sets the feed's password; on a `POST` to an existing feed that has none it answers 409. An empty value is the same as no header, so a `POST` with an empty one creates an open feed.
|
|
496
|
+
*/
|
|
497
|
+
'X-Feed-Password'?: string;
|
|
498
|
+
};
|
|
499
|
+
path: {
|
|
500
|
+
/**
|
|
501
|
+
* The feed's name. It is the write key: anyone who knows it can post.
|
|
502
|
+
*/
|
|
503
|
+
feed: string;
|
|
504
|
+
};
|
|
505
|
+
query?: never;
|
|
506
|
+
url: '/api/v1/feeds/{feed}';
|
|
507
|
+
};
|
|
508
|
+
export type DeleteFeedErrors = {
|
|
509
|
+
/**
|
|
510
|
+
* Invalid or reserved feed name
|
|
511
|
+
*/
|
|
512
|
+
400: Error;
|
|
513
|
+
/**
|
|
514
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
515
|
+
*/
|
|
516
|
+
401: Error;
|
|
517
|
+
/**
|
|
518
|
+
* No such feed
|
|
519
|
+
*/
|
|
520
|
+
404: Error;
|
|
521
|
+
/**
|
|
522
|
+
* Too many posts, edits and deletes, or wrong passwords, from this client
|
|
523
|
+
*/
|
|
524
|
+
429: Error;
|
|
525
|
+
};
|
|
526
|
+
export type DeleteFeedError = DeleteFeedErrors[keyof DeleteFeedErrors];
|
|
527
|
+
export type DeleteFeedResponses = {
|
|
528
|
+
/**
|
|
529
|
+
* Deleted
|
|
530
|
+
*/
|
|
531
|
+
204: void;
|
|
532
|
+
};
|
|
533
|
+
export type DeleteFeedResponse = DeleteFeedResponses[keyof DeleteFeedResponses];
|
|
534
|
+
export type GetFeedData = {
|
|
535
|
+
body?: never;
|
|
536
|
+
headers?: {
|
|
537
|
+
/**
|
|
538
|
+
* The feed's own password, when it has one: to post, list or get, and (as the current password) to change or remove it. On the `POST` that creates a feed it sets the feed's password; on a `POST` to an existing feed that has none it answers 409. An empty value is the same as no header, so a `POST` with an empty one creates an open feed.
|
|
539
|
+
*/
|
|
540
|
+
'X-Feed-Password'?: string;
|
|
541
|
+
};
|
|
542
|
+
path: {
|
|
543
|
+
/**
|
|
544
|
+
* The feed's name. It is the write key: anyone who knows it can post.
|
|
545
|
+
*/
|
|
546
|
+
feed: string;
|
|
547
|
+
};
|
|
548
|
+
query?: never;
|
|
549
|
+
url: '/api/v1/feeds/{feed}';
|
|
550
|
+
};
|
|
551
|
+
export type GetFeedErrors = {
|
|
552
|
+
/**
|
|
553
|
+
* Invalid or reserved feed name
|
|
554
|
+
*/
|
|
555
|
+
400: Error;
|
|
556
|
+
/**
|
|
557
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
558
|
+
*/
|
|
559
|
+
401: Error;
|
|
560
|
+
/**
|
|
561
|
+
* No such feed
|
|
562
|
+
*/
|
|
563
|
+
404: Error;
|
|
564
|
+
/**
|
|
565
|
+
* Too many wrong passwords from this client
|
|
566
|
+
*/
|
|
567
|
+
429: Error;
|
|
568
|
+
};
|
|
569
|
+
export type GetFeedError = GetFeedErrors[keyof GetFeedErrors];
|
|
570
|
+
export type GetFeedResponses = {
|
|
571
|
+
/**
|
|
572
|
+
* The feed
|
|
573
|
+
*/
|
|
574
|
+
200: Feed;
|
|
575
|
+
};
|
|
576
|
+
export type GetFeedResponse = GetFeedResponses[keyof GetFeedResponses];
|
|
577
|
+
export type UpdateFeedData = {
|
|
578
|
+
body: FeedSettings;
|
|
579
|
+
headers?: {
|
|
580
|
+
/**
|
|
581
|
+
* The feed's own password, when it has one: to post, list or get, and (as the current password) to change or remove it. On the `POST` that creates a feed it sets the feed's password; on a `POST` to an existing feed that has none it answers 409. An empty value is the same as no header, so a `POST` with an empty one creates an open feed.
|
|
582
|
+
*/
|
|
583
|
+
'X-Feed-Password'?: string;
|
|
584
|
+
};
|
|
585
|
+
path: {
|
|
586
|
+
/**
|
|
587
|
+
* The feed's name. It is the write key: anyone who knows it can post.
|
|
588
|
+
*/
|
|
589
|
+
feed: string;
|
|
590
|
+
};
|
|
591
|
+
query?: never;
|
|
592
|
+
url: '/api/v1/feeds/{feed}';
|
|
593
|
+
};
|
|
594
|
+
export type UpdateFeedErrors = {
|
|
595
|
+
/**
|
|
596
|
+
* Invalid or reserved feed name, bad JSON, or a title or description that is too long or has control characters
|
|
597
|
+
*/
|
|
598
|
+
400: Error;
|
|
599
|
+
/**
|
|
600
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
601
|
+
*/
|
|
602
|
+
401: Error;
|
|
603
|
+
/**
|
|
604
|
+
* No such feed
|
|
605
|
+
*/
|
|
606
|
+
404: Error;
|
|
607
|
+
/**
|
|
608
|
+
* Too many posts, edits and deletes, or wrong passwords, from this client
|
|
609
|
+
*/
|
|
610
|
+
429: Error;
|
|
611
|
+
};
|
|
612
|
+
export type UpdateFeedError = UpdateFeedErrors[keyof UpdateFeedErrors];
|
|
613
|
+
export type UpdateFeedResponses = {
|
|
614
|
+
/**
|
|
615
|
+
* The feed as it is now
|
|
616
|
+
*/
|
|
617
|
+
200: Feed;
|
|
618
|
+
};
|
|
619
|
+
export type UpdateFeedResponse = UpdateFeedResponses[keyof UpdateFeedResponses];
|
|
620
|
+
export type RemoveFeedPasswordData = {
|
|
621
|
+
body?: never;
|
|
622
|
+
headers?: {
|
|
623
|
+
/**
|
|
624
|
+
* The feed's current password
|
|
625
|
+
*/
|
|
626
|
+
'X-Feed-Password'?: string;
|
|
627
|
+
};
|
|
628
|
+
path: {
|
|
629
|
+
/**
|
|
630
|
+
* The feed's name. It is the write key: anyone who knows it can post.
|
|
631
|
+
*/
|
|
632
|
+
feed: string;
|
|
633
|
+
};
|
|
634
|
+
query?: never;
|
|
635
|
+
url: '/api/v1/feeds/{feed}/password';
|
|
636
|
+
};
|
|
637
|
+
export type RemoveFeedPasswordErrors = {
|
|
638
|
+
/**
|
|
639
|
+
* Invalid or reserved feed name
|
|
640
|
+
*/
|
|
641
|
+
400: Error;
|
|
642
|
+
/**
|
|
643
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
644
|
+
*/
|
|
645
|
+
401: Error;
|
|
646
|
+
/**
|
|
647
|
+
* The feed has no password
|
|
648
|
+
*/
|
|
649
|
+
409: Error;
|
|
650
|
+
/**
|
|
651
|
+
* Too many wrong passwords from this client
|
|
652
|
+
*/
|
|
653
|
+
429: Error;
|
|
654
|
+
};
|
|
655
|
+
export type RemoveFeedPasswordError = RemoveFeedPasswordErrors[keyof RemoveFeedPasswordErrors];
|
|
656
|
+
export type RemoveFeedPasswordResponses = {
|
|
657
|
+
/**
|
|
658
|
+
* Removed
|
|
659
|
+
*/
|
|
660
|
+
204: void;
|
|
661
|
+
};
|
|
662
|
+
export type RemoveFeedPasswordResponse = RemoveFeedPasswordResponses[keyof RemoveFeedPasswordResponses];
|
|
663
|
+
export type ChangeFeedPasswordData = {
|
|
664
|
+
body: PasswordJson;
|
|
665
|
+
headers?: {
|
|
666
|
+
/**
|
|
667
|
+
* The feed's current password
|
|
668
|
+
*/
|
|
669
|
+
'X-Feed-Password'?: string;
|
|
670
|
+
};
|
|
671
|
+
path: {
|
|
672
|
+
/**
|
|
673
|
+
* The feed's name. It is the write key: anyone who knows it can post.
|
|
674
|
+
*/
|
|
675
|
+
feed: string;
|
|
676
|
+
};
|
|
677
|
+
query?: never;
|
|
678
|
+
url: '/api/v1/feeds/{feed}/password';
|
|
679
|
+
};
|
|
680
|
+
export type ChangeFeedPasswordErrors = {
|
|
681
|
+
/**
|
|
682
|
+
* Invalid or reserved feed name, bad JSON, or a new password that is not 1 to 256 printable ASCII characters, with no space at the start or end
|
|
683
|
+
*/
|
|
684
|
+
400: Error;
|
|
685
|
+
/**
|
|
686
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
687
|
+
*/
|
|
688
|
+
401: Error;
|
|
689
|
+
/**
|
|
690
|
+
* The feed has no password
|
|
691
|
+
*/
|
|
692
|
+
409: Error;
|
|
693
|
+
/**
|
|
694
|
+
* Too many wrong passwords from this client
|
|
695
|
+
*/
|
|
696
|
+
429: Error;
|
|
697
|
+
};
|
|
698
|
+
export type ChangeFeedPasswordError = ChangeFeedPasswordErrors[keyof ChangeFeedPasswordErrors];
|
|
699
|
+
export type ChangeFeedPasswordResponses = {
|
|
700
|
+
/**
|
|
701
|
+
* Changed; the old password and unlock cookies stop working
|
|
702
|
+
*/
|
|
703
|
+
204: void;
|
|
704
|
+
};
|
|
705
|
+
export type ChangeFeedPasswordResponse = ChangeFeedPasswordResponses[keyof ChangeFeedPasswordResponses];
|
|
706
|
+
export type GetReadFeedData = {
|
|
707
|
+
body?: never;
|
|
708
|
+
path: {
|
|
709
|
+
/**
|
|
710
|
+
* The feed's read id, from its read link: 22 random characters, or the feed's own name for a reserved feed. Read-only; never reveals the name of any other feed.
|
|
711
|
+
*/
|
|
712
|
+
readId: string;
|
|
713
|
+
};
|
|
714
|
+
query?: never;
|
|
715
|
+
url: '/api/v1/read/{readId}';
|
|
716
|
+
};
|
|
717
|
+
export type GetReadFeedErrors = {
|
|
718
|
+
/**
|
|
719
|
+
* Malformed read id
|
|
720
|
+
*/
|
|
721
|
+
404: Error;
|
|
722
|
+
};
|
|
723
|
+
export type GetReadFeedError = GetReadFeedErrors[keyof GetReadFeedErrors];
|
|
724
|
+
export type GetReadFeedResponses = {
|
|
725
|
+
/**
|
|
726
|
+
* The feed's public settings
|
|
727
|
+
*/
|
|
728
|
+
200: ReadFeed;
|
|
729
|
+
};
|
|
730
|
+
export type GetReadFeedResponse = GetReadFeedResponses[keyof GetReadFeedResponses];
|
|
195
731
|
export type ListReadNotesData = {
|
|
196
732
|
body?: never;
|
|
197
733
|
path: {
|
|
198
734
|
/**
|
|
199
|
-
* The feed's read id, from its read link. Read-only; never reveals the name.
|
|
735
|
+
* The feed's read id, from its read link: 22 random characters, or the feed's own name for a reserved feed. Read-only; never reveals the name of any other feed.
|
|
200
736
|
*/
|
|
201
737
|
readId: string;
|
|
202
738
|
};
|
|
@@ -209,6 +745,10 @@ export type ListReadNotesData = {
|
|
|
209
745
|
* Only notes older than this id: the previous page's `next`
|
|
210
746
|
*/
|
|
211
747
|
before?: string;
|
|
748
|
+
/**
|
|
749
|
+
* Only notes carrying this tag
|
|
750
|
+
*/
|
|
751
|
+
tag?: string;
|
|
212
752
|
};
|
|
213
753
|
url: '/api/v1/read/{readId}/notes';
|
|
214
754
|
};
|
|
@@ -234,7 +774,7 @@ export type GetReadNoteData = {
|
|
|
234
774
|
body?: never;
|
|
235
775
|
path: {
|
|
236
776
|
/**
|
|
237
|
-
* The feed's read id, from its read link. Read-only; never reveals the name.
|
|
777
|
+
* The feed's read id, from its read link: 22 random characters, or the feed's own name for a reserved feed. Read-only; never reveals the name of any other feed.
|
|
238
778
|
*/
|
|
239
779
|
readId: string;
|
|
240
780
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { AuthError, Client, ConfigError, InvalidRequestError, LimitReachedError, NotefeedError, NotFoundError, NoteTooLargeError, RateLimitedError, } from "./client.js";
|
|
2
|
-
export type { ClientOptions, Created, ErrorCode, Note } from "./client.js";
|
|
2
|
+
export type { ClientOptions, Created, ErrorCode, Feed, FeedSettings, ImageUploaded, Note } from "./client.js";
|
package/package.json
CHANGED