@4ort/cli 0.7.0 → 0.8.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/README.md +19 -7
- package/dist/api-client.d.ts +9 -1
- package/dist/api-client.js +9 -2
- package/dist/api-client.js.map +1 -1
- package/dist/commands/docs.d.ts +17 -0
- package/dist/commands/docs.js +90 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/domain.d.ts +20 -0
- package/dist/commands/domain.js +179 -0
- package/dist/commands/domain.js.map +1 -0
- package/dist/commands/domains.d.ts +6 -0
- package/dist/commands/domains.js +91 -0
- package/dist/commands/domains.js.map +1 -0
- package/dist/commands/login-link.d.ts +1 -0
- package/dist/commands/login-link.js +18 -0
- package/dist/commands/login-link.js.map +1 -0
- package/dist/commands/mov.d.ts +1 -0
- package/dist/commands/mov.js +40 -4
- package/dist/commands/mov.js.map +1 -1
- package/dist/commands/register.d.ts +1 -0
- package/dist/commands/register.js +1 -1
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/repo.d.ts +9 -0
- package/dist/commands/repo.js +73 -0
- package/dist/commands/repo.js.map +1 -0
- package/dist/commands/sheets.d.ts +17 -0
- package/dist/commands/sheets.js +90 -0
- package/dist/commands/sheets.js.map +1 -0
- package/dist/gitea-client.d.ts +41 -0
- package/dist/gitea-client.js +79 -0
- package/dist/gitea-client.js.map +1 -0
- package/dist/gitea-client.test.d.ts +1 -0
- package/dist/gitea-client.test.js +40 -0
- package/dist/gitea-client.test.js.map +1 -0
- package/dist/index.js +146 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +204 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/namesilo-client.d.ts +31 -0
- package/dist/namesilo-client.js +85 -0
- package/dist/namesilo-client.js.map +1 -0
- package/dist/namesilo-client.test.d.ts +1 -0
- package/dist/namesilo-client.test.js +58 -0
- package/dist/namesilo-client.test.js.map +1 -0
- package/dist/office-client.d.ts +76 -0
- package/dist/office-client.js +110 -0
- package/dist/office-client.js.map +1 -0
- package/dist/office-client.test.d.ts +1 -0
- package/dist/office-client.test.js +53 -0
- package/dist/office-client.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NameSilo registrar client — BYO-account: every call runs against the USER'S
|
|
3
|
+
* own NameSilo API key. The CLI never bundles or proxies a key.
|
|
4
|
+
*
|
|
5
|
+
* Key resolution order (resolveNamesiloKey):
|
|
6
|
+
* 1. NAMESILO_KEY env var (incl. plaintext injected by `4ort run`)
|
|
7
|
+
* 2. The 4ort.ai secrets vault (ref `4ort://namesilo`), when linked
|
|
8
|
+
*
|
|
9
|
+
* API shape (ported from empire-mcp): GET {base}/{operation}?version=1&type=json&key=...
|
|
10
|
+
* NameSilo replies with reply.code 300 on success. The key rides the query
|
|
11
|
+
* string per NameSilo's API design (HTTPS-only).
|
|
12
|
+
*/
|
|
13
|
+
import { loadConfig } from "./config.js";
|
|
14
|
+
const NAMESILO_API_BASE = process.env.NAMESILO_API_BASE || "https://www.namesilo.com/api";
|
|
15
|
+
export async function namesiloRequest(operation, key, params = {}, fetchFn = fetch) {
|
|
16
|
+
const url = new URL(`${NAMESILO_API_BASE}/${operation}`);
|
|
17
|
+
url.searchParams.set("version", "1");
|
|
18
|
+
url.searchParams.set("type", "json");
|
|
19
|
+
url.searchParams.set("key", key);
|
|
20
|
+
for (const [k, v] of Object.entries(params)) {
|
|
21
|
+
if (v !== undefined)
|
|
22
|
+
url.searchParams.set(k, String(v));
|
|
23
|
+
}
|
|
24
|
+
const res = await fetchFn(url.toString());
|
|
25
|
+
const data = await res.json();
|
|
26
|
+
const reply = data?.reply ?? {};
|
|
27
|
+
const code = String(reply.code ?? "");
|
|
28
|
+
return { ok: code === "300", code, detail: reply.detail, reply };
|
|
29
|
+
}
|
|
30
|
+
export const namesilo = {
|
|
31
|
+
balance: (key, fetchFn) => namesiloRequest("getAccountBalance", key, {}, fetchFn),
|
|
32
|
+
listDomains: (key, fetchFn) => namesiloRequest("listDomains", key, {}, fetchFn),
|
|
33
|
+
check: (key, domains, fetchFn) => namesiloRequest("checkRegisterAvailability", key, { domains: domains.slice(0, 12).join(",") }, fetchFn),
|
|
34
|
+
register: (key, domain, opts = {}, fetchFn) => namesiloRequest("registerDomain", key, {
|
|
35
|
+
domain,
|
|
36
|
+
years: opts.years ?? 1,
|
|
37
|
+
auto_renew: opts.autoRenew === false ? 0 : 1,
|
|
38
|
+
private: opts.privacy === false ? 0 : 1,
|
|
39
|
+
}, fetchFn),
|
|
40
|
+
dnsList: (key, domain, fetchFn) => namesiloRequest("dnsListRecords", key, { domain }, fetchFn),
|
|
41
|
+
dnsAdd: (key, domain, record, fetchFn) => namesiloRequest("dnsAddRecord", key, {
|
|
42
|
+
domain,
|
|
43
|
+
rrtype: record.type.toUpperCase(),
|
|
44
|
+
rrhost: record.host,
|
|
45
|
+
rrvalue: record.value,
|
|
46
|
+
rrttl: record.ttl ?? 3600,
|
|
47
|
+
}, fetchFn),
|
|
48
|
+
};
|
|
49
|
+
/** Normalize a domain arg: lowercase, strip scheme/path/trailing dot. */
|
|
50
|
+
export function normalizeDomainArg(input) {
|
|
51
|
+
return input
|
|
52
|
+
.trim()
|
|
53
|
+
.toLowerCase()
|
|
54
|
+
.replace(/^https?:\/\//, "")
|
|
55
|
+
.replace(/\/.*$/, "")
|
|
56
|
+
.replace(/\.$/, "");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the user's NameSilo key: NAMESILO_KEY env first, then the vault
|
|
60
|
+
* (`4ort://namesilo`). Returns null when neither is available.
|
|
61
|
+
*/
|
|
62
|
+
export async function resolveNamesiloKey(fetchFn = fetch) {
|
|
63
|
+
const fromEnv = process.env.NAMESILO_KEY?.trim();
|
|
64
|
+
if (fromEnv && !fromEnv.startsWith("4ort://"))
|
|
65
|
+
return fromEnv;
|
|
66
|
+
const vault = loadConfig()?.vault;
|
|
67
|
+
if (!vault?.token)
|
|
68
|
+
return null;
|
|
69
|
+
const ref = fromEnv || "4ort://namesilo";
|
|
70
|
+
try {
|
|
71
|
+
const res = await fetchFn(`${vault.server.replace(/\/$/, "")}/api/secrets/resolve`, {
|
|
72
|
+
method: "POST",
|
|
73
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${vault.token}` },
|
|
74
|
+
body: JSON.stringify({ refs: [ref] }),
|
|
75
|
+
});
|
|
76
|
+
if (!res.ok)
|
|
77
|
+
return null;
|
|
78
|
+
const data = (await res.json());
|
|
79
|
+
return data.resolved?.[ref] ?? null;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=namesilo-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namesilo-client.js","sourceRoot":"","sources":["../src/namesilo-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { namesilo, namesiloRequest, normalizeDomainArg } from "./namesilo-client.js";
|
|
4
|
+
function stubFetch(reply) {
|
|
5
|
+
const urls = [];
|
|
6
|
+
const fetchFn = (async (url) => {
|
|
7
|
+
urls.push(String(url));
|
|
8
|
+
return { json: async () => ({ reply }) };
|
|
9
|
+
});
|
|
10
|
+
return { fetchFn, urls };
|
|
11
|
+
}
|
|
12
|
+
test("namesiloRequest treats reply.code 300 as success", async () => {
|
|
13
|
+
const { fetchFn, urls } = stubFetch({ code: 300, detail: "success", balance: "25.00" });
|
|
14
|
+
const r = await namesiloRequest("getAccountBalance", "k123", {}, fetchFn);
|
|
15
|
+
assert.equal(r.ok, true);
|
|
16
|
+
assert.equal(r.reply.balance, "25.00");
|
|
17
|
+
const u = new URL(urls[0]);
|
|
18
|
+
assert.equal(u.searchParams.get("version"), "1");
|
|
19
|
+
assert.equal(u.searchParams.get("type"), "json");
|
|
20
|
+
assert.equal(u.searchParams.get("key"), "k123");
|
|
21
|
+
});
|
|
22
|
+
test("namesiloRequest surfaces non-300 codes as ok:false", async () => {
|
|
23
|
+
const { fetchFn } = stubFetch({ code: 261, detail: "insufficient funds" });
|
|
24
|
+
const r = await namesiloRequest("registerDomain", "k", { domain: "x.com" }, fetchFn);
|
|
25
|
+
assert.equal(r.ok, false);
|
|
26
|
+
assert.equal(r.code, "261");
|
|
27
|
+
assert.match(r.detail, /insufficient/);
|
|
28
|
+
});
|
|
29
|
+
test("register wires years/auto_renew/private flags", async () => {
|
|
30
|
+
const { fetchFn, urls } = stubFetch({ code: 300 });
|
|
31
|
+
await namesilo.register("k", "example.com", { years: 2, autoRenew: false, privacy: true }, fetchFn);
|
|
32
|
+
const u = new URL(urls[0]);
|
|
33
|
+
assert.match(u.pathname, /registerDomain$/);
|
|
34
|
+
assert.equal(u.searchParams.get("domain"), "example.com");
|
|
35
|
+
assert.equal(u.searchParams.get("years"), "2");
|
|
36
|
+
assert.equal(u.searchParams.get("auto_renew"), "0");
|
|
37
|
+
assert.equal(u.searchParams.get("private"), "1");
|
|
38
|
+
});
|
|
39
|
+
test("dnsAdd uppercases type and defaults ttl", async () => {
|
|
40
|
+
const { fetchFn, urls } = stubFetch({ code: 300 });
|
|
41
|
+
await namesilo.dnsAdd("k", "example.com", { type: "a", host: "www", value: "1.2.3.4" }, fetchFn);
|
|
42
|
+
const u = new URL(urls[0]);
|
|
43
|
+
assert.equal(u.searchParams.get("rrtype"), "A");
|
|
44
|
+
assert.equal(u.searchParams.get("rrttl"), "3600");
|
|
45
|
+
});
|
|
46
|
+
test("check joins and caps domains at 12", async () => {
|
|
47
|
+
const { fetchFn, urls } = stubFetch({ code: 300 });
|
|
48
|
+
const domains = Array.from({ length: 15 }, (_, i) => `d${i}.com`);
|
|
49
|
+
await namesilo.check("k", domains, fetchFn);
|
|
50
|
+
const sent = new URL(urls[0]).searchParams.get("domains").split(",");
|
|
51
|
+
assert.equal(sent.length, 12);
|
|
52
|
+
});
|
|
53
|
+
test("normalizeDomainArg strips scheme, path, trailing dot", () => {
|
|
54
|
+
assert.equal(normalizeDomainArg("HTTPS://Example.COM/path?q=1"), "example.com");
|
|
55
|
+
assert.equal(normalizeDomainArg("example.com."), "example.com");
|
|
56
|
+
assert.equal(normalizeDomainArg(" www.example.com "), "www.example.com");
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=namesilo-client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namesilo-client.test.js","sourceRoot":"","sources":["../src/namesilo-client.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Config } from "./config.js";
|
|
2
|
+
export declare const DOCS_DEFAULT_URL = "https://docs.4ort.net";
|
|
3
|
+
export declare const SHEETS_DEFAULT_URL = "https://sheets.4ort.net";
|
|
4
|
+
export interface DocSummary {
|
|
5
|
+
id: string;
|
|
6
|
+
title: string;
|
|
7
|
+
updatedAt: string;
|
|
8
|
+
}
|
|
9
|
+
export interface Doc {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
markdown: string;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
updatedAt: string;
|
|
15
|
+
}
|
|
16
|
+
export interface SheetSummary {
|
|
17
|
+
id: string;
|
|
18
|
+
title: string;
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
}
|
|
21
|
+
export interface Sheet {
|
|
22
|
+
id: string;
|
|
23
|
+
title: string;
|
|
24
|
+
csv: string;
|
|
25
|
+
createdAt: string;
|
|
26
|
+
updatedAt: string;
|
|
27
|
+
}
|
|
28
|
+
export declare class DocsClient {
|
|
29
|
+
private baseUrl;
|
|
30
|
+
private key;
|
|
31
|
+
private fetchFn;
|
|
32
|
+
constructor(baseUrl: string, key: string, fetchFn?: typeof fetch);
|
|
33
|
+
private req;
|
|
34
|
+
list(): Promise<{
|
|
35
|
+
docs: DocSummary[];
|
|
36
|
+
}>;
|
|
37
|
+
read(id: string): Promise<Doc>;
|
|
38
|
+
create(markdown: string, title?: string): Promise<Doc>;
|
|
39
|
+
update(id: string, patch: {
|
|
40
|
+
markdown?: string;
|
|
41
|
+
title?: string;
|
|
42
|
+
}): Promise<Doc>;
|
|
43
|
+
remove(id: string): Promise<{
|
|
44
|
+
message: string;
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
export declare class SheetsClient {
|
|
48
|
+
private baseUrl;
|
|
49
|
+
private key;
|
|
50
|
+
private fetchFn;
|
|
51
|
+
constructor(baseUrl: string, key: string, fetchFn?: typeof fetch);
|
|
52
|
+
private req;
|
|
53
|
+
list(): Promise<{
|
|
54
|
+
sheets: SheetSummary[];
|
|
55
|
+
}>;
|
|
56
|
+
read(id: string): Promise<Sheet>;
|
|
57
|
+
create(csv: string, title?: string): Promise<Sheet>;
|
|
58
|
+
update(id: string, patch: {
|
|
59
|
+
csv?: string;
|
|
60
|
+
title?: string;
|
|
61
|
+
}): Promise<Sheet>;
|
|
62
|
+
remove(id: string): Promise<{
|
|
63
|
+
message: string;
|
|
64
|
+
}>;
|
|
65
|
+
}
|
|
66
|
+
export declare function docsClient(config: Config): DocsClient;
|
|
67
|
+
export declare function sheetsClient(config: Config): SheetsClient;
|
|
68
|
+
/**
|
|
69
|
+
* Resolve document/sheet body content for create/update commands:
|
|
70
|
+
* --file wins, then --content, then piped stdin. Returns null when nothing
|
|
71
|
+
* was provided (caller decides whether that's an error).
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveContentInput(options: {
|
|
74
|
+
file?: string;
|
|
75
|
+
content?: string;
|
|
76
|
+
}): string | null;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clients for the 4ort "office" properties — docs.4ort.net and sheets.4ort.net.
|
|
3
|
+
* Both speak the same Bearer-4n_-key REST shape (validated via 4ort.net
|
|
4
|
+
* federation server-side); docs deal in markdown, sheets in CSV.
|
|
5
|
+
*
|
|
6
|
+
* Ported from the reference clients in 4ort-docs/src/mcp/client.ts and
|
|
7
|
+
* 4ort-sheets/src/mcp/client.ts so the contracts stay identical. fetch is
|
|
8
|
+
* injectable for tests.
|
|
9
|
+
*/
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
export const DOCS_DEFAULT_URL = "https://docs.4ort.net";
|
|
12
|
+
export const SHEETS_DEFAULT_URL = "https://sheets.4ort.net";
|
|
13
|
+
async function officeRequest(fetchFn, baseUrl, key, path, init) {
|
|
14
|
+
const res = await fetchFn(`${baseUrl}${path}`, {
|
|
15
|
+
...init,
|
|
16
|
+
headers: {
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
Authorization: `Bearer ${key}`,
|
|
19
|
+
...(init?.headers || {}),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
const body = await res.text().catch(() => "");
|
|
24
|
+
throw new Error(`${res.status} ${res.statusText}${body ? `: ${body.slice(0, 200)}` : ""}`);
|
|
25
|
+
}
|
|
26
|
+
return res.status === 204 ? null : res.json();
|
|
27
|
+
}
|
|
28
|
+
export class DocsClient {
|
|
29
|
+
baseUrl;
|
|
30
|
+
key;
|
|
31
|
+
fetchFn;
|
|
32
|
+
constructor(baseUrl, key, fetchFn = fetch) {
|
|
33
|
+
this.baseUrl = baseUrl;
|
|
34
|
+
this.key = key;
|
|
35
|
+
this.fetchFn = fetchFn;
|
|
36
|
+
}
|
|
37
|
+
req(path, init) {
|
|
38
|
+
return officeRequest(this.fetchFn, this.baseUrl, this.key, path, init);
|
|
39
|
+
}
|
|
40
|
+
list() {
|
|
41
|
+
return this.req("/api/docs");
|
|
42
|
+
}
|
|
43
|
+
read(id) {
|
|
44
|
+
return this.req(`/api/docs/${encodeURIComponent(id)}`);
|
|
45
|
+
}
|
|
46
|
+
create(markdown, title) {
|
|
47
|
+
return this.req("/api/docs", { method: "POST", body: JSON.stringify({ markdown, title }) });
|
|
48
|
+
}
|
|
49
|
+
update(id, patch) {
|
|
50
|
+
return this.req(`/api/docs/${encodeURIComponent(id)}`, {
|
|
51
|
+
method: "PUT",
|
|
52
|
+
body: JSON.stringify(patch),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
remove(id) {
|
|
56
|
+
return this.req(`/api/docs/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export class SheetsClient {
|
|
60
|
+
baseUrl;
|
|
61
|
+
key;
|
|
62
|
+
fetchFn;
|
|
63
|
+
constructor(baseUrl, key, fetchFn = fetch) {
|
|
64
|
+
this.baseUrl = baseUrl;
|
|
65
|
+
this.key = key;
|
|
66
|
+
this.fetchFn = fetchFn;
|
|
67
|
+
}
|
|
68
|
+
req(path, init) {
|
|
69
|
+
return officeRequest(this.fetchFn, this.baseUrl, this.key, path, init);
|
|
70
|
+
}
|
|
71
|
+
list() {
|
|
72
|
+
return this.req("/api/sheets");
|
|
73
|
+
}
|
|
74
|
+
read(id) {
|
|
75
|
+
return this.req(`/api/sheets/${encodeURIComponent(id)}`);
|
|
76
|
+
}
|
|
77
|
+
create(csv, title) {
|
|
78
|
+
return this.req("/api/sheets", { method: "POST", body: JSON.stringify({ csv, title }) });
|
|
79
|
+
}
|
|
80
|
+
update(id, patch) {
|
|
81
|
+
return this.req(`/api/sheets/${encodeURIComponent(id)}`, {
|
|
82
|
+
method: "PUT",
|
|
83
|
+
body: JSON.stringify(patch),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
remove(id) {
|
|
87
|
+
return this.req(`/api/sheets/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export function docsClient(config) {
|
|
91
|
+
return new DocsClient(process.env.FORT_DOCS_URL || DOCS_DEFAULT_URL, config.apiKey);
|
|
92
|
+
}
|
|
93
|
+
export function sheetsClient(config) {
|
|
94
|
+
return new SheetsClient(process.env.FORT_SHEETS_URL || SHEETS_DEFAULT_URL, config.apiKey);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Resolve document/sheet body content for create/update commands:
|
|
98
|
+
* --file wins, then --content, then piped stdin. Returns null when nothing
|
|
99
|
+
* was provided (caller decides whether that's an error).
|
|
100
|
+
*/
|
|
101
|
+
export function resolveContentInput(options) {
|
|
102
|
+
if (options.file)
|
|
103
|
+
return fs.readFileSync(options.file, "utf-8");
|
|
104
|
+
if (typeof options.content === "string")
|
|
105
|
+
return options.content;
|
|
106
|
+
if (!process.stdin.isTTY)
|
|
107
|
+
return fs.readFileSync(0, "utf-8");
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=office-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-client.js","sourceRoot":"","sources":["../src/office-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { DocsClient, SheetsClient } from "./office-client.js";
|
|
4
|
+
function stubFetch(status, payload) {
|
|
5
|
+
const calls = [];
|
|
6
|
+
const fetchFn = (async (url, init) => {
|
|
7
|
+
calls.push({
|
|
8
|
+
url: String(url),
|
|
9
|
+
method: init?.method || "GET",
|
|
10
|
+
headers: (init?.headers || {}),
|
|
11
|
+
body: init?.body,
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
ok: status >= 200 && status < 300,
|
|
15
|
+
status,
|
|
16
|
+
statusText: status === 201 ? "Created" : status === 404 ? "Not Found" : "OK",
|
|
17
|
+
json: async () => payload,
|
|
18
|
+
text: async () => JSON.stringify(payload),
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
return { fetchFn, calls };
|
|
22
|
+
}
|
|
23
|
+
test("DocsClient hits the right paths with Bearer auth", async () => {
|
|
24
|
+
const { fetchFn, calls } = stubFetch(200, { docs: [] });
|
|
25
|
+
const client = new DocsClient("https://docs.4ort.net", "4n_test", fetchFn);
|
|
26
|
+
await client.list();
|
|
27
|
+
assert.equal(calls[0].url, "https://docs.4ort.net/api/docs");
|
|
28
|
+
assert.equal(calls[0].headers.Authorization, "Bearer 4n_test");
|
|
29
|
+
await client.read("a/b id");
|
|
30
|
+
assert.equal(calls[1].url, "https://docs.4ort.net/api/docs/a%2Fb%20id");
|
|
31
|
+
await client.create("# hi", "My Doc");
|
|
32
|
+
assert.equal(calls[2].method, "POST");
|
|
33
|
+
assert.deepEqual(JSON.parse(calls[2].body), { markdown: "# hi", title: "My Doc" });
|
|
34
|
+
await client.update("id1", { title: "New" });
|
|
35
|
+
assert.equal(calls[3].method, "PUT");
|
|
36
|
+
assert.deepEqual(JSON.parse(calls[3].body), { title: "New" });
|
|
37
|
+
await client.remove("id1");
|
|
38
|
+
assert.equal(calls[4].method, "DELETE");
|
|
39
|
+
});
|
|
40
|
+
test("SheetsClient sends csv payloads to /api/sheets", async () => {
|
|
41
|
+
const { fetchFn, calls } = stubFetch(201, { id: "s1", title: "T", csv: "a,b" });
|
|
42
|
+
const client = new SheetsClient("https://sheets.4ort.net", "4n_test", fetchFn);
|
|
43
|
+
const sheet = await client.create("a,b\n1,2", "T");
|
|
44
|
+
assert.equal(calls[0].url, "https://sheets.4ort.net/api/sheets");
|
|
45
|
+
assert.deepEqual(JSON.parse(calls[0].body), { csv: "a,b\n1,2", title: "T" });
|
|
46
|
+
assert.equal(sheet.id, "s1");
|
|
47
|
+
});
|
|
48
|
+
test("office clients surface HTTP errors with status and body", async () => {
|
|
49
|
+
const { fetchFn } = stubFetch(404, { error: "Doc not found" });
|
|
50
|
+
const client = new DocsClient("https://docs.4ort.net", "4n_test", fetchFn);
|
|
51
|
+
await assert.rejects(client.read("nope"), /404 Not Found.*Doc not found/);
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=office-client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-client.test.js","sourceRoot":"","sources":["../src/office-client.test.ts"],"names":[],"mappings":"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"}
|