// retoor <retoor@molodetz.nl>
export class DevRant {
constructor(baseUrl, username, password) {
this.baseUrl = baseUrl.replace(/\/$/, "");
this.username = username;
this.password = password;
this.auth = {};
}
_url(path, params) {
const url = new URL(`${this.baseUrl}/api/${path.replace(/^\//, "")}`);
for (const [key, value] of Object.entries(params || {})) {
url.searchParams.set(key, value);
}
return url;
}
async _request(method, path, params = {}, body = null) {
const merged = { ...params, ...this.auth };
const headers = { Accept: "application/json" };
let url;
const init = { method, headers };
if (method === "GET" || method === "DELETE") {
url = this._url(path, merged);
} else {
url = this._url(path);
headers["Content-Type"] = "application/x-www-form-urlencoded";
init.body = new URLSearchParams({ ...merged, ...(body || {}) }).toString();
}
const response = await fetch(url, init);
return response.json();
}
async login() {
const result = await this._request("POST", "users/auth-token", {}, {
username: this.username,
password: this.password,
});
if (!result.success) throw new Error(result.error || "login failed");
const token = result.auth_token;
this.auth = { user_id: token.user_id, token_id: token.id, token_key: token.key };
return this.auth;
}
register(email) {
return this._request("POST", "users", {}, {
username: this.username,
email,
password: this.password,
});
}
async rants(sort = "recent", limit = 20, skip = 0) {
const result = await this._request("GET", "devrant/rants", { sort, limit, skip });
return result.rants || [];
}
rant(rantId) {
return this._request("GET", `devrant/rants/${rantId}`);
}
async search(term) {
return (await this._request("GET", "devrant/search", { term })).results || [];
}
async userId(username) {
return (await this._request("GET", "get-user-id", { username })).user_id;
}
async profile(userId) {
return (await this._request("GET", `users/${userId}`)).profile;
}
async notifs() {
return (await this._request("GET", "users/me/notif-feed")).data || {};
}
clearNotifs() {
return this._request("DELETE", "users/me/notif-feed");
}
editProfile(fields) {
return this._request("POST", "users/me/edit-profile", {}, fields);
}
postRant(text, tags = "") {
return this._request("POST", "devrant/rants", {}, { rant: text, tags });
}
editRant(rantId, text, tags = "") {
return this._request("POST", `devrant/rants/${rantId}`, {}, { rant: text, tags });
}
deleteRant(rantId) {
return this._request("DELETE", `devrant/rants/${rantId}`);
}
voteRant(rantId, vote) {
return this._request("POST", `devrant/rants/${rantId}/vote`, {}, { vote });
}
favorite(rantId) {
return this._request("POST", `devrant/rants/${rantId}/favorite`);
}
unfavorite(rantId) {
return this._request("POST", `devrant/rants/${rantId}/unfavorite`);
}
comment(rantId, text) {
return this._request("POST", `devrant/rants/${rantId}/comments`, {}, { comment: text });
}
voteComment(commentId, vote) {
return this._request("POST", `comments/${commentId}/vote`, {}, { vote });
}
}
export function fromEnv() {
return new DevRant(
process.env.DEVRANT_BASE || "http://localhost:10500",
process.env.DEVRANT_USERNAME,
process.env.DEVRANT_PASSWORD,
);
}