@hiai-gg/docsmint 0.5.10 → 0.6.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.
Files changed (41) hide show
  1. package/LICENSE +39 -8
  2. package/README.md +67 -43
  3. package/dist/backend/index.js +45 -12
  4. package/dist/client.d.ts +3 -1
  5. package/dist/client.js +2 -0
  6. package/dist/frontend/HiAiEditor-DSVG3GNd.js +2986 -0
  7. package/dist/frontend/SettingsDialog-BDNgf5rv.js +969 -0
  8. package/dist/frontend/ShareDialog-2Mty7hm4.js +258 -0
  9. package/dist/frontend/{Sidebar-CzcLd6v5.js → Sidebar-DX08utdV.js} +2 -2
  10. package/dist/frontend/app-shell.js +27 -26
  11. package/dist/frontend/components/editor/compact-editor.d.ts +3 -0
  12. package/dist/frontend/components/editor/compact-editor.js +36 -0
  13. package/dist/frontend/components/editor/document-editor.js +2 -2986
  14. package/dist/frontend/components/settings.js +1 -1
  15. package/dist/frontend/components/share-dialog.d.ts +2 -1
  16. package/dist/frontend/components/share-dialog.js +1 -1
  17. package/dist/frontend/components/sidebar.js +1 -1
  18. package/dist/frontend/dashboard.js +1 -1
  19. package/dist/frontend/editor-preferences.d.ts +4 -0
  20. package/dist/frontend/editor-preferences.js +2 -0
  21. package/dist/frontend/editor-preferences.svelte-Bt_A9k7n.js +61 -0
  22. package/dist/frontend/frontend.css +1 -1
  23. package/dist/frontend-ssr/app-shell.js +3 -2
  24. package/dist/frontend-ssr/assets/HiAiEditor-CUOJmKzT.js +2358 -0
  25. package/dist/frontend-ssr/assets/{SettingsDialog-DVp0OxPO.js → SettingsDialog-BjJIiVLc.js} +2 -64
  26. package/dist/frontend-ssr/assets/{ShareDialog-BZd28sg-.js → ShareDialog-C9C-XTm4.js} +1 -1
  27. package/dist/frontend-ssr/assets/{Sidebar-CqsMw0Hd.js → Sidebar-C2sUfGNk.js} +2 -2
  28. package/dist/frontend-ssr/assets/editor-preferences.svelte-iI5jJM1x.js +65 -0
  29. package/dist/frontend-ssr/components/editor/compact-editor.js +19 -0
  30. package/dist/frontend-ssr/components/editor/document-editor.js +1 -2357
  31. package/dist/frontend-ssr/components/settings.js +1 -1
  32. package/dist/frontend-ssr/components/share-dialog.js +1 -1
  33. package/dist/frontend-ssr/components/sidebar.js +1 -1
  34. package/dist/frontend-ssr/dashboard.js +1 -1
  35. package/dist/frontend-ssr/editor-preferences.js +2 -0
  36. package/dist/types.d.ts +5 -0
  37. package/package.json +16 -2
  38. package/packages/cli/src/index.ts +1 -1
  39. package/packages/mcp-server/src/index.ts +1 -1
  40. package/dist/frontend/SettingsDialog-CyZSOjLE.js +0 -1024
  41. package/dist/frontend/ShareDialog-BC-Jl6v1.js +0 -257
package/LICENSE CHANGED
@@ -1,4 +1,5 @@
1
- Apache License
1
+
2
+ Apache License
2
3
  Version 2.0, January 2004
3
4
  http://www.apache.org/licenses/
4
5
 
@@ -34,7 +35,8 @@ Apache License
34
35
 
35
36
  "Work" shall mean the work of authorship, whether in Source or
36
37
  Object form, made available under the License, as indicated by a
37
- copyright notice that is included in or attached to the work.
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
38
40
 
39
41
  "Derivative Works" shall mean any work, whether in Source or Object
40
42
  form, that is based on (or derived from) the Work and for which the
@@ -90,16 +92,17 @@ Apache License
90
92
  modifications, and in Source or Object form, provided that You
91
93
  meet the following conditions:
92
94
 
93
- (a) You must give any other recipients of the Work or Derivative Works
94
- a copy of this License; and
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
95
97
 
96
98
  (b) You must cause any modified files to carry prominent notices
97
99
  stating that You changed the files; and
98
100
 
99
- (c) You must retain, in the Source form of any Derivative Works that
100
- You distribute, all copyright, patent, trademark, and attribution
101
- notices from the Source form of the Work, excluding those notices
102
- that do not pertain to any part of the Derivative Works; and
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
103
106
 
104
107
  (d) If the Work includes a "NOTICE" text file as part of its
105
108
  distribution, then any Derivative Works that You distribute must
@@ -129,6 +132,9 @@ Apache License
129
132
  any Contribution intentionally submitted for inclusion in the Work
130
133
  by You to the Licensor shall be under the terms and conditions of
131
134
  this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
132
138
 
133
139
  6. Trademarks. This License does not grant permission to use the trade
134
140
  names, trademarks, service marks, or product names of the Licensor,
@@ -169,3 +175,28 @@ Apache License
169
175
  of your accepting any such warranty or additional liability.
170
176
 
171
177
  END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # DocsMint
2
2
 
3
- **A self-hosted, AI-native knowledge workspace for people, applications, and agents.**
3
+ **A self-hosted AI-native knowledge workspace and installable PWA for people,
4
+ applications, and AI agents.**
4
5
 
5
6
  DocsMint stores documents in a structured JSON editor model first. Markdown is
6
7
  the convenient second format for editing, importing, and exporting content.
@@ -38,24 +39,36 @@ server.
38
39
  - **Own the full stack**: application data, vectors, graph, queue, and files run
39
40
  on infrastructure you control.
40
41
 
41
- ## What is new in the 0.3.0 release line?
42
-
43
- - **Installable Progressive Web App (PWA)** with a manifest, service worker,
44
- responsive mobile shell, install prompt, update safety, and an offline
45
- fallback shell.
46
- - **Offline document access** through identity-partitioned IndexedDB/Dexie
47
- snapshots. Offline mode is cached read plus explicit local drafts; reconnect
48
- never silently replays mutations.
49
- - **Explicit local drafts** with local autosave, review/apply, optimistic
50
- concurrency (`expectedUpdatedAt`), and actionable conflict handling.
51
- - **Composable self-hosted UI** with typed dashboard/search hosts and extension
52
- slots.
53
- - **Mobile-first editor polish** including a single responsive sidebar, safe
54
- PWA updates, raw Markdown auto-height, and accessible narrow-screen controls.
55
-
56
- Search terms: installable self-hosted PWA knowledge base, offline document
57
- reading, local drafts, semantic multilingual search, GraphRAG, MCP, TypeScript
58
- SDK, CLI, and frontend extension hosts.
42
+ ## What's new in DocsMint 0.6.0?
43
+
44
+ - **Installable, update-safe PWA.** A versioned service worker, responsive app
45
+ shell, install prompt, and deterministic offline fallback make DocsMint feel
46
+ at home on desktop and mobile browsers.
47
+ - **Private offline reading and explicit drafts.** Identity-partitioned local
48
+ snapshots keep selected documents readable offline. Drafts autosave locally,
49
+ then return through a deliberate review-and-apply flow after reconnecting;
50
+ DocsMint never silently replays offline mutations.
51
+ - **Touch-safe mobile navigation.** Sidebar document actions, Copy controls, and
52
+ overflow menus remain reachable on touch devices without depending on hover,
53
+ with accessible targets and narrow-screen layouts.
54
+ - **A flexible editor contract.** Reactive visual/Markdown mode preferences,
55
+ Minimal toolbar support, and a reusable compact TipTap editor let hosts match
56
+ the writing surface to the task without forking editor internals.
57
+ - **Stable document discovery.** The public API and TypeScript SDK provide
58
+ deterministic cursor pagination and global sorting by title, category,
59
+ folder, or update time, with canonical category and folder metadata.
60
+ - **Clear public and restricted sharing.** Share creation exposes the resulting
61
+ URL for both public links and restricted invitation workflows, with an
62
+ explicit Copy action that works on narrow screens.
63
+ - **Knowledge built for agents.** REST, the typed SDK, CLI, and MCP server expose
64
+ scoped document operations, while multilingual hybrid search and GraphRAG
65
+ help people and AI agents retrieve connected knowledge instead of isolated
66
+ keyword matches.
67
+
68
+ DocsMint combines an installable self-hosted PWA knowledge base, mobile document
69
+ workspace, offline reading, local drafts, multilingual semantic search,
70
+ GraphRAG, MCP, a TypeScript SDK, CLI, and composable frontend hosts in one
71
+ open-source system.
59
72
 
60
73
  For self-hosted customization, see [PWA hosting](docs/PWA_HOSTING.md) and
61
74
  [extension points](docs/EXTENDING.md).
@@ -96,6 +109,7 @@ git clone https://github.com/HiAi-gg/docsmint.git
96
109
  cd docsmint
97
110
  bash scripts/quickstart.sh
98
111
  ```
112
+
99
113
  On its first run, the script creates an ignored root `.env`, generates the
100
114
  database, authentication, and storage secrets, builds the PostgreSQL image,
101
115
  applies migrations, and starts the complete application.
@@ -105,12 +119,14 @@ For OpenRouter, add one value to `.env` and run the script again:
105
119
  ```dotenv
106
120
  OPENROUTER_API_KEY=sk-or-your-key
107
121
  ```
122
+
108
123
  For Ollama, select the local provider instead:
109
124
 
110
125
  ```dotenv
111
126
  AI_PROVIDER=ollama
112
127
  OLLAMA_PORT=11434
113
128
  ```
129
+
114
130
  Then make sure the configured local models are available:
115
131
 
116
132
  ```bash
@@ -118,6 +134,7 @@ ollama pull bge-m3
118
134
  ollama pull qwen3:8b
119
135
  bash scripts/quickstart.sh
120
136
  ```
137
+
121
138
  Open **http://localhost:50701**. The API health endpoint is
122
139
  **http://localhost:50700/api/health**.
123
140
 
@@ -133,14 +150,14 @@ Open **http://localhost:50701**. The API health endpoint is
133
150
 
134
151
  The canonical local ports are:
135
152
 
136
- | Service | Port |
137
- |---|---:|
138
- | Web application | `50701` |
139
- | REST API | `50700` |
140
- | PostgreSQL | `5437` |
141
- | Redis | `6384` |
153
+ | Service | Port |
154
+ | -------------------- | ------: |
155
+ | Web application | `50701` |
156
+ | REST API | `50700` |
157
+ | PostgreSQL | `5437` |
158
+ | Redis | `6384` |
142
159
  | SeaweedFS S3 gateway | `50702` |
143
- | SeaweedFS filer UI | `50703` |
160
+ | SeaweedFS filer UI | `50703` |
144
161
 
145
162
  See [Deployment](docs/DEPLOYMENT.md) for domains, TLS, provider tuning,
146
163
  backups, and production operation.
@@ -165,6 +182,7 @@ bunx --package @hiai-gg/docsmint docsmint read <document-id>
165
182
  bunx --package @hiai-gg/docsmint docsmint create \
166
183
  --title "Release notes" --content "# Version 0.2.9"
167
184
  ```
185
+
168
186
  Credentials can also be supplied through `HIAI_DOCS_URL` and
169
187
  `HIAI_DOCS_API_KEY`. See the [CLI guide](packages/cli/README.md) for every
170
188
  command and configuration precedence.
@@ -188,11 +206,13 @@ snapshots, history, and export as MCP tools.
188
206
  }
189
207
  }
190
208
  ```
209
+
191
210
  Run the server directly to verify the installation:
192
211
 
193
212
  ```bash
194
213
  bunx --package @hiai-gg/docsmint docsmint-mcp
195
214
  ```
215
+
196
216
  The server uses stdio and works with MCP-capable clients such as Claude
197
217
  Desktop, Cursor, and coding agents that accept standard MCP configuration. See
198
218
  the [MCP guide](packages/mcp-server/README.md) for its ten tools and routes.
@@ -211,22 +231,24 @@ the CLI, SDK, or REST API.
211
231
  ```bash
212
232
  bun add @hiai-gg/docsmint
213
233
  ```
234
+
214
235
  ```ts
215
- import { DocsClient } from "@hiai-gg/docsmint";
236
+ import { DocsClient } from '@hiai-gg/docsmint';
216
237
 
217
238
  const docs = new DocsClient({
218
- baseUrl: "http://localhost:50700",
239
+ baseUrl: 'http://localhost:50700',
219
240
  apiKey: process.env.HIAI_DOCS_API_KEY,
220
241
  });
221
242
 
222
243
  const created = await docs.createDoc({
223
- title: "Meeting notes",
224
- content: "# Agenda",
244
+ title: 'Meeting notes',
245
+ content: '# Agenda',
225
246
  });
226
247
 
227
- const results = await docs.search("what did we decide?");
248
+ const results = await docs.search('what did we decide?');
228
249
  console.log(created.id, results.items);
229
250
  ```
251
+
230
252
  The SDK is a typed `fetch` client with retries for transient failures. See the
231
253
  [SDK reference](packages/sdk/README.md) and [REST API](docs/API.md).
232
254
 
@@ -234,11 +256,11 @@ The SDK is a typed `fetch` client with retries for transient failures. See the
234
256
 
235
257
  Create and revoke integration keys from **Settings → API**.
236
258
 
237
- | Credential | Intended use | Access |
238
- |---|---|---|
239
- | Global API key | Trusted owner-wide CLI, MCP, SDK, or service | All owner content |
240
- | Category key | Least-privilege agent or product integration | One category with selected permissions |
241
- | Operator key | Administration and reindex operations | `/api/admin/*` only |
259
+ | Credential | Intended use | Access |
260
+ | -------------- | -------------------------------------------- | -------------------------------------- |
261
+ | Global API key | Trusted owner-wide CLI, MCP, SDK, or service | All owner content |
262
+ | Category key | Least-privilege agent or product integration | One category with selected permissions |
263
+ | Operator key | Administration and reindex operations | `/api/admin/*` only |
242
264
 
243
265
  Category permissions are explicit and non-hierarchical:
244
266
 
@@ -263,6 +285,7 @@ packages/cli/ Terminal client
263
285
  packages/mcp-server/ MCP stdio server
264
286
  postgres/ PostgreSQL image with vector and graph extensions
265
287
  ```
288
+
266
289
  The Docker deployment runs:
267
290
 
268
291
  - **Web** — document editor, folders, categories, sharing, settings, and search;
@@ -307,13 +330,13 @@ For pipeline internals and tuning, see [Architecture](docs/ARCHITECTURE.md) and
307
330
  DocsMint overlaps with several excellent open-source knowledge tools, but its
308
331
  focus is a compact knowledge runtime shared equally by humans and agents.
309
332
 
310
- | Project | Primary strength | Difference from DocsMint |
311
- |---|---|---|
312
- | [Outline](https://github.com/outline/outline) | Polished team wiki and collaboration | DocsMint emphasizes built-in retrieval, GraphRAG, scoped agent access, CLI, and MCP |
313
- | [Docmost](https://github.com/docmost/docmost) | Collaborative wiki and real-time editing | DocsMint centers automatic embeddings and agent-facing integration surfaces |
314
- | [AppFlowy](https://github.com/AppFlowy-IO/AppFlowy) | Broad local-first productivity workspace | DocsMint is narrower: a self-hosted document and retrieval service |
315
- | [AnythingLLM](https://github.com/Mintplex-Labs/anything-llm) | Chat-oriented RAG over imported sources | DocsMint starts with the editable knowledge base and exposes it to many clients |
316
- | [Danswer](https://github.com/danswer-ai/danswer) / Onyx | Enterprise search across external connectors | DocsMint owns and edits its native corpus rather than primarily indexing other systems |
333
+ | Project | Primary strength | Difference from DocsMint |
334
+ | ------------------------------------------------------------ | -------------------------------------------- | -------------------------------------------------------------------------------------- |
335
+ | [Outline](https://github.com/outline/outline) | Polished team wiki and collaboration | DocsMint emphasizes built-in retrieval, GraphRAG, scoped agent access, CLI, and MCP |
336
+ | [Docmost](https://github.com/docmost/docmost) | Collaborative wiki and real-time editing | DocsMint centers automatic embeddings and agent-facing integration surfaces |
337
+ | [AppFlowy](https://github.com/AppFlowy-IO/AppFlowy) | Broad local-first productivity workspace | DocsMint is narrower: a self-hosted document and retrieval service |
338
+ | [AnythingLLM](https://github.com/Mintplex-Labs/anything-llm) | Chat-oriented RAG over imported sources | DocsMint starts with the editable knowledge base and exposes it to many clients |
339
+ | [Danswer](https://github.com/danswer-ai/danswer) / Onyx | Enterprise search across external connectors | DocsMint owns and edits its native corpus rather than primarily indexing other systems |
317
340
 
318
341
  This is a product-positioning summary, not a claim that every listed project
319
342
  lacks a feature. Check each project's current documentation when choosing a
@@ -340,6 +363,7 @@ bun run typecheck
340
363
  bun run test
341
364
  bun run build
342
365
  ```
366
+
343
367
  Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request. Please
344
368
  report vulnerabilities through [SECURITY.md](SECURITY.md), not a public issue.
345
369
 
@@ -227119,7 +227119,9 @@ var listQuerySchema2 = exports_external2.object({
227119
227119
  var cursorListQuerySchema = exports_external2.object({
227120
227120
  categoryId: exports_external2.string().uuid().optional(),
227121
227121
  cursor: exports_external2.string().min(1).optional(),
227122
- limit: exports_external2.coerce.number().int().min(1).max(100).default(50)
227122
+ limit: exports_external2.coerce.number().int().min(1).max(100).default(50),
227123
+ sortBy: exports_external2.enum(["title", "category", "folder", "updated"]).default("updated"),
227124
+ sortOrder: exports_external2.enum(["asc", "desc"]).default("desc")
227123
227125
  });
227124
227126
  function cursorScopeHash(input) {
227125
227127
  return Buffer.from(new Bun.CryptoHasher("sha256").update(input).digest("hex"), "utf8").toString("base64url");
@@ -227134,7 +227136,7 @@ function decodeDocumentCursor(value, expectedScopeHash) {
227134
227136
  if (!cursor || typeof cursor !== "object")
227135
227137
  throw new Error("Malformed cursor");
227136
227138
  const candidate = cursor;
227137
- if (candidate.v !== 1 || typeof candidate.updatedAt !== "string" || Number.isNaN(Date.parse(candidate.updatedAt)) || typeof candidate.id !== "string" || typeof candidate.scopeHash !== "string" || candidate.scopeHash !== expectedScopeHash) {
227139
+ if (candidate.v !== 2 || !["title", "category", "folder", "updated"].includes(String(candidate.sortBy)) || !["asc", "desc"].includes(String(candidate.sortOrder)) || candidate.value !== null && typeof candidate.value !== "string" || typeof candidate.id !== "string" || typeof candidate.scopeHash !== "string" || candidate.scopeHash !== expectedScopeHash) {
227138
227140
  throw new Error("Cursor does not match this listing scope");
227139
227141
  }
227140
227142
  return candidate;
@@ -227378,12 +227380,20 @@ var documentRoutes = new Elysia({ prefix: "/api" }).get("/documents", async ({ q
227378
227380
  set2.status = 400;
227379
227381
  return { error: "Invalid query", details: parsed.error.flatten() };
227380
227382
  }
227381
- const { categoryId, cursor: encodedCursor, limit } = parsed.data;
227383
+ const {
227384
+ categoryId,
227385
+ cursor: encodedCursor,
227386
+ limit,
227387
+ sortBy,
227388
+ sortOrder
227389
+ } = parsed.data;
227382
227390
  const effectiveCategoryId = access.restricted ? access.categoryId ?? categoryId : categoryId;
227383
227391
  const scopeHash = cursorScopeHash(JSON.stringify({
227384
227392
  workspaceId: ctx.workspaceId ?? null,
227385
227393
  actorUserId: access.userId,
227386
- categoryId: effectiveCategoryId ?? null
227394
+ categoryId: effectiveCategoryId ?? null,
227395
+ sortBy,
227396
+ sortOrder
227387
227397
  }));
227388
227398
  let cursor;
227389
227399
  if (encodedCursor) {
@@ -227396,31 +227406,54 @@ var documentRoutes = new Elysia({ prefix: "/api" }).get("/documents", async ({ q
227396
227406
  };
227397
227407
  }
227398
227408
  }
227409
+ const sortValue = sortBy === "title" ? sql`lower(${documents.title})` : sortBy === "category" ? sql`lower(${categories.name})` : sortBy === "folder" ? sql`lower(${folders.name})` : sql`${documents.updatedAt}`;
227399
227410
  const conditions2 = [
227400
227411
  tenantOwnerCondition(documents.ownerId, documents.workspaceId, ctx),
227401
227412
  isNull(documents.deletedAt),
227402
- ...effectiveCategoryId ? [eq(documents.categoryId, effectiveCategoryId)] : [],
227403
- ...cursor ? [
227404
- or(lt(documents.updatedAt, new Date(cursor.updatedAt)), and(eq(documents.updatedAt, new Date(cursor.updatedAt)), lt(documents.id, cursor.id)))
227405
- ] : []
227413
+ ...effectiveCategoryId ? [eq(documents.categoryId, effectiveCategoryId)] : []
227406
227414
  ];
227415
+ if (cursor) {
227416
+ const idAfter = sortOrder === "asc" ? gt(documents.id, cursor.id) : lt(documents.id, cursor.id);
227417
+ if (sortBy === "updated" && cursor.value) {
227418
+ const cursorDate = new Date(cursor.value);
227419
+ const valueAfter = sortOrder === "asc" ? gt(documents.updatedAt, cursorDate) : lt(documents.updatedAt, cursorDate);
227420
+ const cursorCondition = or(valueAfter, and(eq(documents.updatedAt, cursorDate), idAfter));
227421
+ if (cursorCondition)
227422
+ conditions2.push(cursorCondition);
227423
+ } else if (cursor.value === null) {
227424
+ const cursorCondition = and(isNull(sortValue), idAfter);
227425
+ if (cursorCondition)
227426
+ conditions2.push(cursorCondition);
227427
+ } else {
227428
+ const valueAfter = sortOrder === "asc" ? gt(sortValue, cursor.value) : lt(sortValue, cursor.value);
227429
+ const cursorCondition = or(valueAfter, and(eq(sortValue, cursor.value), idAfter), isNull(sortValue));
227430
+ if (cursorCondition)
227431
+ conditions2.push(cursorCondition);
227432
+ }
227433
+ }
227407
227434
  try {
227408
227435
  const rows = await withTenant(ctx, (tx) => tx.select({
227409
227436
  id: documents.id,
227410
227437
  title: documents.title,
227411
227438
  content: sql`LEFT(${documents.content}, 200)`.as("content"),
227412
227439
  folderId: documents.folderId,
227440
+ folderName: folders.name,
227441
+ categoryId: documents.categoryId,
227442
+ categoryName: categories.name,
227413
227443
  createdAt: documents.createdAt,
227414
227444
  updatedAt: documents.updatedAt
227415
- }).from(documents).where(and(...conditions2)).orderBy(desc(documents.updatedAt), desc(documents.id)).limit(limit + 1));
227445
+ }).from(documents).leftJoin(folders, eq(folders.id, documents.folderId)).leftJoin(categories, eq(categories.id, documents.categoryId)).where(and(...conditions2)).orderBy(sortOrder === "asc" ? sql`${sortValue} asc nulls last` : sql`${sortValue} desc nulls last`, sortOrder === "asc" ? asc(documents.id) : desc(documents.id)).limit(limit + 1));
227416
227446
  const hasMore = rows.length > limit;
227417
227447
  const page = rows.slice(0, limit);
227418
227448
  const last2 = page.at(-1);
227449
+ const lastValue = last2 ? sortBy === "title" ? last2.title.toLocaleLowerCase() : sortBy === "category" ? last2.categoryName?.toLocaleLowerCase() ?? null : sortBy === "folder" ? last2.folderName?.toLocaleLowerCase() ?? null : new Date(last2.updatedAt).toISOString() : null;
227419
227450
  return {
227420
227451
  items: await withTags(ctx, page),
227421
227452
  nextCursor: hasMore && last2 ? encodeDocumentCursor({
227422
- v: 1,
227423
- updatedAt: new Date(last2.updatedAt).toISOString(),
227453
+ v: 2,
227454
+ sortBy,
227455
+ sortOrder,
227456
+ value: lastValue,
227424
227457
  id: last2.id,
227425
227458
  scopeHash
227426
227459
  }) : null
@@ -234286,7 +234319,7 @@ var swaggerConfig = {
234286
234319
  },
234287
234320
  info: {
234288
234321
  title: "DocsMint API",
234289
- version: "0.5.10",
234322
+ version: "0.6.0",
234290
234323
  description: "Self-hosted AI-first documentation platform. Full-text + semantic search, version history, sharing, and folder organization.",
234291
234324
  contact: { name: "HiAi-gg", url: "https://github.com/HiAi-gg/docsmint" },
234292
234325
  license: {
package/dist/client.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  * failures (502 / 503 / 504 / timeout / network reset) are retried
8
8
  * with exponential backoff up to `config.retries` attempts.
9
9
  */
10
- import type { DocsApiKeyCreated, DocsApiKeyListResponse, DocsAttachment, DocsAttachmentConfirmInput, DocsAttachmentListResponse, DocsAttachmentPresignInput, DocsAttachmentPresignResponse, DocsCategory, DocsCategoryInput, DocsCategoryUpdate, DocsDocument, DocsDocumentCreateInput, DocsDocumentListResponse, DocsDocumentCursorPage, DocsDocumentPipeline, DocsDocumentUpdateInput, DocsFolder, DocsFolderCreateInput, DocsFolderUpdateInput, DocsGraphEntitiesResponse, DocsGraphRelatedResponse, DocsGraphSearchResponse, DocsHealthResponse, DocsRequestContext, DocsSearchOptions, DocsSearchResponse, DocsSearchSuggestItem, DocsSharedContent, DocsShareLink, DocsShareListResponse, DocsShareRole, DocsTag, DocsVersion, DocsVersionDiff } from "./types.js";
10
+ import type { DocsApiKeyCreated, DocsApiKeyListResponse, DocsAttachment, DocsAttachmentConfirmInput, DocsAttachmentListResponse, DocsAttachmentPresignInput, DocsAttachmentPresignResponse, DocsCategory, DocsCategoryInput, DocsCategoryUpdate, DocsDocument, DocsDocumentCreateInput, DocsDocumentCursorPage, DocsDocumentListResponse, DocsDocumentPipeline, DocsDocumentUpdateInput, DocsFolder, DocsFolderCreateInput, DocsFolderUpdateInput, DocsGraphEntitiesResponse, DocsGraphRelatedResponse, DocsGraphSearchResponse, DocsHealthResponse, DocsRequestContext, DocsSearchOptions, DocsSearchResponse, DocsSearchSuggestItem, DocsSharedContent, DocsShareLink, DocsShareListResponse, DocsShareRole, DocsTag, DocsVersion, DocsVersionDiff } from "./types.js";
11
11
  export interface DocsClientConfig {
12
12
  /** Base URL of the hiai-docs API, e.g. `http://localhost:50700`. */
13
13
  baseUrl: string;
@@ -76,6 +76,8 @@ export declare class DocsClient {
76
76
  categoryId?: string;
77
77
  cursor?: string;
78
78
  limit?: number;
79
+ sortBy?: import("./types").DocsDocumentSortField;
80
+ sortOrder?: import("./types").DocsSortOrder;
79
81
  }, context?: DocsRequestContext): Promise<DocsDocumentCursorPage>;
80
82
  duplicateDoc(id: string, context?: DocsRequestContext): Promise<DocsDocument>;
81
83
  getDocumentPipeline(id: string, context?: DocsRequestContext): Promise<DocsDocumentPipeline>;
package/dist/client.js CHANGED
@@ -112,6 +112,8 @@ export class DocsClient {
112
112
  categoryId: options.categoryId,
113
113
  cursor: options.cursor,
114
114
  limit: options.limit,
115
+ sortBy: options.sortBy,
116
+ sortOrder: options.sortOrder,
115
117
  }),
116
118
  }, context);
117
119
  }