@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.
Files changed (57) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +189 -0
  3. package/dist/api/categories.d.ts +4 -0
  4. package/dist/api/categories.js +14 -0
  5. package/dist/api/categories.js.map +1 -0
  6. package/dist/api/http.d.ts +8 -0
  7. package/dist/api/http.js +119 -0
  8. package/dist/api/http.js.map +1 -0
  9. package/dist/api/organizations.d.ts +14 -0
  10. package/dist/api/organizations.js +15 -0
  11. package/dist/api/organizations.js.map +1 -0
  12. package/dist/api/pages.d.ts +16 -0
  13. package/dist/api/pages.js +35 -0
  14. package/dist/api/pages.js.map +1 -0
  15. package/dist/api/types.d.ts +69 -0
  16. package/dist/api/types.js +13 -0
  17. package/dist/api/types.js.map +1 -0
  18. package/dist/api/wikis.d.ts +12 -0
  19. package/dist/api/wikis.js +25 -0
  20. package/dist/api/wikis.js.map +1 -0
  21. package/dist/auth/client.d.ts +54 -0
  22. package/dist/auth/client.js +162 -0
  23. package/dist/auth/client.js.map +1 -0
  24. package/dist/auth/discovery.d.ts +14 -0
  25. package/dist/auth/discovery.js +26 -0
  26. package/dist/auth/discovery.js.map +1 -0
  27. package/dist/auth/flow.d.ts +21 -0
  28. package/dist/auth/flow.js +188 -0
  29. package/dist/auth/flow.js.map +1 -0
  30. package/dist/auth/pkce.d.ts +7 -0
  31. package/dist/auth/pkce.js +20 -0
  32. package/dist/auth/pkce.js.map +1 -0
  33. package/dist/auth/registration.d.ts +21 -0
  34. package/dist/auth/registration.js +28 -0
  35. package/dist/auth/registration.js.map +1 -0
  36. package/dist/auth/tokens.d.ts +25 -0
  37. package/dist/auth/tokens.js +51 -0
  38. package/dist/auth/tokens.js.map +1 -0
  39. package/dist/cli.d.ts +2 -0
  40. package/dist/cli.js +128 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/server.d.ts +15 -0
  43. package/dist/server.js +53 -0
  44. package/dist/server.js.map +1 -0
  45. package/dist/tools/register.d.ts +12 -0
  46. package/dist/tools/register.js +244 -0
  47. package/dist/tools/register.js.map +1 -0
  48. package/dist/tools/shared.d.ts +5 -0
  49. package/dist/tools/shared.js +38 -0
  50. package/dist/tools/shared.js.map +1 -0
  51. package/dist/transports/http.d.ts +9 -0
  52. package/dist/transports/http.js +150 -0
  53. package/dist/transports/http.js.map +1 -0
  54. package/dist/transports/stdio.d.ts +7 -0
  55. package/dist/transports/stdio.js +20 -0
  56. package/dist/transports/stdio.js.map +1 -0
  57. 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>;
@@ -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
+ }