initial
This commit is contained in:
5
ts/00_commitinfo_data.ts
Normal file
5
ts/00_commitinfo_data.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export const commitinfo = {
|
||||
name: '@apiclient.xyz/bookstack',
|
||||
version: '1.0.0',
|
||||
description: 'A TypeScript API client for BookStack, providing easy access to books, chapters, pages, shelves, and more.',
|
||||
};
|
||||
592
ts/bookstack.classes.account.ts
Normal file
592
ts/bookstack.classes.account.ts
Normal file
@@ -0,0 +1,592 @@
|
||||
import * as plugins from './bookstack.plugins.js';
|
||||
import type {
|
||||
ITestConnectionResult,
|
||||
IBookStackListParams,
|
||||
IBookStackListResponse,
|
||||
IBookStackBook,
|
||||
IBookStackChapter,
|
||||
IBookStackPage,
|
||||
IBookStackShelf,
|
||||
IBookStackAttachment,
|
||||
IBookStackComment,
|
||||
IBookStackImage,
|
||||
IBookStackUser,
|
||||
IBookStackRole,
|
||||
IBookStackSearchResult,
|
||||
IBookStackAuditLogEntry,
|
||||
IBookStackRecycleBinItem,
|
||||
IBookStackContentPermission,
|
||||
IBookStackSystemInfo,
|
||||
IBookStackTag,
|
||||
} from './bookstack.interfaces.js';
|
||||
import { BookStackBook } from './bookstack.classes.book.js';
|
||||
import { BookStackChapter } from './bookstack.classes.chapter.js';
|
||||
import { BookStackPage } from './bookstack.classes.page.js';
|
||||
import { BookStackShelf } from './bookstack.classes.shelf.js';
|
||||
import { autoPaginate } from './bookstack.helpers.js';
|
||||
|
||||
export class BookStackAccount {
|
||||
private baseUrl: string;
|
||||
private tokenId: string;
|
||||
private tokenSecret: string;
|
||||
|
||||
constructor(baseUrl: string, tokenId: string, tokenSecret: string) {
|
||||
this.baseUrl = baseUrl.replace(/\/+$/, '');
|
||||
this.tokenId = tokenId;
|
||||
this.tokenSecret = tokenSecret;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// HTTP helpers (internal)
|
||||
// ===========================================================================
|
||||
|
||||
/** @internal */
|
||||
async request<T = any>(
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
||||
path: string,
|
||||
data?: any,
|
||||
): Promise<T> {
|
||||
const url = `${this.baseUrl}/api${path}`;
|
||||
|
||||
let builder = plugins.smartrequest.SmartRequest.create()
|
||||
.url(url)
|
||||
.header('Authorization', `Token ${this.tokenId}:${this.tokenSecret}`)
|
||||
.header('Content-Type', 'application/json');
|
||||
|
||||
if (data) {
|
||||
builder = builder.json(data);
|
||||
}
|
||||
|
||||
let response: Awaited<ReturnType<typeof builder.get>>;
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
response = await builder.get();
|
||||
break;
|
||||
case 'POST':
|
||||
response = await builder.post();
|
||||
break;
|
||||
case 'PUT':
|
||||
response = await builder.put();
|
||||
break;
|
||||
case 'DELETE':
|
||||
response = await builder.delete();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`${method} ${path}: ${response.status} ${response.statusText} - ${errorText}`);
|
||||
}
|
||||
|
||||
try {
|
||||
return (await response.json()) as T;
|
||||
} catch {
|
||||
return undefined as unknown as T;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
async requestText(
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
||||
path: string,
|
||||
): Promise<string> {
|
||||
const url = `${this.baseUrl}/api${path}`;
|
||||
|
||||
let builder = plugins.smartrequest.SmartRequest.create()
|
||||
.url(url)
|
||||
.header('Authorization', `Token ${this.tokenId}:${this.tokenSecret}`)
|
||||
.header('Accept', 'text/plain');
|
||||
|
||||
let response: Awaited<ReturnType<typeof builder.get>>;
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
response = await builder.get();
|
||||
break;
|
||||
case 'POST':
|
||||
response = await builder.post();
|
||||
break;
|
||||
case 'PUT':
|
||||
response = await builder.put();
|
||||
break;
|
||||
case 'DELETE':
|
||||
response = await builder.delete();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`${method} ${path}: ${response.status} ${response.statusText} - ${errorText}`);
|
||||
}
|
||||
|
||||
return response.text();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
async requestBinary(path: string): Promise<Uint8Array> {
|
||||
const url = `${this.baseUrl}/api${path}`;
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
Authorization: `Token ${this.tokenId}:${this.tokenSecret}`,
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`GET ${path}: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
const buf = await response.arrayBuffer();
|
||||
return new Uint8Array(buf);
|
||||
}
|
||||
|
||||
/** @internal — build a URL with list query params */
|
||||
buildListUrl(basePath: string, opts?: IBookStackListParams): string {
|
||||
const params: string[] = [];
|
||||
if (opts?.count !== undefined) params.push(`count=${opts.count}`);
|
||||
if (opts?.offset !== undefined) params.push(`offset=${opts.offset}`);
|
||||
if (opts?.sort) params.push(`sort=${encodeURIComponent(opts.sort)}`);
|
||||
if (opts?.filter) {
|
||||
for (const [key, value] of Object.entries(opts.filter)) {
|
||||
params.push(`filter[${encodeURIComponent(key)}]=${encodeURIComponent(value)}`);
|
||||
}
|
||||
}
|
||||
return params.length > 0 ? `${basePath}?${params.join('&')}` : basePath;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Connection
|
||||
// ===========================================================================
|
||||
|
||||
public async testConnection(): Promise<ITestConnectionResult> {
|
||||
try {
|
||||
await this.request<IBookStackListResponse<IBookStackBook>>('GET', '/books?count=1');
|
||||
return { ok: true };
|
||||
} catch (err) {
|
||||
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
||||
}
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Books
|
||||
// ===========================================================================
|
||||
|
||||
public async getBooks(opts?: IBookStackListParams): Promise<BookStackBook[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackBook>>(
|
||||
'GET',
|
||||
this.buildListUrl('/books', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
).then((books) => books.map((b) => new BookStackBook(this, b)));
|
||||
}
|
||||
|
||||
public async getBook(id: number): Promise<BookStackBook> {
|
||||
const raw = await this.request<IBookStackBook>('GET', `/books/${id}`);
|
||||
return new BookStackBook(this, raw);
|
||||
}
|
||||
|
||||
public async createBook(data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
description_html?: string;
|
||||
tags?: IBookStackTag[];
|
||||
default_template_id?: number | null;
|
||||
}): Promise<BookStackBook> {
|
||||
const raw = await this.request<IBookStackBook>('POST', '/books', data);
|
||||
return new BookStackBook(this, raw);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Chapters
|
||||
// ===========================================================================
|
||||
|
||||
public async getChapters(opts?: IBookStackListParams): Promise<BookStackChapter[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackChapter>>(
|
||||
'GET',
|
||||
this.buildListUrl('/chapters', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
).then((chapters) => chapters.map((c) => new BookStackChapter(this, c)));
|
||||
}
|
||||
|
||||
public async getChapter(id: number): Promise<BookStackChapter> {
|
||||
const raw = await this.request<IBookStackChapter>('GET', `/chapters/${id}`);
|
||||
return new BookStackChapter(this, raw);
|
||||
}
|
||||
|
||||
public async createChapter(data: {
|
||||
book_id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
description_html?: string;
|
||||
tags?: IBookStackTag[];
|
||||
priority?: number;
|
||||
default_template_id?: number | null;
|
||||
}): Promise<BookStackChapter> {
|
||||
const raw = await this.request<IBookStackChapter>('POST', '/chapters', data);
|
||||
return new BookStackChapter(this, raw);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Pages
|
||||
// ===========================================================================
|
||||
|
||||
public async getPages(opts?: IBookStackListParams): Promise<BookStackPage[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackPage>>(
|
||||
'GET',
|
||||
this.buildListUrl('/pages', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
).then((pages) => pages.map((p) => new BookStackPage(this, p)));
|
||||
}
|
||||
|
||||
public async getPage(id: number): Promise<BookStackPage> {
|
||||
const raw = await this.request<IBookStackPage>('GET', `/pages/${id}`);
|
||||
return new BookStackPage(this, raw);
|
||||
}
|
||||
|
||||
public async createPage(data: {
|
||||
name: string;
|
||||
book_id?: number;
|
||||
chapter_id?: number;
|
||||
html?: string;
|
||||
markdown?: string;
|
||||
tags?: IBookStackTag[];
|
||||
priority?: number;
|
||||
}): Promise<BookStackPage> {
|
||||
const raw = await this.request<IBookStackPage>('POST', '/pages', data);
|
||||
return new BookStackPage(this, raw);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Shelves
|
||||
// ===========================================================================
|
||||
|
||||
public async getShelves(opts?: IBookStackListParams): Promise<BookStackShelf[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackShelf>>(
|
||||
'GET',
|
||||
this.buildListUrl('/shelves', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
).then((shelves) => shelves.map((s) => new BookStackShelf(this, s)));
|
||||
}
|
||||
|
||||
public async getShelf(id: number): Promise<BookStackShelf> {
|
||||
const raw = await this.request<IBookStackShelf>('GET', `/shelves/${id}`);
|
||||
return new BookStackShelf(this, raw);
|
||||
}
|
||||
|
||||
public async createShelf(data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
description_html?: string;
|
||||
books?: number[];
|
||||
tags?: IBookStackTag[];
|
||||
}): Promise<BookStackShelf> {
|
||||
const raw = await this.request<IBookStackShelf>('POST', '/shelves', data);
|
||||
return new BookStackShelf(this, raw);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Attachments
|
||||
// ===========================================================================
|
||||
|
||||
public async getAttachments(opts?: IBookStackListParams): Promise<IBookStackAttachment[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackAttachment>>(
|
||||
'GET',
|
||||
this.buildListUrl('/attachments', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
public async getAttachment(id: number): Promise<IBookStackAttachment> {
|
||||
return this.request<IBookStackAttachment>('GET', `/attachments/${id}`);
|
||||
}
|
||||
|
||||
public async createAttachment(data: {
|
||||
name: string;
|
||||
uploaded_to: number;
|
||||
link?: string;
|
||||
}): Promise<IBookStackAttachment> {
|
||||
return this.request<IBookStackAttachment>('POST', '/attachments', data);
|
||||
}
|
||||
|
||||
public async updateAttachment(id: number, data: {
|
||||
name?: string;
|
||||
uploaded_to?: number;
|
||||
link?: string;
|
||||
}): Promise<IBookStackAttachment> {
|
||||
return this.request<IBookStackAttachment>('PUT', `/attachments/${id}`, data);
|
||||
}
|
||||
|
||||
public async deleteAttachment(id: number): Promise<void> {
|
||||
await this.request('DELETE', `/attachments/${id}`);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Comments
|
||||
// ===========================================================================
|
||||
|
||||
public async getComments(opts?: IBookStackListParams): Promise<IBookStackComment[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackComment>>(
|
||||
'GET',
|
||||
this.buildListUrl('/comments', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
public async getComment(id: number): Promise<IBookStackComment> {
|
||||
return this.request<IBookStackComment>('GET', `/comments/${id}`);
|
||||
}
|
||||
|
||||
public async createComment(data: {
|
||||
page_id: number;
|
||||
html: string;
|
||||
reply_to?: number;
|
||||
content_ref?: string;
|
||||
}): Promise<IBookStackComment> {
|
||||
return this.request<IBookStackComment>('POST', '/comments', data);
|
||||
}
|
||||
|
||||
public async updateComment(id: number, data: {
|
||||
html?: string;
|
||||
archived?: boolean;
|
||||
}): Promise<IBookStackComment> {
|
||||
return this.request<IBookStackComment>('PUT', `/comments/${id}`, data);
|
||||
}
|
||||
|
||||
public async deleteComment(id: number): Promise<void> {
|
||||
await this.request('DELETE', `/comments/${id}`);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Image Gallery
|
||||
// ===========================================================================
|
||||
|
||||
public async getImages(opts?: IBookStackListParams): Promise<IBookStackImage[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackImage>>(
|
||||
'GET',
|
||||
this.buildListUrl('/image-gallery', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
public async getImage(id: number): Promise<IBookStackImage> {
|
||||
return this.request<IBookStackImage>('GET', `/image-gallery/${id}`);
|
||||
}
|
||||
|
||||
public async updateImage(id: number, data: {
|
||||
name?: string;
|
||||
}): Promise<IBookStackImage> {
|
||||
return this.request<IBookStackImage>('PUT', `/image-gallery/${id}`, data);
|
||||
}
|
||||
|
||||
public async deleteImage(id: number): Promise<void> {
|
||||
await this.request('DELETE', `/image-gallery/${id}`);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Users
|
||||
// ===========================================================================
|
||||
|
||||
public async getUsers(opts?: IBookStackListParams): Promise<IBookStackUser[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackUser>>(
|
||||
'GET',
|
||||
this.buildListUrl('/users', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
public async getUser(id: number): Promise<IBookStackUser> {
|
||||
return this.request<IBookStackUser>('GET', `/users/${id}`);
|
||||
}
|
||||
|
||||
public async createUser(data: {
|
||||
name: string;
|
||||
email: string;
|
||||
password?: string;
|
||||
roles?: number[];
|
||||
send_invite?: boolean;
|
||||
external_auth_id?: string;
|
||||
language?: string;
|
||||
}): Promise<IBookStackUser> {
|
||||
return this.request<IBookStackUser>('POST', '/users', data);
|
||||
}
|
||||
|
||||
public async updateUser(id: number, data: {
|
||||
name?: string;
|
||||
email?: string;
|
||||
password?: string;
|
||||
roles?: number[];
|
||||
external_auth_id?: string;
|
||||
language?: string;
|
||||
}): Promise<IBookStackUser> {
|
||||
return this.request<IBookStackUser>('PUT', `/users/${id}`, data);
|
||||
}
|
||||
|
||||
public async deleteUser(id: number, opts?: { migrate_ownership_id?: number }): Promise<void> {
|
||||
const path = opts?.migrate_ownership_id
|
||||
? `/users/${id}?migrate_ownership_id=${opts.migrate_ownership_id}`
|
||||
: `/users/${id}`;
|
||||
await this.request('DELETE', path);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Roles
|
||||
// ===========================================================================
|
||||
|
||||
public async getRoles(opts?: IBookStackListParams): Promise<IBookStackRole[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackRole>>(
|
||||
'GET',
|
||||
this.buildListUrl('/roles', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
public async getRole(id: number): Promise<IBookStackRole> {
|
||||
return this.request<IBookStackRole>('GET', `/roles/${id}`);
|
||||
}
|
||||
|
||||
public async createRole(data: {
|
||||
display_name: string;
|
||||
description?: string;
|
||||
mfa_enforced?: boolean;
|
||||
external_auth_id?: string;
|
||||
permissions?: string[];
|
||||
}): Promise<IBookStackRole> {
|
||||
return this.request<IBookStackRole>('POST', '/roles', data);
|
||||
}
|
||||
|
||||
public async updateRole(id: number, data: {
|
||||
display_name?: string;
|
||||
description?: string;
|
||||
mfa_enforced?: boolean;
|
||||
external_auth_id?: string;
|
||||
permissions?: string[];
|
||||
}): Promise<IBookStackRole> {
|
||||
return this.request<IBookStackRole>('PUT', `/roles/${id}`, data);
|
||||
}
|
||||
|
||||
public async deleteRole(id: number): Promise<void> {
|
||||
await this.request('DELETE', `/roles/${id}`);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Search
|
||||
// ===========================================================================
|
||||
|
||||
public async search(query: string, opts?: { page?: number; count?: number }): Promise<IBookStackSearchResult[]> {
|
||||
let url = `/search?query=${encodeURIComponent(query)}`;
|
||||
if (opts?.page) url += `&page=${opts.page}`;
|
||||
if (opts?.count) url += `&count=${opts.count}`;
|
||||
const result = await this.request<IBookStackListResponse<IBookStackSearchResult>>('GET', url);
|
||||
return result.data;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Audit Log
|
||||
// ===========================================================================
|
||||
|
||||
public async getAuditLog(opts?: IBookStackListParams): Promise<IBookStackAuditLogEntry[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackAuditLogEntry>>(
|
||||
'GET',
|
||||
this.buildListUrl('/audit-log', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Recycle Bin
|
||||
// ===========================================================================
|
||||
|
||||
public async getRecycleBinItems(opts?: IBookStackListParams): Promise<IBookStackRecycleBinItem[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.request<IBookStackListResponse<IBookStackRecycleBinItem>>(
|
||||
'GET',
|
||||
this.buildListUrl('/recycle-bin', { ...opts, offset, count }),
|
||||
),
|
||||
opts,
|
||||
);
|
||||
}
|
||||
|
||||
public async restoreRecycleBinItem(deletionId: number): Promise<{ restore_count: number }> {
|
||||
return this.request<{ restore_count: number }>('PUT', `/recycle-bin/${deletionId}`);
|
||||
}
|
||||
|
||||
public async destroyRecycleBinItem(deletionId: number): Promise<{ delete_count: number }> {
|
||||
return this.request<{ delete_count: number }>('DELETE', `/recycle-bin/${deletionId}`);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Content Permissions
|
||||
// ===========================================================================
|
||||
|
||||
public async getContentPermissions(
|
||||
contentType: 'page' | 'book' | 'chapter' | 'bookshelf',
|
||||
contentId: number,
|
||||
): Promise<IBookStackContentPermission> {
|
||||
return this.request<IBookStackContentPermission>(
|
||||
'GET',
|
||||
`/content-permissions/${contentType}/${contentId}`,
|
||||
);
|
||||
}
|
||||
|
||||
public async updateContentPermissions(
|
||||
contentType: 'page' | 'book' | 'chapter' | 'bookshelf',
|
||||
contentId: number,
|
||||
data: {
|
||||
owner_id?: number;
|
||||
role_permissions?: {
|
||||
role_id: number;
|
||||
view: boolean;
|
||||
create: boolean;
|
||||
update: boolean;
|
||||
delete: boolean;
|
||||
}[];
|
||||
fallback_permissions?: {
|
||||
inheriting: boolean;
|
||||
view?: boolean;
|
||||
create?: boolean;
|
||||
update?: boolean;
|
||||
delete?: boolean;
|
||||
};
|
||||
},
|
||||
): Promise<IBookStackContentPermission> {
|
||||
return this.request<IBookStackContentPermission>(
|
||||
'PUT',
|
||||
`/content-permissions/${contentType}/${contentId}`,
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// System
|
||||
// ===========================================================================
|
||||
|
||||
public async getSystemInfo(): Promise<IBookStackSystemInfo> {
|
||||
return this.request<IBookStackSystemInfo>('GET', '/system');
|
||||
}
|
||||
}
|
||||
155
ts/bookstack.classes.book.ts
Normal file
155
ts/bookstack.classes.book.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import type { BookStackAccount } from './bookstack.classes.account.js';
|
||||
import type {
|
||||
IBookStackBook,
|
||||
IBookStackChapter,
|
||||
IBookStackPage,
|
||||
IBookStackTag,
|
||||
IBookStackListParams,
|
||||
IBookStackListResponse,
|
||||
TBookStackExportFormat,
|
||||
} from './bookstack.interfaces.js';
|
||||
import { BookStackChapter } from './bookstack.classes.chapter.js';
|
||||
import { BookStackPage } from './bookstack.classes.page.js';
|
||||
import { autoPaginate } from './bookstack.helpers.js';
|
||||
|
||||
export class BookStackBook {
|
||||
public readonly id: number;
|
||||
public readonly name: string;
|
||||
public readonly slug: string;
|
||||
public readonly description: string;
|
||||
public readonly createdAt: string;
|
||||
public readonly updatedAt: string;
|
||||
public readonly createdBy: number;
|
||||
public readonly updatedBy: number;
|
||||
public readonly ownedBy: number;
|
||||
public readonly defaultTemplateId: number | null;
|
||||
public readonly tags: IBookStackTag[];
|
||||
|
||||
/** @internal */
|
||||
constructor(
|
||||
private accountRef: BookStackAccount,
|
||||
raw: IBookStackBook,
|
||||
) {
|
||||
this.id = raw.id;
|
||||
this.name = raw.name || '';
|
||||
this.slug = raw.slug || '';
|
||||
this.description = raw.description || '';
|
||||
this.createdAt = raw.created_at || '';
|
||||
this.updatedAt = raw.updated_at || '';
|
||||
this.createdBy = raw.created_by;
|
||||
this.updatedBy = raw.updated_by;
|
||||
this.ownedBy = raw.owned_by;
|
||||
this.defaultTemplateId = raw.default_template_id ?? null;
|
||||
this.tags = raw.tags || [];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// CRUD
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async update(data: {
|
||||
name?: string;
|
||||
description?: string;
|
||||
description_html?: string;
|
||||
tags?: IBookStackTag[];
|
||||
default_template_id?: number | null;
|
||||
}): Promise<BookStackBook> {
|
||||
const raw = await this.accountRef.request<IBookStackBook>('PUT', `/books/${this.id}`, data);
|
||||
return new BookStackBook(this.accountRef, raw);
|
||||
}
|
||||
|
||||
async delete(): Promise<void> {
|
||||
await this.accountRef.request('DELETE', `/books/${this.id}`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Export
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async export(format: TBookStackExportFormat): Promise<string | Uint8Array> {
|
||||
if (format === 'pdf') {
|
||||
return this.accountRef.requestBinary(`/books/${this.id}/export/${format}`);
|
||||
}
|
||||
return this.accountRef.requestText('GET', `/books/${this.id}/export/${format}`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Navigation — Chapters
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async getChapters(opts?: IBookStackListParams): Promise<BookStackChapter[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.accountRef.request<IBookStackListResponse<IBookStackChapter>>(
|
||||
'GET',
|
||||
this.accountRef.buildListUrl(`/chapters`, { ...opts, offset, count, filter: { ...opts?.filter, book_id: String(this.id) } }),
|
||||
),
|
||||
opts,
|
||||
).then((chapters) => chapters.map((c) => new BookStackChapter(this.accountRef, c)));
|
||||
}
|
||||
|
||||
async createChapter(data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
description_html?: string;
|
||||
tags?: IBookStackTag[];
|
||||
priority?: number;
|
||||
default_template_id?: number | null;
|
||||
}): Promise<BookStackChapter> {
|
||||
const raw = await this.accountRef.request<IBookStackChapter>('POST', '/chapters', {
|
||||
book_id: this.id,
|
||||
...data,
|
||||
});
|
||||
return new BookStackChapter(this.accountRef, raw);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Navigation — Pages
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async getPages(opts?: IBookStackListParams): Promise<BookStackPage[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.accountRef.request<IBookStackListResponse<IBookStackPage>>(
|
||||
'GET',
|
||||
this.accountRef.buildListUrl(`/pages`, { ...opts, offset, count, filter: { ...opts?.filter, book_id: String(this.id) } }),
|
||||
),
|
||||
opts,
|
||||
).then((pages) => pages.map((p) => new BookStackPage(this.accountRef, p)));
|
||||
}
|
||||
|
||||
async createPage(data: {
|
||||
name: string;
|
||||
html?: string;
|
||||
markdown?: string;
|
||||
chapter_id?: number;
|
||||
tags?: IBookStackTag[];
|
||||
priority?: number;
|
||||
}): Promise<BookStackPage> {
|
||||
const raw = await this.accountRef.request<IBookStackPage>('POST', '/pages', {
|
||||
book_id: this.id,
|
||||
...data,
|
||||
});
|
||||
return new BookStackPage(this.accountRef, raw);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Serialization
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
toJSON(): IBookStackBook {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
slug: this.slug,
|
||||
description: this.description,
|
||||
created_at: this.createdAt,
|
||||
updated_at: this.updatedAt,
|
||||
created_by: this.createdBy,
|
||||
updated_by: this.updatedBy,
|
||||
owned_by: this.ownedBy,
|
||||
default_template_id: this.defaultTemplateId,
|
||||
tags: this.tags,
|
||||
};
|
||||
}
|
||||
}
|
||||
127
ts/bookstack.classes.chapter.ts
Normal file
127
ts/bookstack.classes.chapter.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import type { BookStackAccount } from './bookstack.classes.account.js';
|
||||
import type {
|
||||
IBookStackChapter,
|
||||
IBookStackPage,
|
||||
IBookStackTag,
|
||||
IBookStackListParams,
|
||||
IBookStackListResponse,
|
||||
TBookStackExportFormat,
|
||||
} from './bookstack.interfaces.js';
|
||||
import { BookStackPage } from './bookstack.classes.page.js';
|
||||
import { autoPaginate } from './bookstack.helpers.js';
|
||||
|
||||
export class BookStackChapter {
|
||||
public readonly id: number;
|
||||
public readonly bookId: number;
|
||||
public readonly name: string;
|
||||
public readonly slug: string;
|
||||
public readonly description: string;
|
||||
public readonly priority: number;
|
||||
public readonly createdAt: string;
|
||||
public readonly updatedAt: string;
|
||||
public readonly createdBy: number;
|
||||
public readonly updatedBy: number;
|
||||
public readonly ownedBy: number;
|
||||
public readonly tags: IBookStackTag[];
|
||||
|
||||
/** @internal */
|
||||
constructor(
|
||||
private accountRef: BookStackAccount,
|
||||
raw: IBookStackChapter,
|
||||
) {
|
||||
this.id = raw.id;
|
||||
this.bookId = raw.book_id;
|
||||
this.name = raw.name || '';
|
||||
this.slug = raw.slug || '';
|
||||
this.description = raw.description || '';
|
||||
this.priority = raw.priority || 0;
|
||||
this.createdAt = raw.created_at || '';
|
||||
this.updatedAt = raw.updated_at || '';
|
||||
this.createdBy = raw.created_by;
|
||||
this.updatedBy = raw.updated_by;
|
||||
this.ownedBy = raw.owned_by;
|
||||
this.tags = raw.tags || [];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// CRUD
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async update(data: {
|
||||
name?: string;
|
||||
description?: string;
|
||||
description_html?: string;
|
||||
book_id?: number;
|
||||
tags?: IBookStackTag[];
|
||||
priority?: number;
|
||||
default_template_id?: number | null;
|
||||
}): Promise<BookStackChapter> {
|
||||
const raw = await this.accountRef.request<IBookStackChapter>('PUT', `/chapters/${this.id}`, data);
|
||||
return new BookStackChapter(this.accountRef, raw);
|
||||
}
|
||||
|
||||
async delete(): Promise<void> {
|
||||
await this.accountRef.request('DELETE', `/chapters/${this.id}`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Export
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async export(format: TBookStackExportFormat): Promise<string | Uint8Array> {
|
||||
if (format === 'pdf') {
|
||||
return this.accountRef.requestBinary(`/chapters/${this.id}/export/${format}`);
|
||||
}
|
||||
return this.accountRef.requestText('GET', `/chapters/${this.id}/export/${format}`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Navigation — Pages
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async getPages(opts?: IBookStackListParams): Promise<BookStackPage[]> {
|
||||
return autoPaginate(
|
||||
(offset, count) =>
|
||||
this.accountRef.request<IBookStackListResponse<IBookStackPage>>(
|
||||
'GET',
|
||||
this.accountRef.buildListUrl(`/pages`, { ...opts, offset, count, filter: { ...opts?.filter, chapter_id: String(this.id) } }),
|
||||
),
|
||||
opts,
|
||||
).then((pages) => pages.map((p) => new BookStackPage(this.accountRef, p)));
|
||||
}
|
||||
|
||||
async createPage(data: {
|
||||
name: string;
|
||||
html?: string;
|
||||
markdown?: string;
|
||||
tags?: IBookStackTag[];
|
||||
priority?: number;
|
||||
}): Promise<BookStackPage> {
|
||||
const raw = await this.accountRef.request<IBookStackPage>('POST', '/pages', {
|
||||
chapter_id: this.id,
|
||||
...data,
|
||||
});
|
||||
return new BookStackPage(this.accountRef, raw);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Serialization
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
toJSON(): IBookStackChapter {
|
||||
return {
|
||||
id: this.id,
|
||||
book_id: this.bookId,
|
||||
name: this.name,
|
||||
slug: this.slug,
|
||||
description: this.description,
|
||||
priority: this.priority,
|
||||
created_at: this.createdAt,
|
||||
updated_at: this.updatedAt,
|
||||
created_by: this.createdBy,
|
||||
updated_by: this.updatedBy,
|
||||
owned_by: this.ownedBy,
|
||||
tags: this.tags,
|
||||
};
|
||||
}
|
||||
}
|
||||
135
ts/bookstack.classes.page.ts
Normal file
135
ts/bookstack.classes.page.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import type { BookStackAccount } from './bookstack.classes.account.js';
|
||||
import type {
|
||||
IBookStackPage,
|
||||
IBookStackTag,
|
||||
IBookStackComment,
|
||||
TBookStackExportFormat,
|
||||
} from './bookstack.interfaces.js';
|
||||
|
||||
export class BookStackPage {
|
||||
public readonly id: number;
|
||||
public readonly bookId: number;
|
||||
public readonly chapterId: number;
|
||||
public readonly name: string;
|
||||
public readonly slug: string;
|
||||
public readonly html: string;
|
||||
public readonly markdown: string;
|
||||
public readonly priority: number;
|
||||
public readonly draft: boolean;
|
||||
public readonly template: boolean;
|
||||
public readonly revisionCount: number;
|
||||
public readonly editor: string;
|
||||
public readonly createdAt: string;
|
||||
public readonly updatedAt: string;
|
||||
public readonly createdBy: number;
|
||||
public readonly updatedBy: number;
|
||||
public readonly ownedBy: number;
|
||||
public readonly tags: IBookStackTag[];
|
||||
|
||||
/** @internal */
|
||||
constructor(
|
||||
private accountRef: BookStackAccount,
|
||||
raw: IBookStackPage,
|
||||
) {
|
||||
this.id = raw.id;
|
||||
this.bookId = raw.book_id;
|
||||
this.chapterId = raw.chapter_id;
|
||||
this.name = raw.name || '';
|
||||
this.slug = raw.slug || '';
|
||||
this.html = raw.html || '';
|
||||
this.markdown = raw.markdown || '';
|
||||
this.priority = raw.priority || 0;
|
||||
this.draft = raw.draft || false;
|
||||
this.template = raw.template || false;
|
||||
this.revisionCount = raw.revision_count || 0;
|
||||
this.editor = raw.editor || '';
|
||||
this.createdAt = raw.created_at || '';
|
||||
this.updatedAt = raw.updated_at || '';
|
||||
this.createdBy = raw.created_by;
|
||||
this.updatedBy = raw.updated_by;
|
||||
this.ownedBy = raw.owned_by;
|
||||
this.tags = raw.tags || [];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// CRUD
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async update(data: {
|
||||
name?: string;
|
||||
html?: string;
|
||||
markdown?: string;
|
||||
book_id?: number;
|
||||
chapter_id?: number;
|
||||
tags?: IBookStackTag[];
|
||||
priority?: number;
|
||||
}): Promise<BookStackPage> {
|
||||
const raw = await this.accountRef.request<IBookStackPage>('PUT', `/pages/${this.id}`, data);
|
||||
return new BookStackPage(this.accountRef, raw);
|
||||
}
|
||||
|
||||
async delete(): Promise<void> {
|
||||
await this.accountRef.request('DELETE', `/pages/${this.id}`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Export
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async export(format: TBookStackExportFormat): Promise<string | Uint8Array> {
|
||||
if (format === 'pdf') {
|
||||
return this.accountRef.requestBinary(`/pages/${this.id}/export/${format}`);
|
||||
}
|
||||
return this.accountRef.requestText('GET', `/pages/${this.id}/export/${format}`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Comments
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async getComments(): Promise<IBookStackComment[]> {
|
||||
const result = await this.accountRef.request<{ data: IBookStackComment[] }>(
|
||||
'GET',
|
||||
`/comments?filter[page_id]=${this.id}`,
|
||||
);
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async addComment(data: {
|
||||
html: string;
|
||||
reply_to?: number;
|
||||
content_ref?: string;
|
||||
}): Promise<IBookStackComment> {
|
||||
return this.accountRef.request<IBookStackComment>('POST', '/comments', {
|
||||
page_id: this.id,
|
||||
...data,
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Serialization
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
toJSON(): IBookStackPage {
|
||||
return {
|
||||
id: this.id,
|
||||
book_id: this.bookId,
|
||||
chapter_id: this.chapterId,
|
||||
name: this.name,
|
||||
slug: this.slug,
|
||||
html: this.html,
|
||||
markdown: this.markdown,
|
||||
priority: this.priority,
|
||||
draft: this.draft,
|
||||
template: this.template,
|
||||
revision_count: this.revisionCount,
|
||||
editor: this.editor,
|
||||
created_at: this.createdAt,
|
||||
updated_at: this.updatedAt,
|
||||
created_by: this.createdBy,
|
||||
updated_by: this.updatedBy,
|
||||
owned_by: this.ownedBy,
|
||||
tags: this.tags,
|
||||
};
|
||||
}
|
||||
}
|
||||
91
ts/bookstack.classes.shelf.ts
Normal file
91
ts/bookstack.classes.shelf.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import type { BookStackAccount } from './bookstack.classes.account.js';
|
||||
import type {
|
||||
IBookStackShelf,
|
||||
IBookStackBook,
|
||||
IBookStackTag,
|
||||
IBookStackListParams,
|
||||
IBookStackListResponse,
|
||||
} from './bookstack.interfaces.js';
|
||||
import { BookStackBook } from './bookstack.classes.book.js';
|
||||
import { autoPaginate } from './bookstack.helpers.js';
|
||||
|
||||
export class BookStackShelf {
|
||||
public readonly id: number;
|
||||
public readonly name: string;
|
||||
public readonly slug: string;
|
||||
public readonly description: string;
|
||||
public readonly createdAt: string;
|
||||
public readonly updatedAt: string;
|
||||
public readonly createdBy: number;
|
||||
public readonly updatedBy: number;
|
||||
public readonly ownedBy: number;
|
||||
public readonly tags: IBookStackTag[];
|
||||
|
||||
/** @internal */
|
||||
constructor(
|
||||
private accountRef: BookStackAccount,
|
||||
raw: IBookStackShelf,
|
||||
) {
|
||||
this.id = raw.id;
|
||||
this.name = raw.name || '';
|
||||
this.slug = raw.slug || '';
|
||||
this.description = raw.description || '';
|
||||
this.createdAt = raw.created_at || '';
|
||||
this.updatedAt = raw.updated_at || '';
|
||||
this.createdBy = raw.created_by;
|
||||
this.updatedBy = raw.updated_by;
|
||||
this.ownedBy = raw.owned_by;
|
||||
this.tags = raw.tags || [];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// CRUD
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async update(data: {
|
||||
name?: string;
|
||||
description?: string;
|
||||
description_html?: string;
|
||||
books?: number[];
|
||||
tags?: IBookStackTag[];
|
||||
}): Promise<BookStackShelf> {
|
||||
const raw = await this.accountRef.request<IBookStackShelf>('PUT', `/shelves/${this.id}`, data);
|
||||
return new BookStackShelf(this.accountRef, raw);
|
||||
}
|
||||
|
||||
async delete(): Promise<void> {
|
||||
await this.accountRef.request('DELETE', `/shelves/${this.id}`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Navigation — Books
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async getBooks(opts?: IBookStackListParams): Promise<BookStackBook[]> {
|
||||
// The shelf detail endpoint includes books inline
|
||||
const detail = await this.accountRef.request<IBookStackShelf>('GET', `/shelves/${this.id}`);
|
||||
if (detail.books) {
|
||||
return detail.books.map((b) => new BookStackBook(this.accountRef, b));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Serialization
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
toJSON(): IBookStackShelf {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
slug: this.slug,
|
||||
description: this.description,
|
||||
created_at: this.createdAt,
|
||||
updated_at: this.updatedAt,
|
||||
created_by: this.createdBy,
|
||||
updated_by: this.updatedBy,
|
||||
owned_by: this.ownedBy,
|
||||
tags: this.tags,
|
||||
};
|
||||
}
|
||||
}
|
||||
29
ts/bookstack.helpers.ts
Normal file
29
ts/bookstack.helpers.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { IBookStackListResponse } from './bookstack.interfaces.js';
|
||||
|
||||
/**
|
||||
* Auto-paginate a BookStack list endpoint using offset/count.
|
||||
* If opts includes a specific offset, returns just that single page (no auto-pagination).
|
||||
*/
|
||||
export async function autoPaginate<T>(
|
||||
fetchPage: (offset: number, count: number) => Promise<IBookStackListResponse<T>>,
|
||||
opts?: { offset?: number; count?: number },
|
||||
): Promise<T[]> {
|
||||
const count = opts?.count || 100;
|
||||
|
||||
// If caller requests a specific offset, return just that page
|
||||
if (opts?.offset !== undefined) {
|
||||
const result = await fetchPage(opts.offset, count);
|
||||
return result.data;
|
||||
}
|
||||
|
||||
// Otherwise auto-paginate through all pages
|
||||
const all: T[] = [];
|
||||
let offset = 0;
|
||||
while (true) {
|
||||
const result = await fetchPage(offset, count);
|
||||
all.push(...result.data);
|
||||
offset += count;
|
||||
if (offset >= result.total) break;
|
||||
}
|
||||
return all;
|
||||
}
|
||||
322
ts/bookstack.interfaces.ts
Normal file
322
ts/bookstack.interfaces.ts
Normal file
@@ -0,0 +1,322 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// Common
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface ITestConnectionResult {
|
||||
ok: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface IBookStackListParams {
|
||||
count?: number;
|
||||
offset?: number;
|
||||
sort?: string;
|
||||
filter?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface IBookStackListResponse<T> {
|
||||
data: T[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface IBookStackErrorResponse {
|
||||
error: {
|
||||
code: number;
|
||||
message: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IBookStackTag {
|
||||
name: string;
|
||||
value: string;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
export type TBookStackExportFormat = 'html' | 'pdf' | 'plaintext' | 'markdown';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Books
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackBook {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
description: string;
|
||||
description_html?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created_by: number;
|
||||
updated_by: number;
|
||||
owned_by: number;
|
||||
default_template_id: number | null;
|
||||
tags?: IBookStackTag[];
|
||||
cover?: { id: number; name: string; url: string } | null;
|
||||
contents?: IBookStackBookContent[];
|
||||
}
|
||||
|
||||
export interface IBookStackBookContent {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
type: 'chapter' | 'page';
|
||||
book_id: number;
|
||||
priority: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
url: string;
|
||||
pages?: IBookStackBookContent[];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Chapters
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackChapter {
|
||||
id: number;
|
||||
book_id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
description: string;
|
||||
description_html?: string;
|
||||
priority: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created_by: number;
|
||||
updated_by: number;
|
||||
owned_by: number;
|
||||
default_template_id?: number | null;
|
||||
tags?: IBookStackTag[];
|
||||
pages?: IBookStackPage[];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Pages
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackPage {
|
||||
id: number;
|
||||
book_id: number;
|
||||
chapter_id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
html: string;
|
||||
raw_html?: string;
|
||||
markdown: string;
|
||||
priority: number;
|
||||
draft: boolean;
|
||||
template: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created_by: number;
|
||||
updated_by: number;
|
||||
owned_by: number;
|
||||
revision_count: number;
|
||||
editor: string;
|
||||
book_slug?: string;
|
||||
tags?: IBookStackTag[];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shelves
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackShelf {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
description: string;
|
||||
description_html?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created_by: number;
|
||||
updated_by: number;
|
||||
owned_by: number;
|
||||
tags?: IBookStackTag[];
|
||||
cover?: { id: number; name: string; url: string } | null;
|
||||
books?: IBookStackBook[];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Attachments
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackAttachment {
|
||||
id: number;
|
||||
name: string;
|
||||
extension: string;
|
||||
uploaded_to: number;
|
||||
external: boolean;
|
||||
order: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created_by: number;
|
||||
updated_by: number;
|
||||
content?: string;
|
||||
links?: {
|
||||
html: string;
|
||||
markdown: string;
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Comments
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackComment {
|
||||
id: number;
|
||||
html: string;
|
||||
parent_id: number | null;
|
||||
local_id: number;
|
||||
content_ref: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created_by: number;
|
||||
updated_by: number;
|
||||
archived?: boolean;
|
||||
replies?: IBookStackComment[];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Image Gallery
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackImage {
|
||||
id: number;
|
||||
name: string;
|
||||
url: string;
|
||||
path: string;
|
||||
type: string;
|
||||
uploaded_to: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created_by: number;
|
||||
updated_by: number;
|
||||
thumbs?: {
|
||||
gallery: string;
|
||||
display: string;
|
||||
};
|
||||
content?: {
|
||||
html: string;
|
||||
markdown: string;
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Users
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackUser {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
email: string;
|
||||
profile_url: string;
|
||||
edit_url?: string;
|
||||
avatar_url: string;
|
||||
external_auth_id: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
last_activity_at?: string;
|
||||
roles?: { id: number; display_name: string }[];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Roles
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackRole {
|
||||
id: number;
|
||||
display_name: string;
|
||||
description: string;
|
||||
mfa_enforced: boolean;
|
||||
external_auth_id: string;
|
||||
permissions_count: number;
|
||||
users_count?: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
permissions?: string[];
|
||||
users?: IBookStackUser[];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Search
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackSearchResult {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
book_id?: number;
|
||||
chapter_id?: number;
|
||||
type: string;
|
||||
url: string;
|
||||
preview_html?: { name: string; content: string };
|
||||
tags?: IBookStackTag[];
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Audit Log
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackAuditLogEntry {
|
||||
id: number;
|
||||
type: string;
|
||||
detail: string;
|
||||
user_id: number;
|
||||
loggable_id: number;
|
||||
loggable_type: string;
|
||||
ip: string;
|
||||
created_at: string;
|
||||
user?: IBookStackUser;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Recycle Bin
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackRecycleBinItem {
|
||||
id: number;
|
||||
deleted_by: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
deletable_type: string;
|
||||
deletable_id: number;
|
||||
deletable?: Record<string, any>;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Content Permissions
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackContentPermission {
|
||||
owner: IBookStackUser;
|
||||
role_permissions: {
|
||||
role_id: number;
|
||||
view: boolean;
|
||||
create: boolean;
|
||||
update: boolean;
|
||||
delete: boolean;
|
||||
}[];
|
||||
fallback_permissions: {
|
||||
inheriting: boolean;
|
||||
view: boolean;
|
||||
create: boolean;
|
||||
update: boolean;
|
||||
delete: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// System
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface IBookStackSystemInfo {
|
||||
version: string;
|
||||
instance_id: string;
|
||||
app_name: string;
|
||||
app_logo: string | null;
|
||||
base_url: string;
|
||||
}
|
||||
3
ts/bookstack.plugins.ts
Normal file
3
ts/bookstack.plugins.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import * as smartrequest from '@push.rocks/smartrequest';
|
||||
|
||||
export { smartrequest };
|
||||
38
ts/index.ts
Normal file
38
ts/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
// Main client
|
||||
export { BookStackAccount } from './bookstack.classes.account.js';
|
||||
|
||||
// Domain classes
|
||||
export { BookStackBook } from './bookstack.classes.book.js';
|
||||
export { BookStackChapter } from './bookstack.classes.chapter.js';
|
||||
export { BookStackPage } from './bookstack.classes.page.js';
|
||||
export { BookStackShelf } from './bookstack.classes.shelf.js';
|
||||
|
||||
// Helpers
|
||||
export { autoPaginate } from './bookstack.helpers.js';
|
||||
|
||||
// Interfaces (raw API types)
|
||||
export type {
|
||||
IBookStackBook,
|
||||
IBookStackChapter,
|
||||
IBookStackPage,
|
||||
IBookStackShelf,
|
||||
IBookStackAttachment,
|
||||
IBookStackComment,
|
||||
IBookStackImage,
|
||||
IBookStackUser,
|
||||
IBookStackRole,
|
||||
IBookStackSearchResult,
|
||||
IBookStackAuditLogEntry,
|
||||
IBookStackRecycleBinItem,
|
||||
IBookStackContentPermission,
|
||||
IBookStackSystemInfo,
|
||||
IBookStackListResponse,
|
||||
IBookStackListParams,
|
||||
IBookStackErrorResponse,
|
||||
IBookStackTag,
|
||||
TBookStackExportFormat,
|
||||
ITestConnectionResult,
|
||||
} from './bookstack.interfaces.js';
|
||||
|
||||
// Commit info
|
||||
export { commitinfo } from './00_commitinfo_data.js';
|
||||
Reference in New Issue
Block a user