notefeed 0.33.1 → 0.35.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 +3 -1
- package/dist/client.d.ts +10 -3
- package/dist/client.js +26 -5
- package/dist/generated/index.d.ts +2 -2
- package/dist/generated/index.js +1 -1
- package/dist/generated/sdk.gen.d.ts +8 -2
- package/dist/generated/sdk.gen.js +11 -1
- package/dist/generated/types.gen.d.ts +101 -6
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# notefeed
|
|
2
2
|
|
|
3
|
-
Post and read markdown notes on a [notefeed](https://github.com/notefeed/notefeed) server from Node or the command line. No dependencies; Node
|
|
3
|
+
Post and read markdown notes on a [notefeed](https://github.com/notefeed/notefeed) server from Node or the command line. No dependencies; Node 22 or newer.
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
6
|
npm install notefeed
|
|
@@ -27,6 +27,8 @@ Every note has a date, now unless you give one: `client.post(text, { date: "2025
|
|
|
27
27
|
|
|
28
28
|
A note posted with `draft: true` (`notefeed post "…" --draft`) is a draft: readers don't see it, or its pictures, until `client.update(id, { draft: false })` (`notefeed update <id> --publish`) publishes it at its date; `draft: true` (`--draft`) hides it again.
|
|
29
29
|
|
|
30
|
+
Where the operator took a post down for breaking the instance's content rules, a list has a mark in its place: a note with `removed: true`, type `application/x-notefeed-removed`, the removed note's id and date, no content and `file_url` null. Getting it alone or editing it throws `NotFoundError` (code `removed`, 410), and so does the removed note's id after the mark is gone; `client.delete(id)` (`notefeed delete <id>`) takes the mark off the feed, and the note does not come back.
|
|
31
|
+
|
|
30
32
|
`Client.fromEnv()` reads `NOTEFEED_URL` / `NOTEFEED_FEED` / `NOTEFEED_PASSWORD`; so does the `notefeed` command, unless given `--url` / `--feed` / `--password`.
|
|
31
33
|
|
|
32
34
|
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.
|
package/dist/client.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export declare class RateLimitedError extends NotefeedError {
|
|
|
34
34
|
readonly retryAfter: number | null;
|
|
35
35
|
constructor(message: string, status: number | null, code: ErrorCode | null, retryAfter: number | null);
|
|
36
36
|
}
|
|
37
|
-
/** No such note, or a malformed read id; also a feed the operator removed for good (`removed`, 410). */
|
|
37
|
+
/** No such note, or a malformed read id; also a feed or a note the operator removed for good (`removed`, 410). */
|
|
38
38
|
export declare class NotFoundError extends NotefeedError {
|
|
39
39
|
}
|
|
40
40
|
/** The instance's feed or note limit, or the feed's image limit, is reached. */
|
|
@@ -51,7 +51,8 @@ export declare class InvalidRequestError extends NotefeedError {
|
|
|
51
51
|
}
|
|
52
52
|
export declare class Client {
|
|
53
53
|
readonly url: string;
|
|
54
|
-
|
|
54
|
+
/** The feed calls use when they name none; a rename of it through updateFeed() (`name`) moves it to the new name. */
|
|
55
|
+
feed: string | null;
|
|
55
56
|
private readonly api;
|
|
56
57
|
private readonly timeoutMs;
|
|
57
58
|
private readonly feedPassword;
|
|
@@ -124,7 +125,7 @@ export declare class Client {
|
|
|
124
125
|
feed?: string;
|
|
125
126
|
feedPassword?: string;
|
|
126
127
|
}): Promise<Feed>;
|
|
127
|
-
/** 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. `read_id` gives the feed another read id (3 to 64 characters of `a-z`, `0-9`, `-`, `_`; `""` for a random one; left out keeps it); the old one is freed, and relative image links in notes follow while full URLs do not. The feed must already exist. Same options as post(). */
|
|
128
|
+
/** 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. `read_id` gives the feed another read id (3 to 64 characters of `a-z`, `0-9`, `-`, `_`; `""` for a random one; left out keeps it); the old one is freed, and relative image links in notes follow while full URLs do not. `name` renames the feed (1 to 64 characters of `a-z`, `0-9`, `-`, `_`): everything goes with it and the old name stops working at once; when it was this client's own feed, the client uses the new name for the rest of this run; change NOTEFEED_FEED (or wherever the name is configured) before the next one. The feed must already exist. Same options as post(). */
|
|
128
129
|
updateFeed(settings: FeedSettings, options?: {
|
|
129
130
|
feed?: string;
|
|
130
131
|
feedPassword?: string;
|
|
@@ -181,6 +182,12 @@ export declare class Client {
|
|
|
181
182
|
feed?: string;
|
|
182
183
|
feedPassword?: string;
|
|
183
184
|
}): Promise<Note>;
|
|
185
|
+
/** A note's file by its own name (a note's `file`, `<id>.<ext>`), as bytes: also a draft's or a scheduled note's, which the read link
|
|
186
|
+
* (`file_url`) does not serve until readers may see them, so a post's pictures can be checked before it goes out. */
|
|
187
|
+
file(name: string, options?: {
|
|
188
|
+
feed?: string;
|
|
189
|
+
feedPassword?: string;
|
|
190
|
+
}): Promise<Uint8Array>;
|
|
184
191
|
/** Like notes(), by the feed's read id: public, read-only, needs no password. */
|
|
185
192
|
readNotes(readId: string, options?: {
|
|
186
193
|
pageSize?: number;
|
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 { changeFeedPassword, createFeed, deleteFeed, deleteFeedLicense, deleteNote, editNote, getFeed, getLicenses, getNote, getReadNote, listNotes, listReadNotes, patchNote, postNote, putFeedLicense, recoverFeedPassword, removeFeedImage, setFeedImage, updateFeed } from "./generated/sdk.gen.js";
|
|
6
|
+
import { changeFeedPassword, createFeed, deleteFeed, deleteFeedLicense, deleteNote, editNote, getFeed, getFile, getLicenses, getNote, getReadNote, listNotes, listReadNotes, patchNote, postNote, putFeedLicense, recoverFeedPassword, removeFeedImage, setFeedImage, updateFeed } 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;
|
|
@@ -29,7 +29,7 @@ export class RateLimitedError extends NotefeedError {
|
|
|
29
29
|
this.retryAfter = retryAfter;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
/** No such note, or a malformed read id; also a feed the operator removed for good (`removed`, 410). */
|
|
32
|
+
/** No such note, or a malformed read id; also a feed or a note the operator removed for good (`removed`, 410). */
|
|
33
33
|
export class NotFoundError extends NotefeedError {
|
|
34
34
|
}
|
|
35
35
|
/** The instance's feed or note limit, or the feed's image limit, is reached. */
|
|
@@ -81,6 +81,7 @@ function asFile(content, type) {
|
|
|
81
81
|
}
|
|
82
82
|
export class Client {
|
|
83
83
|
url;
|
|
84
|
+
/** The feed calls use when they name none; a rename of it through updateFeed() (`name`) moves it to the new name. */
|
|
84
85
|
feed;
|
|
85
86
|
api;
|
|
86
87
|
timeoutMs;
|
|
@@ -208,11 +209,22 @@ export class Client {
|
|
|
208
209
|
const feed = this.feedFor(options.feed);
|
|
209
210
|
return this.call(getFeed({ client: this.api, path: { feed }, ...this.opts(options.feedPassword) }));
|
|
210
211
|
}
|
|
211
|
-
/** 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. `read_id` gives the feed another read id (3 to 64 characters of `a-z`, `0-9`, `-`, `_`; `""` for a random one; left out keeps it); the old one is freed, and relative image links in notes follow while full URLs do not. The feed must already exist. Same options as post(). */
|
|
212
|
+
/** 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. `read_id` gives the feed another read id (3 to 64 characters of `a-z`, `0-9`, `-`, `_`; `""` for a random one; left out keeps it); the old one is freed, and relative image links in notes follow while full URLs do not. `name` renames the feed (1 to 64 characters of `a-z`, `0-9`, `-`, `_`): everything goes with it and the old name stops working at once; when it was this client's own feed, the client uses the new name for the rest of this run; change NOTEFEED_FEED (or wherever the name is configured) before the next one. The feed must already exist. Same options as post(). */
|
|
212
213
|
async updateFeed(settings, options = {}) {
|
|
213
214
|
const feed = this.feedFor(options.feed);
|
|
214
|
-
|
|
215
|
-
|
|
215
|
+
if (settings.name)
|
|
216
|
+
checkFeed(settings.name);
|
|
217
|
+
const body = {
|
|
218
|
+
title: settings.title,
|
|
219
|
+
description: settings.description,
|
|
220
|
+
...(settings.image === undefined ? {} : { image: settings.image }),
|
|
221
|
+
...(settings.read_id === undefined ? {} : { read_id: settings.read_id }),
|
|
222
|
+
...(settings.name === undefined ? {} : { name: settings.name }),
|
|
223
|
+
};
|
|
224
|
+
const updated = await this.call(updateFeed({ client: this.api, path: { feed }, body, ...this.opts(options.feedPassword) }));
|
|
225
|
+
if (feed === this.feed && typeof updated?.name === "string" && updated.name !== feed)
|
|
226
|
+
this.feed = updated.name;
|
|
227
|
+
return updated;
|
|
216
228
|
}
|
|
217
229
|
/** Put the license the key names on the feed, taking it off the feed it was on; a feed needs no password for it. Only on an instance that sells licenses. Same options as post(). */
|
|
218
230
|
async attachLicense(key, options = {}) {
|
|
@@ -265,6 +277,15 @@ export class Client {
|
|
|
265
277
|
const feed = this.feedFor(options.feed);
|
|
266
278
|
return this.call(getNote({ client: this.api, path: { feed, id }, ...this.opts(options.feedPassword) }));
|
|
267
279
|
}
|
|
280
|
+
/** A note's file by its own name (a note's `file`, `<id>.<ext>`), as bytes: also a draft's or a scheduled note's, which the read link
|
|
281
|
+
* (`file_url`) does not serve until readers may see them, so a post's pictures can be checked before it goes out. */
|
|
282
|
+
async file(name, options = {}) {
|
|
283
|
+
const feed = this.feedFor(options.feed);
|
|
284
|
+
const request = getFile({ client: this.api, path: { feed, file: name }, parseAs: "arrayBuffer", ...this.opts(options.feedPassword) });
|
|
285
|
+
// Asked for as an ArrayBuffer, whatever the generated type says; wrapped so call() checks it like any other answer.
|
|
286
|
+
const asBytes = request.then((r) => ({ ...r, data: r.data instanceof ArrayBuffer ? { bytes: new Uint8Array(r.data) } : undefined }));
|
|
287
|
+
return (await this.call(asBytes)).bytes;
|
|
288
|
+
}
|
|
268
289
|
/** Like notes(), by the feed's read id: public, read-only, needs no password. */
|
|
269
290
|
readNotes(readId, options = {}) {
|
|
270
291
|
return this.pages((before) => listReadNotes({ client: this.api, path: { readId }, query: { limit: options.pageSize, before, tag: options.tag }, ...this.opts() }));
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { changeFeedPassword, createFeed, deleteFeed, deleteFeedLicense, deleteNote, editNote, getFeed, getLicenses, getNote, getOpenApi, getReadFeed, getReadNote, listNotes, listReadNotes, type Options, patchNote, postNote, putFeedLicense, recoverFeedPassword, removeFeedImage, removeFeedPassword, setFeedImage, updateFeed } from './sdk.gen.js';
|
|
2
|
-
export type { ChangeFeedPasswordData, ChangeFeedPasswordError, ChangeFeedPasswordErrors, ChangeFeedPasswordResponse, ChangeFeedPasswordResponses, ClientOptions, Created, CreateFeedData, CreateFeedError, CreateFeedErrors, CreateFeedJson, CreateFeedResponse, CreateFeedResponses, DeleteFeedData, DeleteFeedError, DeleteFeedErrors, DeleteFeedLicenseData, DeleteFeedLicenseError, DeleteFeedLicenseErrors, DeleteFeedLicenseResponse, DeleteFeedLicenseResponses, DeleteFeedResponse, DeleteFeedResponses, DeleteNoteData, DeleteNoteError, DeleteNoteErrors, DeleteNoteResponse, DeleteNoteResponses, EditNoteData, EditNoteError, EditNoteErrors, EditNoteResponse, EditNoteResponses, Error, Feed, FeedSettings, FreeTier, GetFeedData, GetFeedError, GetFeedErrors, GetFeedResponse, GetFeedResponses, GetLicensesData, GetLicensesError, GetLicensesErrors, GetLicensesResponse, GetLicensesResponses, GetNoteData, GetNoteError, GetNoteErrors, GetNoteResponse, GetNoteResponses, GetOpenApiData, GetOpenApiResponse, GetOpenApiResponses, GetReadFeedData, GetReadFeedError, GetReadFeedErrors, GetReadFeedResponse, GetReadFeedResponses, GetReadNoteData, GetReadNoteError, GetReadNoteErrors, GetReadNoteResponse, GetReadNoteResponses, LicenseKey, Licenses, ListNotesData, ListNotesError, ListNotesErrors, ListNotesResponse, ListNotesResponses, ListReadNotesData, ListReadNotesError, ListReadNotesErrors, ListReadNotesResponse, ListReadNotesResponses, MultipartNote, Note, NoteEdited, NoteList, NoteMeta, PasswordJson, PatchNoteData, PatchNoteError, PatchNoteErrors, PatchNoteResponse, PatchNoteResponses, Posted, PostNoteData, PostNoteError, PostNoteErrors, PostNoteResponse, PostNoteResponses, PutFeedLicenseData, PutFeedLicenseError, PutFeedLicenseErrors, PutFeedLicenseResponse, PutFeedLicenseResponses, ReadFeed, RecoverFeedPasswordData, RecoverFeedPasswordError, RecoverFeedPasswordErrors, RecoverFeedPasswordResponse, RecoverFeedPasswordResponses, RecoveryJson, RemoveFeedImageData, RemoveFeedImageError, RemoveFeedImageErrors, RemoveFeedImageResponse, RemoveFeedImageResponses, RemoveFeedPasswordData, RemoveFeedPasswordError, RemoveFeedPasswordErrors, RemoveFeedPasswordResponse, RemoveFeedPasswordResponses, SetFeedImageData, SetFeedImageError, SetFeedImageErrors, SetFeedImageResponse, SetFeedImageResponses, UpdateFeedData, UpdateFeedError, UpdateFeedErrors, UpdateFeedResponse, UpdateFeedResponses } from './types.gen.js';
|
|
1
|
+
export { changeFeedPassword, createFeed, deleteFeed, deleteFeedLicense, deleteNote, editNote, getFeed, getFile, getLicenses, getNote, getOpenApi, getReadFeed, getReadNote, listNotes, listReadNotes, type Options, patchNote, postNote, putFeedLicense, recoverFeedPassword, removeFeedImage, removeFeedPassword, setFeedImage, updateFeed } from './sdk.gen.js';
|
|
2
|
+
export type { ChangeFeedPasswordData, ChangeFeedPasswordError, ChangeFeedPasswordErrors, ChangeFeedPasswordResponse, ChangeFeedPasswordResponses, ClientOptions, Created, CreateFeedData, CreateFeedError, CreateFeedErrors, CreateFeedJson, CreateFeedResponse, CreateFeedResponses, DeleteFeedData, DeleteFeedError, DeleteFeedErrors, DeleteFeedLicenseData, DeleteFeedLicenseError, DeleteFeedLicenseErrors, DeleteFeedLicenseResponse, DeleteFeedLicenseResponses, DeleteFeedResponse, DeleteFeedResponses, DeleteNoteData, DeleteNoteError, DeleteNoteErrors, DeleteNoteResponse, DeleteNoteResponses, EditNoteData, EditNoteError, EditNoteErrors, EditNoteResponse, EditNoteResponses, Error, Feed, FeedSettings, FreeTier, GetFeedData, GetFeedError, GetFeedErrors, GetFeedResponse, GetFeedResponses, GetFileData, GetFileError, GetFileErrors, GetFileResponse, GetFileResponses, GetLicensesData, GetLicensesError, GetLicensesErrors, GetLicensesResponse, GetLicensesResponses, GetNoteData, GetNoteError, GetNoteErrors, GetNoteResponse, GetNoteResponses, GetOpenApiData, GetOpenApiResponse, GetOpenApiResponses, GetReadFeedData, GetReadFeedError, GetReadFeedErrors, GetReadFeedResponse, GetReadFeedResponses, GetReadNoteData, GetReadNoteError, GetReadNoteErrors, GetReadNoteResponse, GetReadNoteResponses, LicenseKey, Licenses, ListNotesData, ListNotesError, ListNotesErrors, ListNotesResponse, ListNotesResponses, ListReadNotesData, ListReadNotesError, ListReadNotesErrors, ListReadNotesResponse, ListReadNotesResponses, MultipartNote, Note, NoteEdited, NoteList, NoteMeta, PasswordJson, PatchNoteData, PatchNoteError, PatchNoteErrors, PatchNoteResponse, PatchNoteResponses, Posted, PostNoteData, PostNoteError, PostNoteErrors, PostNoteResponse, PostNoteResponses, PutFeedLicenseData, PutFeedLicenseError, PutFeedLicenseErrors, PutFeedLicenseResponse, PutFeedLicenseResponses, ReadFeed, RecoverFeedPasswordData, RecoverFeedPasswordError, RecoverFeedPasswordErrors, RecoverFeedPasswordResponse, RecoverFeedPasswordResponses, RecoveryJson, RemoveFeedImageData, RemoveFeedImageError, RemoveFeedImageErrors, RemoveFeedImageResponse, RemoveFeedImageResponses, RemoveFeedPasswordData, RemoveFeedPasswordError, RemoveFeedPasswordErrors, RemoveFeedPasswordResponse, RemoveFeedPasswordResponses, SetFeedImageData, SetFeedImageError, SetFeedImageErrors, SetFeedImageResponse, SetFeedImageResponses, UpdateFeedData, UpdateFeedError, UpdateFeedErrors, UpdateFeedResponse, UpdateFeedResponses } 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 { changeFeedPassword, createFeed, deleteFeed, deleteFeedLicense, deleteNote, editNote, getFeed, getLicenses, getNote, getOpenApi, getReadFeed, getReadNote, listNotes, listReadNotes, patchNote, postNote, putFeedLicense, recoverFeedPassword, removeFeedImage, removeFeedPassword, setFeedImage, updateFeed } from './sdk.gen.js';
|
|
2
|
+
export { changeFeedPassword, createFeed, deleteFeed, deleteFeedLicense, deleteNote, editNote, getFeed, getFile, getLicenses, getNote, getOpenApi, getReadFeed, getReadNote, listNotes, listReadNotes, patchNote, postNote, putFeedLicense, recoverFeedPassword, removeFeedImage, removeFeedPassword, setFeedImage, updateFeed } 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 { ChangeFeedPasswordData, ChangeFeedPasswordErrors, ChangeFeedPasswordResponses, CreateFeedData, CreateFeedErrors, CreateFeedResponses, DeleteFeedData, DeleteFeedErrors, DeleteFeedLicenseData, DeleteFeedLicenseErrors, DeleteFeedLicenseResponses, DeleteFeedResponses, DeleteNoteData, DeleteNoteErrors, DeleteNoteResponses, EditNoteData, EditNoteErrors, EditNoteResponses, GetFeedData, GetFeedErrors, GetFeedResponses, GetLicensesData, GetLicensesErrors, GetLicensesResponses, GetNoteData, GetNoteErrors, GetNoteResponses, GetOpenApiData, GetOpenApiResponses, GetReadFeedData, GetReadFeedErrors, GetReadFeedResponses, GetReadNoteData, GetReadNoteErrors, GetReadNoteResponses, ListNotesData, ListNotesErrors, ListNotesResponses, ListReadNotesData, ListReadNotesErrors, ListReadNotesResponses, PatchNoteData, PatchNoteErrors, PatchNoteResponses, PostNoteData, PostNoteErrors, PostNoteResponses, PutFeedLicenseData, PutFeedLicenseErrors, PutFeedLicenseResponses, RecoverFeedPasswordData, RecoverFeedPasswordErrors, RecoverFeedPasswordResponses, RemoveFeedImageData, RemoveFeedImageErrors, RemoveFeedImageResponses, RemoveFeedPasswordData, RemoveFeedPasswordErrors, RemoveFeedPasswordResponses, SetFeedImageData, SetFeedImageErrors, SetFeedImageResponses, UpdateFeedData, UpdateFeedErrors, UpdateFeedResponses } from './types.gen.js';
|
|
2
|
+
import type { ChangeFeedPasswordData, ChangeFeedPasswordErrors, ChangeFeedPasswordResponses, CreateFeedData, CreateFeedErrors, CreateFeedResponses, DeleteFeedData, DeleteFeedErrors, DeleteFeedLicenseData, DeleteFeedLicenseErrors, DeleteFeedLicenseResponses, DeleteFeedResponses, DeleteNoteData, DeleteNoteErrors, DeleteNoteResponses, EditNoteData, EditNoteErrors, EditNoteResponses, GetFeedData, GetFeedErrors, GetFeedResponses, GetFileData, GetFileErrors, GetFileResponses, GetLicensesData, GetLicensesErrors, GetLicensesResponses, GetNoteData, GetNoteErrors, GetNoteResponses, GetOpenApiData, GetOpenApiResponses, GetReadFeedData, GetReadFeedErrors, GetReadFeedResponses, GetReadNoteData, GetReadNoteErrors, GetReadNoteResponses, ListNotesData, ListNotesErrors, ListNotesResponses, ListReadNotesData, ListReadNotesErrors, ListReadNotesResponses, PatchNoteData, PatchNoteErrors, PatchNoteResponses, PostNoteData, PostNoteErrors, PostNoteResponses, PutFeedLicenseData, PutFeedLicenseErrors, PutFeedLicenseResponses, RecoverFeedPasswordData, RecoverFeedPasswordErrors, RecoverFeedPasswordResponses, RemoveFeedImageData, RemoveFeedImageErrors, RemoveFeedImageResponses, RemoveFeedPasswordData, RemoveFeedPasswordErrors, RemoveFeedPasswordResponses, SetFeedImageData, SetFeedImageErrors, SetFeedImageResponses, UpdateFeedData, UpdateFeedErrors, UpdateFeedResponses } 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
|
|
@@ -47,6 +47,12 @@ export declare const patchNote: <ThrowOnError extends boolean = false>(options:
|
|
|
47
47
|
* The body is the new file, with the same rules as posting: a `Content-Type` that is one of the accepted types, a body that is what it declares. A note keeps its type, so the type must be the note's own (`415` otherwise). An image is stored processed, not as sent: turned the way its EXIF orientation says, scaled to at most 2560 px on its long side, encoded again in its own format (JPEG and WebP at quality 85, PNG lossless, an animated GIF or WebP keeps its frames), and without metadata (EXIF, GPS position, XMP, comments). Send it full size; one of more than 100 megapixels is `413`, and a body that does not decode as the image it declares is `415`. Id, creation time and metadata stay: the title of a markdown note without one set follows the new text. Change the title, alt text or tags with `PATCH`. Needs the feed's password if it has one, and counts against the post rate limit. Read links can't edit. A markdown note with its pictures is one `multipart/form-data` request: a `text` part (the markdown, a field or a file part; a file part keeps its line breaks, a field's are sent as CRLF), `file` parts (up to 10 pictures, each with its file name and image `Content-Type`) and `alt.<file name>` fields. The pictures are stored first, each as its own note named by its file name, then the text with its references to them (``, `[x]: chart.png`, as written or percent-decoded) swapped for the stored files; a picture it never refers to is appended as ``. Several pictures may have the same file name (a phone calls every photo `image.jpg`): each is stored, and they are appended, but a text that refers to such a name is 400. Everything is checked before the first write, and a failed write removes what the request stored: all or nothing. `X-Note-Alt` and `X-Note-Name` are 400. The answer has `attachments`, the stored pictures in the order of the `file` parts. On a `PUT` the `text` part is required and the note must be a markdown note; the note keeps its own title and tags, `X-Note-Tags` goes on the new pictures. A raw body ignores `X-Note-Tags`. The note is looked up first: a missing note is `404` and an image note `415` whatever the body holds.
|
|
48
48
|
*/
|
|
49
49
|
export declare const editNote: <ThrowOnError extends boolean = false>(options: Options<EditNoteData, ThrowOnError>) => RequestResult<EditNoteResponses, EditNoteErrors, ThrowOnError>;
|
|
50
|
+
/**
|
|
51
|
+
* Get one of the feed's files
|
|
52
|
+
*
|
|
53
|
+
* A note's file by its own name (`<id>.<ext>`, a note's `file`), for whoever may post to the feed: also a draft's or a scheduled note's, which the read link (`file_url`) does not serve until readers may see them, so a post with pictures can be checked before it goes out. The body is the file's bytes, with the `Content-Type` of its extension and an `ETag` (`If-None-Match` gives `304`). Files by any other name, as the read link has them, are not served here.
|
|
54
|
+
*/
|
|
55
|
+
export declare const getFile: <ThrowOnError extends boolean = false>(options: Options<GetFileData, ThrowOnError>) => RequestResult<GetFileResponses, GetFileErrors, ThrowOnError>;
|
|
50
56
|
/**
|
|
51
57
|
* Delete a feed
|
|
52
58
|
*
|
|
@@ -68,7 +74,7 @@ export declare const createFeed: <ThrowOnError extends boolean = false>(options:
|
|
|
68
74
|
/**
|
|
69
75
|
* Change a feed's settings
|
|
70
76
|
*
|
|
71
|
-
* Replaces both the title (at most 100 characters) and the description (at most 500); surrounding whitespace is trimmed and control and text-direction override characters are refused. `show_sender` (default true) shows who posted each note to readers; omitted leaves it as it is. `read_id` gives the feed another read link (3 to 64 characters: a-z, 0-9, - and _; empty for a random one): the old id is freed and answers like an unknown read id until another feed takes it, and the notes are not edited (a relative image link follows the new id, a full URL does not). A short readable read id is guessable, so protect the feed with a password if that matters. An instance can turn chosen read ids off (NOTEFEED_ALLOW_CUSTOM_IDS=0): then only an empty `read_id` is accepted. `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.
|
|
77
|
+
* Replaces both the title (at most 100 characters) and the description (at most 500); surrounding whitespace is trimmed and control and text-direction override characters are refused. `show_sender` (default true) shows who posted each note to readers; omitted leaves it as it is. `read_id` gives the feed another read link (3 to 64 characters: a-z, 0-9, - and _; empty for a random one): the old id is freed and answers like an unknown read id until another feed takes it, and the notes are not edited (a relative image link follows the new id, a full URL does not). A short readable read id is guessable, so protect the feed with a password if that matters. An instance can turn chosen read ids off (NOTEFEED_ALLOW_CUSTOM_IDS=0): then only an empty `read_id` is accepted. `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. `name` renames the feed (#350), after everything else is saved: the answer is the feed under its new name, and the old name answers like any unused one from then on. 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.
|
|
72
78
|
*/
|
|
73
79
|
export declare const updateFeed: <ThrowOnError extends boolean = false>(options: Options<UpdateFeedData, ThrowOnError>) => RequestResult<UpdateFeedResponses, UpdateFeedErrors, ThrowOnError>;
|
|
74
80
|
/**
|
|
@@ -72,6 +72,16 @@ export const editNote = (options) => (options.client ?? client).put({
|
|
|
72
72
|
...options.headers
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
|
+
/**
|
|
76
|
+
* Get one of the feed's files
|
|
77
|
+
*
|
|
78
|
+
* A note's file by its own name (`<id>.<ext>`, a note's `file`), for whoever may post to the feed: also a draft's or a scheduled note's, which the read link (`file_url`) does not serve until readers may see them, so a post with pictures can be checked before it goes out. The body is the file's bytes, with the `Content-Type` of its extension and an `ETag` (`If-None-Match` gives `304`). Files by any other name, as the read link has them, are not served here.
|
|
79
|
+
*/
|
|
80
|
+
export const getFile = (options) => (options.client ?? client).get({
|
|
81
|
+
security: [{ scheme: 'bearer', type: 'http' }],
|
|
82
|
+
url: '/api/v1/feeds/{feed}/files/{file}',
|
|
83
|
+
...options
|
|
84
|
+
});
|
|
75
85
|
/**
|
|
76
86
|
* Delete a feed
|
|
77
87
|
*
|
|
@@ -109,7 +119,7 @@ export const createFeed = (options) => (options.client ?? client).post({
|
|
|
109
119
|
/**
|
|
110
120
|
* Change a feed's settings
|
|
111
121
|
*
|
|
112
|
-
* Replaces both the title (at most 100 characters) and the description (at most 500); surrounding whitespace is trimmed and control and text-direction override characters are refused. `show_sender` (default true) shows who posted each note to readers; omitted leaves it as it is. `read_id` gives the feed another read link (3 to 64 characters: a-z, 0-9, - and _; empty for a random one): the old id is freed and answers like an unknown read id until another feed takes it, and the notes are not edited (a relative image link follows the new id, a full URL does not). A short readable read id is guessable, so protect the feed with a password if that matters. An instance can turn chosen read ids off (NOTEFEED_ALLOW_CUSTOM_IDS=0): then only an empty `read_id` is accepted. `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.
|
|
122
|
+
* Replaces both the title (at most 100 characters) and the description (at most 500); surrounding whitespace is trimmed and control and text-direction override characters are refused. `show_sender` (default true) shows who posted each note to readers; omitted leaves it as it is. `read_id` gives the feed another read link (3 to 64 characters: a-z, 0-9, - and _; empty for a random one): the old id is freed and answers like an unknown read id until another feed takes it, and the notes are not edited (a relative image link follows the new id, a full URL does not). A short readable read id is guessable, so protect the feed with a password if that matters. An instance can turn chosen read ids off (NOTEFEED_ALLOW_CUSTOM_IDS=0): then only an empty `read_id` is accepted. `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. `name` renames the feed (#350), after everything else is saved: the answer is the feed under its new name, and the old name answers like any unused one from then on. 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.
|
|
113
123
|
*/
|
|
114
124
|
export const updateFeed = (options) => (options.client ?? client).put({
|
|
115
125
|
security: [{ scheme: 'bearer', type: 'http' }],
|
|
@@ -7,7 +7,7 @@ export type Note = {
|
|
|
7
7
|
*/
|
|
8
8
|
id: string;
|
|
9
9
|
/**
|
|
10
|
-
* The media type of the note's file: `text/markdown`, `image/png`, `image/jpeg`, `image/gif` or `image/webp`
|
|
10
|
+
* The media type of the note's file: `text/markdown`, `image/png`, `image/jpeg`, `image/gif` or `image/webp`; `application/x-notefeed-removed` for the operator's mark (see `removed`)
|
|
11
11
|
*/
|
|
12
12
|
type: string;
|
|
13
13
|
/**
|
|
@@ -66,6 +66,10 @@ export type Note = {
|
|
|
66
66
|
* Present, and true, for a damaged note: its stored copy can't be decrypted. A list shows it in its place, with its id, file, type and time; its title and tags are empty, its size 0, it has no content, and reading it alone is a 500 with the code `unreadable`. Deleting it works. Absent for every other note
|
|
67
67
|
*/
|
|
68
68
|
unreadable?: true;
|
|
69
|
+
/**
|
|
70
|
+
* Present, and true, for the mark the operator left where a post was removed for breaking the content rules (type `application/x-notefeed-removed`): it has the removed note's id and date, no content, an empty title, size 0, and `file_url` null; getting it alone is a 410 with the code `removed`, and so is any edit. Deleting it works; the post does not come back. Absent for every other note
|
|
71
|
+
*/
|
|
72
|
+
removed?: true;
|
|
69
73
|
};
|
|
70
74
|
export type NoteList = {
|
|
71
75
|
/**
|
|
@@ -91,6 +95,10 @@ export type Created = {
|
|
|
91
95
|
* 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
|
|
92
96
|
*/
|
|
93
97
|
read_url: string | null;
|
|
98
|
+
/**
|
|
99
|
+
* The same feed as Atom (RFC 4287), beside the RSS link; null exactly when read_url is
|
|
100
|
+
*/
|
|
101
|
+
atom_url: string | null;
|
|
94
102
|
/**
|
|
95
103
|
* The note's file name, `<id>.<extension>`. For an image note, pass it as a feed's `image` setting
|
|
96
104
|
*/
|
|
@@ -121,6 +129,10 @@ export type Posted = {
|
|
|
121
129
|
* 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
|
|
122
130
|
*/
|
|
123
131
|
read_url: string | null;
|
|
132
|
+
/**
|
|
133
|
+
* The same feed as Atom (RFC 4287), beside the RSS link; null exactly when read_url is
|
|
134
|
+
*/
|
|
135
|
+
atom_url: string | null;
|
|
124
136
|
/**
|
|
125
137
|
* The note's file name, `<id>.<extension>`. For an image note, pass it as a feed's `image` setting
|
|
126
138
|
*/
|
|
@@ -144,7 +156,7 @@ export type NoteEdited = {
|
|
|
144
156
|
*/
|
|
145
157
|
id: string;
|
|
146
158
|
/**
|
|
147
|
-
* The media type of the note's file: `text/markdown`, `image/png`, `image/jpeg`, `image/gif` or `image/webp`
|
|
159
|
+
* The media type of the note's file: `text/markdown`, `image/png`, `image/jpeg`, `image/gif` or `image/webp`; `application/x-notefeed-removed` for the operator's mark (see `removed`)
|
|
148
160
|
*/
|
|
149
161
|
type: string;
|
|
150
162
|
/**
|
|
@@ -203,6 +215,10 @@ export type NoteEdited = {
|
|
|
203
215
|
* Present, and true, for a damaged note: its stored copy can't be decrypted. A list shows it in its place, with its id, file, type and time; its title and tags are empty, its size 0, it has no content, and reading it alone is a 500 with the code `unreadable`. Deleting it works. Absent for every other note
|
|
204
216
|
*/
|
|
205
217
|
unreadable?: true;
|
|
218
|
+
/**
|
|
219
|
+
* Present, and true, for the mark the operator left where a post was removed for breaking the content rules (type `application/x-notefeed-removed`): it has the removed note's id and date, no content, an empty title, size 0, and `file_url` null; getting it alone is a 410 with the code `removed`, and so is any edit. Deleting it works; the post does not come back. Absent for every other note
|
|
220
|
+
*/
|
|
221
|
+
removed?: true;
|
|
206
222
|
/**
|
|
207
223
|
* A multipart request's pictures, one per `file` part, in their order; absent for a raw body
|
|
208
224
|
*/
|
|
@@ -307,14 +323,18 @@ export type FeedSettings = {
|
|
|
307
323
|
* A new read id (3 to 64 characters: a-z, 0-9, - and _), empty for a random one; omitted leaves it as it is. The old read link stops showing this feed, and may later show another one. Notes are not edited: a relative image link (``) follows the new id, a full URL keeps the old one and is yours to change. Reserved feeds keep theirs. 409 when it is taken
|
|
308
324
|
*/
|
|
309
325
|
read_id?: string;
|
|
326
|
+
/**
|
|
327
|
+
* A new name for the feed (1 to 64 characters: a-z, 0-9, - and _); omitted, empty or the current one leaves it as it is. Everything goes with it: notes, files, settings, password, license and read link. The old name stops working at once and is free: a post to it later creates a new feed, without an error. Change NOTEFEED_FEED, CI secrets, scripts and MCP configurations before they next run (a browser that unlocked the feed unlocks it again). A short name is guessable: protect the feed with a password if that matters. Reserved feeds keep theirs. 409 when it is taken
|
|
328
|
+
*/
|
|
329
|
+
name?: string;
|
|
310
330
|
};
|
|
311
331
|
export type FreeTier = {
|
|
312
332
|
/**
|
|
313
|
-
* The feed's
|
|
333
|
+
* The feed's notes now: texts, images and the operator's marks alike
|
|
314
334
|
*/
|
|
315
335
|
notes: number;
|
|
316
336
|
/**
|
|
317
|
-
* How many
|
|
337
|
+
* How many notes a free feed keeps; past it, each new note drops the oldest one, of any kind
|
|
318
338
|
*/
|
|
319
339
|
cap: number;
|
|
320
340
|
};
|
|
@@ -339,6 +359,10 @@ export type Feed = {
|
|
|
339
359
|
* 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
|
|
340
360
|
*/
|
|
341
361
|
read_url: string | null;
|
|
362
|
+
/**
|
|
363
|
+
* The same feed as Atom (RFC 4287), beside the RSS link; null exactly when read_url is
|
|
364
|
+
*/
|
|
365
|
+
atom_url: string | null;
|
|
342
366
|
/**
|
|
343
367
|
* The feed's title image (absolute URL, served under the read id), or null
|
|
344
368
|
*/
|
|
@@ -347,6 +371,10 @@ export type Feed = {
|
|
|
347
371
|
* Whether readers see who posted each note
|
|
348
372
|
*/
|
|
349
373
|
show_sender: boolean;
|
|
374
|
+
/**
|
|
375
|
+
* The iPhone Shortcut "Send to notefeed": opened on an iPhone, it adds notefeed to the share sheet; at setup it asks for the server's address, this feed's name, its password and, optional, the server password
|
|
376
|
+
*/
|
|
377
|
+
shortcut_url: string;
|
|
350
378
|
/**
|
|
351
379
|
* A feed without a license on an instance that sells them: its notes against the free tier's cap. null when no cap applies (a licensed feed, or an instance that sells no licenses)
|
|
352
380
|
*/
|
|
@@ -660,6 +688,10 @@ export type GetNoteErrors = {
|
|
|
660
688
|
* No such note
|
|
661
689
|
*/
|
|
662
690
|
404: Error;
|
|
691
|
+
/**
|
|
692
|
+
* The operator removed this note (`removed`, #159): for good, also once its mark is deleted; the mark itself can't be edited
|
|
693
|
+
*/
|
|
694
|
+
410: Error;
|
|
663
695
|
/**
|
|
664
696
|
* Too many wrong passwords from this client
|
|
665
697
|
*/
|
|
@@ -715,6 +747,10 @@ export type PatchNoteErrors = {
|
|
|
715
747
|
* The note, or a picture posted with it, is the feed's title image, so it cannot become a draft (`title_image`)
|
|
716
748
|
*/
|
|
717
749
|
409: Error;
|
|
750
|
+
/**
|
|
751
|
+
* The operator removed this note (`removed`, #159): for good, also once its mark is deleted; the mark itself can't be edited
|
|
752
|
+
*/
|
|
753
|
+
410: Error;
|
|
718
754
|
/**
|
|
719
755
|
* Content-Type is not application/json
|
|
720
756
|
*/
|
|
@@ -785,6 +821,10 @@ export type EditNoteErrors = {
|
|
|
785
821
|
* No such note
|
|
786
822
|
*/
|
|
787
823
|
404: Error;
|
|
824
|
+
/**
|
|
825
|
+
* The operator removed this note (`removed`, #159): for good, also once its mark is deleted; the mark itself can't be edited
|
|
826
|
+
*/
|
|
827
|
+
410: Error;
|
|
788
828
|
/**
|
|
789
829
|
* Markdown over 102400 bytes, or an image over NOTEFEED_MAX_IMAGE_BYTES or 100 megapixels (each picture of a multipart body too), or a multipart body over 102400 bytes plus 10 images plus 64 KiB, and never over 64 MiB
|
|
790
830
|
*/
|
|
@@ -818,6 +858,61 @@ export type EditNoteResponses = {
|
|
|
818
858
|
200: NoteEdited;
|
|
819
859
|
};
|
|
820
860
|
export type EditNoteResponse = EditNoteResponses[keyof EditNoteResponses];
|
|
861
|
+
export type GetFileData = {
|
|
862
|
+
body?: never;
|
|
863
|
+
headers?: {
|
|
864
|
+
/**
|
|
865
|
+
* 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.
|
|
866
|
+
*/
|
|
867
|
+
'X-Feed-Password'?: string;
|
|
868
|
+
};
|
|
869
|
+
path: {
|
|
870
|
+
/**
|
|
871
|
+
* The feed's name. It is the write key: anyone who knows it can post.
|
|
872
|
+
*/
|
|
873
|
+
feed: string;
|
|
874
|
+
/**
|
|
875
|
+
* A note's file name, `<id>.<ext>` (its `file`)
|
|
876
|
+
*/
|
|
877
|
+
file: string;
|
|
878
|
+
};
|
|
879
|
+
query?: never;
|
|
880
|
+
url: '/api/v1/feeds/{feed}/files/{file}';
|
|
881
|
+
};
|
|
882
|
+
export type GetFileErrors = {
|
|
883
|
+
/**
|
|
884
|
+
* Invalid or reserved feed name
|
|
885
|
+
*/
|
|
886
|
+
400: Error;
|
|
887
|
+
/**
|
|
888
|
+
* The instance has a password, or the feed has its own, and it is missing or wrong
|
|
889
|
+
*/
|
|
890
|
+
401: Error;
|
|
891
|
+
/**
|
|
892
|
+
* No such file
|
|
893
|
+
*/
|
|
894
|
+
404: Error;
|
|
895
|
+
/**
|
|
896
|
+
* The operator removed this note (`removed`, #159): for good, also once its mark is deleted; the mark itself can't be edited
|
|
897
|
+
*/
|
|
898
|
+
410: Error;
|
|
899
|
+
/**
|
|
900
|
+
* Too many wrong passwords from this client
|
|
901
|
+
*/
|
|
902
|
+
429: Error;
|
|
903
|
+
/**
|
|
904
|
+
* The key service is unreachable: the instance is down for maintenance; try again after Retry-After
|
|
905
|
+
*/
|
|
906
|
+
503: Error;
|
|
907
|
+
};
|
|
908
|
+
export type GetFileError = GetFileErrors[keyof GetFileErrors];
|
|
909
|
+
export type GetFileResponses = {
|
|
910
|
+
/**
|
|
911
|
+
* The file's bytes; `Content-Type` is the file's own (an image, `text/markdown`, …)
|
|
912
|
+
*/
|
|
913
|
+
200: Blob | File;
|
|
914
|
+
};
|
|
915
|
+
export type GetFileResponse = GetFileResponses[keyof GetFileResponses];
|
|
821
916
|
export type DeleteFeedData = {
|
|
822
917
|
body?: never;
|
|
823
918
|
headers?: {
|
|
@@ -992,7 +1087,7 @@ export type UpdateFeedErrors = {
|
|
|
992
1087
|
*/
|
|
993
1088
|
404: Error;
|
|
994
1089
|
/**
|
|
995
|
-
* The read id belongs to another feed or is held back
|
|
1090
|
+
* The read id or the new name belongs to another feed, or is held back
|
|
996
1091
|
*/
|
|
997
1092
|
409: Error;
|
|
998
1093
|
/**
|
|
@@ -1478,7 +1573,7 @@ export type GetReadNoteErrors = {
|
|
|
1478
1573
|
*/
|
|
1479
1574
|
404: Error;
|
|
1480
1575
|
/**
|
|
1481
|
-
* The operator removed the feed this read id belonged to (`removed`)
|
|
1576
|
+
* The operator removed the feed this read id belonged to, or this note (`removed`)
|
|
1482
1577
|
*/
|
|
1483
1578
|
410: Error;
|
|
1484
1579
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "notefeed",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Client and CLI for notefeed, a self-hosted inbox for markdown notes that you read back as RSS.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Marcel Bruckner",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"dist"
|
|
28
28
|
],
|
|
29
29
|
"engines": {
|
|
30
|
-
"node": ">=
|
|
30
|
+
"node": ">=22"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"build": "tsc",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"url": "https://github.com/notefeed/notefeed/issues"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@types/node": "^
|
|
47
|
+
"@types/node": "^22",
|
|
48
48
|
"typescript": "^7.0",
|
|
49
|
-
"vitest": "^
|
|
49
|
+
"vitest": "^5.0"
|
|
50
50
|
}
|
|
51
51
|
}
|