@zuwiki/mcp 0.1.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/LICENSE +7 -0
- package/README.md +189 -0
- package/dist/api/categories.d.ts +4 -0
- package/dist/api/categories.js +14 -0
- package/dist/api/categories.js.map +1 -0
- package/dist/api/http.d.ts +8 -0
- package/dist/api/http.js +119 -0
- package/dist/api/http.js.map +1 -0
- package/dist/api/organizations.d.ts +14 -0
- package/dist/api/organizations.js +15 -0
- package/dist/api/organizations.js.map +1 -0
- package/dist/api/pages.d.ts +16 -0
- package/dist/api/pages.js +35 -0
- package/dist/api/pages.js.map +1 -0
- package/dist/api/types.d.ts +69 -0
- package/dist/api/types.js +13 -0
- package/dist/api/types.js.map +1 -0
- package/dist/api/wikis.d.ts +12 -0
- package/dist/api/wikis.js +25 -0
- package/dist/api/wikis.js.map +1 -0
- package/dist/auth/client.d.ts +54 -0
- package/dist/auth/client.js +162 -0
- package/dist/auth/client.js.map +1 -0
- package/dist/auth/discovery.d.ts +14 -0
- package/dist/auth/discovery.js +26 -0
- package/dist/auth/discovery.js.map +1 -0
- package/dist/auth/flow.d.ts +21 -0
- package/dist/auth/flow.js +188 -0
- package/dist/auth/flow.js.map +1 -0
- package/dist/auth/pkce.d.ts +7 -0
- package/dist/auth/pkce.js +20 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/auth/registration.d.ts +21 -0
- package/dist/auth/registration.js +28 -0
- package/dist/auth/registration.js.map +1 -0
- package/dist/auth/tokens.d.ts +25 -0
- package/dist/auth/tokens.js +51 -0
- package/dist/auth/tokens.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +128 -0
- package/dist/cli.js.map +1 -0
- package/dist/server.d.ts +15 -0
- package/dist/server.js +53 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/register.d.ts +12 -0
- package/dist/tools/register.js +244 -0
- package/dist/tools/register.js.map +1 -0
- package/dist/tools/shared.d.ts +5 -0
- package/dist/tools/shared.js +38 -0
- package/dist/tools/shared.js.map +1 -0
- package/dist/transports/http.d.ts +9 -0
- package/dist/transports/http.js +150 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/stdio.d.ts +7 -0
- package/dist/transports/stdio.js +20 -0
- package/dist/transports/stdio.js.map +1 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2026 The Zu Company
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
## Zuwiki MCP
|
|
2
|
+
|
|
3
|
+
A [Model Context Protocol](https://modelcontextprotocol.io) server for [Zuwiki](https://zuwiki.com). Once connected to any MCP client (Claude, Cursor, Windsurf, VS Code, Zed, and more), your assistant can browse and edit your wikis, categories and pages in natural language.
|
|
4
|
+
|
|
5
|
+
### Quick start
|
|
6
|
+
|
|
7
|
+
You do not need to clone anything. All you need is Node.js 20+ installed. The server runs over stdio with the command:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx -y @zuwiki/mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Most MCP clients use the same JSON config format, just in different places. On the first start a browser window opens, you sign in to Zuwiki, and you are ready to go.
|
|
14
|
+
|
|
15
|
+
#### Claude Code
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
claude mcp add zuwiki npx -y @zuwiki/mcp
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
#### Claude Desktop
|
|
22
|
+
|
|
23
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, equivalent on other OSes:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"zuwiki": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["-y", "@zuwiki/mcp"]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### Cursor
|
|
37
|
+
|
|
38
|
+
`~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (per project):
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"mcpServers": {
|
|
43
|
+
"zuwiki": {
|
|
44
|
+
"command": "npx",
|
|
45
|
+
"args": ["-y", "@zuwiki/mcp"]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### Windsurf
|
|
52
|
+
|
|
53
|
+
`~/.codeium/windsurf/mcp_config.json`:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"zuwiki": {
|
|
59
|
+
"command": "npx",
|
|
60
|
+
"args": ["-y", "@zuwiki/mcp"]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### VS Code (Continue, Cline, or other MCP enabled extensions)
|
|
67
|
+
|
|
68
|
+
Add a server entry pointing to the same `npx -y @zuwiki/mcp` command. The exact location depends on the extension; the value is always the same.
|
|
69
|
+
|
|
70
|
+
#### Any other MCP client
|
|
71
|
+
|
|
72
|
+
Anything that can launch a stdio MCP server works. Configure it with:
|
|
73
|
+
|
|
74
|
+
* command: `npx`
|
|
75
|
+
* args: `["-y", "@zuwiki/mcp"]`
|
|
76
|
+
|
|
77
|
+
Or, if you have installed the package globally with `npm install -g @zuwiki/mcp`:
|
|
78
|
+
|
|
79
|
+
* command: `zuwiki-mcp`
|
|
80
|
+
* args: `[]`
|
|
81
|
+
|
|
82
|
+
### Example prompts
|
|
83
|
+
|
|
84
|
+
Once connected, try things like:
|
|
85
|
+
|
|
86
|
+
* "List my Zuwiki organizations and switch to the one called Acme."
|
|
87
|
+
* "Show me all wikis in the active organization."
|
|
88
|
+
* "Create a new page called 'Onboarding' in the wiki 'Handbook' with a short welcome text."
|
|
89
|
+
* "Find the deployment page and rewrite the section on staging."
|
|
90
|
+
|
|
91
|
+
### Organizations
|
|
92
|
+
|
|
93
|
+
Zuwiki accounts can belong to several organizations and every API request needs to pick one. Easiest way: ask the LLM to call `zuwiki_list_organizations` and then `zuwiki_set_active_organization`. The choice persists for the lifetime of the server. Alternatively set `ZUWIKI_ORGANIZATION_ID` in your MCP config.
|
|
94
|
+
|
|
95
|
+
### How authentication works
|
|
96
|
+
|
|
97
|
+
The server uses OAuth 2.1 (Authorization Code Flow with PKCE) against the Zuwiki auth server, with Dynamic Client Registration per RFC 7591 on first start. Access and refresh tokens are stored in `~/.config/zuwiki-mcp/credentials.json` with file mode 0600. Subsequent runs use the refresh token automatically without any user interaction.
|
|
98
|
+
|
|
99
|
+
To sign in as a different user, or to force a fresh authorization, delete that file.
|
|
100
|
+
|
|
101
|
+
### Available tools
|
|
102
|
+
|
|
103
|
+
Read tools:
|
|
104
|
+
|
|
105
|
+
* `zuwiki_list_organizations`, `zuwiki_get_active_organization`
|
|
106
|
+
* `zuwiki_list_wikis`, `zuwiki_get_wiki`, `zuwiki_get_wiki_editor`
|
|
107
|
+
* `zuwiki_get_page_content`, `zuwiki_get_page_settings`, `zuwiki_get_page_history`
|
|
108
|
+
|
|
109
|
+
Write tools:
|
|
110
|
+
|
|
111
|
+
* `zuwiki_set_active_organization`
|
|
112
|
+
* `zuwiki_create_wiki`, `zuwiki_update_wiki`, `zuwiki_delete_wiki`
|
|
113
|
+
* `zuwiki_create_category`, `zuwiki_rename_category`, `zuwiki_delete_category`
|
|
114
|
+
* `zuwiki_create_page`, `zuwiki_rename_page`, `zuwiki_delete_page`
|
|
115
|
+
* `zuwiki_update_page_content`, `zuwiki_update_page_settings`
|
|
116
|
+
* `zuwiki_set_page_status`, `zuwiki_restore_page_history`
|
|
117
|
+
|
|
118
|
+
On failure each tool returns an `isError: true` result with a descriptive message. Common codes are `insufficient_scope`, `forbidden_or_not_member`, `not_found`, `conflict`, `rate_limited`. 429 responses are retried up to twice with backoff; 401 triggers an automatic token refresh and one retry.
|
|
119
|
+
|
|
120
|
+
### Configuration
|
|
121
|
+
|
|
122
|
+
CLI options:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
--http Use streamable HTTP transport instead of stdio
|
|
126
|
+
--host <host> HTTP host (default 127.0.0.1)
|
|
127
|
+
--port <port> HTTP port (default 3333)
|
|
128
|
+
--path <path> HTTP path (default /mcp)
|
|
129
|
+
--base-url <url> Zuwiki base URL (default https://zuwiki.com)
|
|
130
|
+
--organization <id> Active organization id
|
|
131
|
+
--credentials <path> Path to the credentials file
|
|
132
|
+
--organizations-path <p> Override the API path for the organizations list
|
|
133
|
+
--help Show help
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
All options can also be set via environment variables. CLI flags take precedence:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
ZUWIKI_BASE_URL Zuwiki base URL
|
|
140
|
+
ZUWIKI_ORGANIZATION_ID Active organization id
|
|
141
|
+
ZUWIKI_CREDENTIALS_PATH Path to the credentials file
|
|
142
|
+
ZUWIKI_HTTP_HOST HTTP host
|
|
143
|
+
ZUWIKI_HTTP_PORT HTTP port
|
|
144
|
+
ZUWIKI_HTTP_PATH HTTP path
|
|
145
|
+
ZUWIKI_ORGANIZATIONS_PATH Override the API path for organizations
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Run from source
|
|
149
|
+
|
|
150
|
+
If you want to hack on the server itself:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
pnpm install
|
|
154
|
+
pnpm build
|
|
155
|
+
node dist/cli.js
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
For development without rebuilding each time:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pnpm dev
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### HTTP mode
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
node dist/cli.js --http --port 3333
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The streamable HTTP endpoint listens at `http://127.0.0.1:3333/mcp`. Every client must send its own bearer token via the `Authorization` header on every request. The server forwards that token as is when talking to the Zuwiki API and never persists it. Valid tokens come from the Zuwiki auth server, for example via a client side OAuth flow.
|
|
171
|
+
|
|
172
|
+
### Tests
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
pnpm test
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The tests cover PKCE generation, token refresh logic, HTTP behavior (401 retry, 429 backoff, scope and org errors) and MCP tool registration plus argument validation.
|
|
179
|
+
|
|
180
|
+
### Security
|
|
181
|
+
|
|
182
|
+
* Tokens are stored with mode 0600
|
|
183
|
+
* PKCE S256 is mandatory
|
|
184
|
+
* The state parameter is validated against CSRF
|
|
185
|
+
* In HTTP mode the server only forwards incoming bearer tokens and never persists them
|
|
186
|
+
|
|
187
|
+
### License
|
|
188
|
+
|
|
189
|
+
MIT
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ApiContext, Category } from "./types.js";
|
|
2
|
+
export declare function createCategory(ctx: ApiContext, wikiId: string, name: string): Promise<Category>;
|
|
3
|
+
export declare function renameCategory(ctx: ApiContext, wikiId: string, categoryId: string, name: string): Promise<Category>;
|
|
4
|
+
export declare function deleteCategory(ctx: ApiContext, wikiId: string, categoryId: string): Promise<void>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { apiRequest } from "./http.js";
|
|
2
|
+
export function createCategory(ctx, wikiId, name) {
|
|
3
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/categories`, {
|
|
4
|
+
method: "POST",
|
|
5
|
+
body: { name },
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
export function renameCategory(ctx, wikiId, categoryId, name) {
|
|
9
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/categories/${encodeURIComponent(categoryId)}`, { method: "PATCH", body: { name } });
|
|
10
|
+
}
|
|
11
|
+
export function deleteCategory(ctx, wikiId, categoryId) {
|
|
12
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/categories/${encodeURIComponent(categoryId)}`, { method: "DELETE" });
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=categories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.js","sourceRoot":"","sources":["../../src/api/categories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,MAAM,UAAU,cAAc,CAC5B,GAAe,EACf,MAAc,EACd,IAAY;IAEZ,OAAO,UAAU,CAAC,GAAG,EAAE,cAAc,kBAAkB,CAAC,MAAM,CAAC,aAAa,EAAE;QAC5E,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,EAAE,IAAI,EAAE;KACf,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,GAAe,EACf,MAAc,EACd,UAAkB,EAClB,IAAY;IAEZ,OAAO,UAAU,CACf,GAAG,EACH,cAAc,kBAAkB,CAAC,MAAM,CAAC,eAAe,kBAAkB,CAAC,UAAU,CAAC,EAAE,EACvF,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,GAAe,EACf,MAAc,EACd,UAAkB;IAElB,OAAO,UAAU,CACf,GAAG,EACH,cAAc,kBAAkB,CAAC,MAAM,CAAC,eAAe,kBAAkB,CAAC,UAAU,CAAC,EAAE,EACvF,EAAE,MAAM,EAAE,QAAQ,EAAE,CACrB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ApiContext } from "./types.js";
|
|
2
|
+
export interface RequestOptions {
|
|
3
|
+
method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
|
|
4
|
+
body?: unknown;
|
|
5
|
+
/** When true, the x-organization-id header is omitted (e.g. for the organizations list). */
|
|
6
|
+
withoutOrganization?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function apiRequest<T = unknown>(context: ApiContext, path: string, options?: RequestOptions): Promise<T>;
|
package/dist/api/http.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { ApiError } from "./types.js";
|
|
2
|
+
const MAX_RETRY_AFTER_MS = 10_000;
|
|
3
|
+
export async function apiRequest(context, path, options = {}) {
|
|
4
|
+
const fetchImpl = context.fetchImpl ?? fetch;
|
|
5
|
+
const method = options.method ?? "GET";
|
|
6
|
+
if (!options.withoutOrganization && !context.organizationId) {
|
|
7
|
+
throw new ApiError("No active organization set. Use zuwiki_list_organizations and zuwiki_set_active_organization or set ZUWIKI_ORGANIZATION_ID.", 400, "no_active_organization");
|
|
8
|
+
}
|
|
9
|
+
const url = joinUrl(context.baseUrl, path);
|
|
10
|
+
const buildInit = async (token) => {
|
|
11
|
+
const headers = {
|
|
12
|
+
authorization: `Bearer ${token}`,
|
|
13
|
+
accept: "application/json",
|
|
14
|
+
};
|
|
15
|
+
if (!options.withoutOrganization && context.organizationId) {
|
|
16
|
+
headers["x-organization-id"] = context.organizationId;
|
|
17
|
+
}
|
|
18
|
+
let body;
|
|
19
|
+
if (options.body !== undefined) {
|
|
20
|
+
headers["content-type"] = "application/json";
|
|
21
|
+
body = JSON.stringify(options.body);
|
|
22
|
+
}
|
|
23
|
+
return { method, headers, body };
|
|
24
|
+
};
|
|
25
|
+
let attempt = 0;
|
|
26
|
+
let token = await context.getAccessToken();
|
|
27
|
+
while (true) {
|
|
28
|
+
const init = await buildInit(token);
|
|
29
|
+
const response = await fetchImpl(url, init);
|
|
30
|
+
if (response.status === 401 && attempt === 0) {
|
|
31
|
+
attempt++;
|
|
32
|
+
try {
|
|
33
|
+
token = await context.invalidateAndRefreshToken();
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
throw new ApiError(`Authentication failed and refresh is not possible: ${err.message}`, 401, "unauthorized");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (response.status === 429 && attempt < 2) {
|
|
41
|
+
attempt++;
|
|
42
|
+
const retryAfter = parseRetryAfter(response.headers.get("retry-after"));
|
|
43
|
+
await sleep(Math.min(retryAfter, MAX_RETRY_AFTER_MS));
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const detail = await readErrorDetail(response);
|
|
48
|
+
const code = mapStatusToCode(response.status, response.headers.get("www-authenticate"));
|
|
49
|
+
throw new ApiError(formatErrorMessage(method, path, response.status, code, detail.message), response.status, code, detail.body);
|
|
50
|
+
}
|
|
51
|
+
if (response.status === 204) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
55
|
+
if (contentType.includes("application/json")) {
|
|
56
|
+
return (await response.json());
|
|
57
|
+
}
|
|
58
|
+
return (await response.text());
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function joinUrl(base, path) {
|
|
62
|
+
const trimmedBase = base.replace(/\/+$/, "");
|
|
63
|
+
const trimmedPath = path.startsWith("/") ? path : `/${path}`;
|
|
64
|
+
return `${trimmedBase}${trimmedPath}`;
|
|
65
|
+
}
|
|
66
|
+
function parseRetryAfter(value) {
|
|
67
|
+
if (!value)
|
|
68
|
+
return 1000;
|
|
69
|
+
const asSeconds = Number(value);
|
|
70
|
+
if (!Number.isNaN(asSeconds) && asSeconds >= 0) {
|
|
71
|
+
return Math.min(asSeconds * 1000, MAX_RETRY_AFTER_MS);
|
|
72
|
+
}
|
|
73
|
+
const date = Date.parse(value);
|
|
74
|
+
if (!Number.isNaN(date)) {
|
|
75
|
+
return Math.max(0, Math.min(date - Date.now(), MAX_RETRY_AFTER_MS));
|
|
76
|
+
}
|
|
77
|
+
return 1000;
|
|
78
|
+
}
|
|
79
|
+
function sleep(ms) {
|
|
80
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
81
|
+
}
|
|
82
|
+
async function readErrorDetail(response) {
|
|
83
|
+
const text = await response.text().catch(() => "");
|
|
84
|
+
if (!text)
|
|
85
|
+
return { message: response.statusText, body: undefined };
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(text);
|
|
88
|
+
const message = typeof parsed === "object" && parsed !== null && typeof parsed.message === "string"
|
|
89
|
+
? (parsed.message)
|
|
90
|
+
: text;
|
|
91
|
+
return { message, body: parsed };
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return { message: text, body: text };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function mapStatusToCode(status, wwwAuthenticate) {
|
|
98
|
+
if (status === 401)
|
|
99
|
+
return "unauthorized";
|
|
100
|
+
if (status === 403) {
|
|
101
|
+
if (wwwAuthenticate && /insufficient_scope/i.test(wwwAuthenticate)) {
|
|
102
|
+
return "insufficient_scope";
|
|
103
|
+
}
|
|
104
|
+
return "forbidden_or_not_member";
|
|
105
|
+
}
|
|
106
|
+
if (status === 404)
|
|
107
|
+
return "not_found";
|
|
108
|
+
if (status === 409)
|
|
109
|
+
return "conflict";
|
|
110
|
+
if (status === 429)
|
|
111
|
+
return "rate_limited";
|
|
112
|
+
if (status >= 500)
|
|
113
|
+
return "server_error";
|
|
114
|
+
return "error";
|
|
115
|
+
}
|
|
116
|
+
function formatErrorMessage(method, path, status, code, detail) {
|
|
117
|
+
return `Zuwiki API error on ${method} ${path}: ${status} ${code}. ${detail}`.trim();
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/api/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ApiContext, Organization } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the organizations the currently signed in user is a member of.
|
|
4
|
+
*
|
|
5
|
+
* The endpoint is called without the x-organization-id header because the
|
|
6
|
+
* token is user-scoped and the goal is to discover which organizations
|
|
7
|
+
* exist for this user.
|
|
8
|
+
*
|
|
9
|
+
* The exact path is configurable via ZUWIKI_ORGANIZATIONS_PATH (see cli.ts).
|
|
10
|
+
* Default is /api/organizations.
|
|
11
|
+
*/
|
|
12
|
+
export declare function listOrganizations(ctx: ApiContext, path?: string): Promise<Organization[] | {
|
|
13
|
+
items: Organization[];
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { apiRequest } from "./http.js";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the organizations the currently signed in user is a member of.
|
|
4
|
+
*
|
|
5
|
+
* The endpoint is called without the x-organization-id header because the
|
|
6
|
+
* token is user-scoped and the goal is to discover which organizations
|
|
7
|
+
* exist for this user.
|
|
8
|
+
*
|
|
9
|
+
* The exact path is configurable via ZUWIKI_ORGANIZATIONS_PATH (see cli.ts).
|
|
10
|
+
* Default is /api/organizations.
|
|
11
|
+
*/
|
|
12
|
+
export function listOrganizations(ctx, path = "/api/organizations") {
|
|
13
|
+
return apiRequest(ctx, path, { withoutOrganization: true });
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=organizations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organizations.js","sourceRoot":"","sources":["../../src/api/organizations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,GAAe,EACf,IAAI,GAAG,oBAAoB;IAE3B,OAAO,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ApiContext, Page, PageContent, PageHistoryEntry, PageSettings } from "./types.js";
|
|
2
|
+
export declare function createPage(ctx: ApiContext, wikiId: string, body: {
|
|
3
|
+
title: string;
|
|
4
|
+
categoryId?: string | null;
|
|
5
|
+
}): Promise<Page>;
|
|
6
|
+
export declare function renamePage(ctx: ApiContext, wikiId: string, pageId: string, title: string): Promise<Page>;
|
|
7
|
+
export declare function deletePage(ctx: ApiContext, wikiId: string, pageId: string): Promise<void>;
|
|
8
|
+
export declare function getPageContent(ctx: ApiContext, wikiId: string, pageId: string): Promise<PageContent>;
|
|
9
|
+
export declare function updatePageContent(ctx: ApiContext, wikiId: string, pageId: string, content: string): Promise<PageContent | void>;
|
|
10
|
+
export declare function getPageSettings(ctx: ApiContext, wikiId: string, pageId: string): Promise<PageSettings>;
|
|
11
|
+
export declare function updatePageSettings(ctx: ApiContext, wikiId: string, pageId: string, patch: PageSettings): Promise<PageSettings>;
|
|
12
|
+
export declare function setPageStatus(ctx: ApiContext, wikiId: string, pageId: string, status: "DRAFT" | "PUBLISHED"): Promise<Page>;
|
|
13
|
+
export declare function getPageHistory(ctx: ApiContext, wikiId: string, pageId: string): Promise<PageHistoryEntry[] | {
|
|
14
|
+
items: PageHistoryEntry[];
|
|
15
|
+
}>;
|
|
16
|
+
export declare function restorePageHistory(ctx: ApiContext, wikiId: string, pageId: string, historyId: string): Promise<Page | void>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { apiRequest } from "./http.js";
|
|
2
|
+
export function createPage(ctx, wikiId, body) {
|
|
3
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/pages`, {
|
|
4
|
+
method: "POST",
|
|
5
|
+
body,
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
export function renamePage(ctx, wikiId, pageId, title) {
|
|
9
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/pages/${encodeURIComponent(pageId)}`, { method: "PATCH", body: { title } });
|
|
10
|
+
}
|
|
11
|
+
export function deletePage(ctx, wikiId, pageId) {
|
|
12
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/pages/${encodeURIComponent(pageId)}`, { method: "DELETE" });
|
|
13
|
+
}
|
|
14
|
+
export function getPageContent(ctx, wikiId, pageId) {
|
|
15
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/pages/${encodeURIComponent(pageId)}/content`);
|
|
16
|
+
}
|
|
17
|
+
export function updatePageContent(ctx, wikiId, pageId, content) {
|
|
18
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/pages/${encodeURIComponent(pageId)}/content`, { method: "PUT", body: { content } });
|
|
19
|
+
}
|
|
20
|
+
export function getPageSettings(ctx, wikiId, pageId) {
|
|
21
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/pages/${encodeURIComponent(pageId)}/settings`);
|
|
22
|
+
}
|
|
23
|
+
export function updatePageSettings(ctx, wikiId, pageId, patch) {
|
|
24
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/pages/${encodeURIComponent(pageId)}/settings`, { method: "PATCH", body: patch });
|
|
25
|
+
}
|
|
26
|
+
export function setPageStatus(ctx, wikiId, pageId, status) {
|
|
27
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/pages/${encodeURIComponent(pageId)}/status`, { method: "PATCH", body: { status } });
|
|
28
|
+
}
|
|
29
|
+
export function getPageHistory(ctx, wikiId, pageId) {
|
|
30
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/pages/${encodeURIComponent(pageId)}/history`);
|
|
31
|
+
}
|
|
32
|
+
export function restorePageHistory(ctx, wikiId, pageId, historyId) {
|
|
33
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/pages/${encodeURIComponent(pageId)}/history/${encodeURIComponent(historyId)}/restore`, { method: "POST" });
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=pages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/api/pages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface ApiContext {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
organizationId: string | null;
|
|
4
|
+
getAccessToken(): Promise<string>;
|
|
5
|
+
/** Forces a token refresh. Throws when not supported (HTTP mode). */
|
|
6
|
+
invalidateAndRefreshToken(): Promise<string>;
|
|
7
|
+
fetchImpl?: typeof fetch;
|
|
8
|
+
}
|
|
9
|
+
export declare class ApiError extends Error {
|
|
10
|
+
readonly status: number;
|
|
11
|
+
readonly code?: string | undefined;
|
|
12
|
+
readonly body?: unknown | undefined;
|
|
13
|
+
constructor(message: string, status: number, code?: string | undefined, body?: unknown | undefined);
|
|
14
|
+
}
|
|
15
|
+
export interface Wiki {
|
|
16
|
+
id: string;
|
|
17
|
+
title: string;
|
|
18
|
+
slug?: string;
|
|
19
|
+
organizationId?: string;
|
|
20
|
+
createdAt?: string;
|
|
21
|
+
updatedAt?: string;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
export interface Category {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
wikiId: string;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
export interface Page {
|
|
31
|
+
id: string;
|
|
32
|
+
title: string;
|
|
33
|
+
slug?: string;
|
|
34
|
+
status?: "DRAFT" | "PUBLISHED";
|
|
35
|
+
categoryId?: string | null;
|
|
36
|
+
wikiId: string;
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
}
|
|
39
|
+
export interface PageContent {
|
|
40
|
+
content: string;
|
|
41
|
+
}
|
|
42
|
+
export interface PageSettings {
|
|
43
|
+
title?: string;
|
|
44
|
+
slug?: string;
|
|
45
|
+
hidden?: boolean;
|
|
46
|
+
pageVisibility?: "PUBLIC" | "PRIVATE_ACCOUNT" | "PRIVATE_PASSWORD" | "PRIVATE_EMAIL_DOMAIN";
|
|
47
|
+
seoTitle?: string;
|
|
48
|
+
seoDescription?: string;
|
|
49
|
+
seoKeywords?: string;
|
|
50
|
+
icon?: string;
|
|
51
|
+
[key: string]: unknown;
|
|
52
|
+
}
|
|
53
|
+
export interface PageHistoryEntry {
|
|
54
|
+
id: string;
|
|
55
|
+
createdAt?: string;
|
|
56
|
+
authorId?: string;
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
}
|
|
59
|
+
export interface EditorSnapshot {
|
|
60
|
+
categories?: unknown;
|
|
61
|
+
rootPages?: unknown;
|
|
62
|
+
rootLinks?: unknown;
|
|
63
|
+
[key: string]: unknown;
|
|
64
|
+
}
|
|
65
|
+
export interface Organization {
|
|
66
|
+
id: string;
|
|
67
|
+
name?: string;
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class ApiError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
code;
|
|
4
|
+
body;
|
|
5
|
+
constructor(message, status, code, body) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.body = body;
|
|
10
|
+
this.name = "ApiError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGf;IACA;IACA;IAJlB,YACE,OAAe,EACC,MAAc,EACd,IAAa,EACb,IAAc;QAE9B,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAS;QACb,SAAI,GAAJ,IAAI,CAAU;QAG9B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ApiContext, EditorSnapshot, Wiki } from "./types.js";
|
|
2
|
+
export declare function listWikis(ctx: ApiContext): Promise<Wiki[] | {
|
|
3
|
+
items: Wiki[];
|
|
4
|
+
}>;
|
|
5
|
+
export declare function getWiki(ctx: ApiContext, wikiId: string): Promise<Wiki>;
|
|
6
|
+
export declare function createWiki(ctx: ApiContext, title: string): Promise<Wiki>;
|
|
7
|
+
export declare function updateWiki(ctx: ApiContext, wikiId: string, patch: {
|
|
8
|
+
title?: string;
|
|
9
|
+
slug?: string;
|
|
10
|
+
}): Promise<Wiki>;
|
|
11
|
+
export declare function deleteWiki(ctx: ApiContext, wikiId: string): Promise<void>;
|
|
12
|
+
export declare function getWikiEditor(ctx: ApiContext, wikiId: string): Promise<EditorSnapshot>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { apiRequest } from "./http.js";
|
|
2
|
+
export function listWikis(ctx) {
|
|
3
|
+
return apiRequest(ctx, "/api/wikis");
|
|
4
|
+
}
|
|
5
|
+
export function getWiki(ctx, wikiId) {
|
|
6
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}`);
|
|
7
|
+
}
|
|
8
|
+
export function createWiki(ctx, title) {
|
|
9
|
+
return apiRequest(ctx, "/api/wikis", { method: "POST", body: { title } });
|
|
10
|
+
}
|
|
11
|
+
export function updateWiki(ctx, wikiId, patch) {
|
|
12
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}`, {
|
|
13
|
+
method: "PATCH",
|
|
14
|
+
body: patch,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export function deleteWiki(ctx, wikiId) {
|
|
18
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}`, {
|
|
19
|
+
method: "DELETE",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function getWikiEditor(ctx, wikiId) {
|
|
23
|
+
return apiRequest(ctx, `/api/wikis/${encodeURIComponent(wikiId)}/editor`);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=wikis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wikis.js","sourceRoot":"","sources":["../../src/api/wikis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,MAAM,UAAU,SAAS,CAAC,GAAe;IACvC,OAAO,UAAU,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAe,EAAE,MAAc;IACrD,OAAO,UAAU,CAAC,GAAG,EAAE,cAAc,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAe,EAAE,KAAa;IACvD,OAAO,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,GAAe,EACf,MAAc,EACd,KAAwC;IAExC,OAAO,UAAU,CAAC,GAAG,EAAE,cAAc,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE;QACjE,MAAM,EAAE,OAAO;QACf,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAe,EAAE,MAAc;IACxD,OAAO,UAAU,CAAC,GAAG,EAAE,cAAc,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE;QACjE,MAAM,EAAE,QAAQ;KACjB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAe,EAAE,MAAc;IAC3D,OAAO,UAAU,CAAC,GAAG,EAAE,cAAc,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAC5E,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export declare const DEFAULT_SCOPE = "openid profile email offline_access wiki:read wiki:write";
|
|
2
|
+
export interface AuthManagerOptions {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
credentialsPath?: string;
|
|
5
|
+
scope?: string;
|
|
6
|
+
clientName?: string;
|
|
7
|
+
fetchImpl?: typeof fetch;
|
|
8
|
+
loopbackPorts?: number[];
|
|
9
|
+
/** Logger for status messages, defaults to process.stderr.write. */
|
|
10
|
+
log?: (message: string) => void;
|
|
11
|
+
openBrowser?: (url: string) => Promise<unknown>;
|
|
12
|
+
/** If false, the interactive browser flow is never triggered. Used for HTTP mode. */
|
|
13
|
+
interactive?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Manages OAuth credentials for the local server.
|
|
17
|
+
*
|
|
18
|
+
* On the first call to ensureAccessToken it runs discovery, dynamic client
|
|
19
|
+
* registration and the authorization code flow if needed. Later calls reuse
|
|
20
|
+
* the refresh token as long as possible.
|
|
21
|
+
*/
|
|
22
|
+
export declare class AuthManager {
|
|
23
|
+
private readonly baseUrl;
|
|
24
|
+
private readonly credentialsPath;
|
|
25
|
+
private readonly scope;
|
|
26
|
+
private readonly clientName;
|
|
27
|
+
private readonly fetchImpl;
|
|
28
|
+
private readonly loopbackPorts;
|
|
29
|
+
private readonly log;
|
|
30
|
+
private readonly openBrowser?;
|
|
31
|
+
private readonly interactive;
|
|
32
|
+
private credentials;
|
|
33
|
+
private metadata;
|
|
34
|
+
private inflight;
|
|
35
|
+
constructor(options: AuthManagerOptions);
|
|
36
|
+
getBaseUrl(): string;
|
|
37
|
+
ensureAccessToken(): Promise<string>;
|
|
38
|
+
private ensureAccessTokenInner;
|
|
39
|
+
/** Forces a refresh, for example after a 401 response. */
|
|
40
|
+
invalidateAndRefresh(): Promise<string>;
|
|
41
|
+
private getCredentials;
|
|
42
|
+
private getMetadata;
|
|
43
|
+
private runInitialAuth;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Holds the active organization id and lets callers update it at runtime.
|
|
47
|
+
* Shared with the server so that zuwiki_set_active_organization can take effect.
|
|
48
|
+
*/
|
|
49
|
+
export declare class OrganizationState {
|
|
50
|
+
private organizationId;
|
|
51
|
+
constructor(organizationId: string | null);
|
|
52
|
+
get(): string | null;
|
|
53
|
+
set(id: string | null): void;
|
|
54
|
+
}
|